servers.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. const fs = require('fs-extra')
  2. const http = require('http')
  3. const https = require('https')
  4. const { ApolloServer } = require('apollo-server-express')
  5. const Promise = require('bluebird')
  6. const _ = require('lodash')
  7. /* global WIKI */
  8. module.exports = {
  9. servers: {
  10. graph: null,
  11. http: null,
  12. https: null
  13. },
  14. connections: new Map(),
  15. le: null,
  16. /**
  17. * Start HTTP Server
  18. */
  19. async startHTTP () {
  20. WIKI.logger.info(`HTTP Server on port: [ ${WIKI.config.port} ]`)
  21. this.servers.http = http.createServer(WIKI.app)
  22. this.servers.http.listen(WIKI.config.port, WIKI.config.bindIP)
  23. this.servers.http.on('error', (error) => {
  24. if (error.syscall !== 'listen') {
  25. throw error
  26. }
  27. switch (error.code) {
  28. case 'EACCES':
  29. WIKI.logger.error('Listening on port ' + WIKI.config.port + ' requires elevated privileges!')
  30. return process.exit(1)
  31. case 'EADDRINUSE':
  32. WIKI.logger.error('Port ' + WIKI.config.port + ' is already in use!')
  33. return process.exit(1)
  34. default:
  35. throw error
  36. }
  37. })
  38. this.servers.http.on('listening', () => {
  39. WIKI.logger.info('HTTP Server: [ RUNNING ]')
  40. })
  41. this.servers.http.on('connection', conn => {
  42. let connKey = `http:${conn.remoteAddress}:${conn.remotePort}`
  43. this.connections.set(connKey, conn)
  44. conn.on('close', () => {
  45. this.connections.delete(connKey)
  46. })
  47. })
  48. },
  49. /**
  50. * Start HTTPS Server
  51. */
  52. async startHTTPS () {
  53. if (WIKI.config.ssl.provider === 'letsencrypt') {
  54. this.le = require('./letsencrypt')
  55. await this.le.init()
  56. }
  57. WIKI.logger.info(`HTTPS Server on port: [ ${WIKI.config.ssl.port} ]`)
  58. const tlsOpts = {}
  59. try {
  60. if (WIKI.config.ssl.format === 'pem') {
  61. tlsOpts.key = WIKI.config.ssl.inline ? WIKI.config.ssl.key : fs.readFileSync(WIKI.config.ssl.key)
  62. tlsOpts.cert = WIKI.config.ssl.inline ? WIKI.config.ssl.cert : fs.readFileSync(WIKI.config.ssl.cert)
  63. } else {
  64. tlsOpts.pfx = WIKI.config.ssl.inline ? WIKI.config.ssl.pfx : fs.readFileSync(WIKI.config.ssl.pfx)
  65. }
  66. if (!_.isEmpty(WIKI.config.ssl.passphrase)) {
  67. tlsOpts.passphrase = WIKI.config.ssl.passphrase
  68. }
  69. if (!_.isEmpty(WIKI.config.ssl.dhparam)) {
  70. tlsOpts.dhparam = WIKI.config.ssl.dhparam
  71. }
  72. } catch (err) {
  73. WIKI.logger.error('Failed to setup HTTPS server parameters:')
  74. WIKI.logger.error(err)
  75. return process.exit(1)
  76. }
  77. this.servers.https = https.createServer(tlsOpts, WIKI.app)
  78. this.servers.https.listen(WIKI.config.ssl.port, WIKI.config.bindIP)
  79. this.servers.https.on('error', (error) => {
  80. if (error.syscall !== 'listen') {
  81. throw error
  82. }
  83. switch (error.code) {
  84. case 'EACCES':
  85. WIKI.logger.error('Listening on port ' + WIKI.config.ssl.port + ' requires elevated privileges!')
  86. return process.exit(1)
  87. case 'EADDRINUSE':
  88. WIKI.logger.error('Port ' + WIKI.config.ssl.port + ' is already in use!')
  89. return process.exit(1)
  90. default:
  91. throw error
  92. }
  93. })
  94. this.servers.https.on('listening', () => {
  95. WIKI.logger.info('HTTPS Server: [ RUNNING ]')
  96. })
  97. this.servers.https.on('connection', conn => {
  98. let connKey = `https:${conn.remoteAddress}:${conn.remotePort}`
  99. this.connections.set(connKey, conn)
  100. conn.on('close', () => {
  101. this.connections.delete(connKey)
  102. })
  103. })
  104. },
  105. /**
  106. * Start GraphQL Server
  107. */
  108. async startGraphQL () {
  109. const graphqlSchema = require('../graph')
  110. this.servers.graph = new ApolloServer({
  111. schema: graphqlSchema,
  112. uploads: false,
  113. context: ({ req, res }) => ({ req, res }),
  114. plugins: [
  115. // ApolloServerPluginDrainHttpServer({ httpServer: this.servers.http })
  116. // ...(this.servers.https && ApolloServerPluginDrainHttpServer({ httpServer: this.servers.https }))
  117. ]
  118. })
  119. await this.servers.graph.start()
  120. this.servers.graph.applyMiddleware({ app: WIKI.app, cors: false })
  121. },
  122. /**
  123. * Close all active connections
  124. */
  125. closeConnections (mode = 'all') {
  126. for (const [key, conn] of this.connections) {
  127. if (mode !== `all` && key.indexOf(`${mode}:`) !== 0) {
  128. continue
  129. }
  130. conn.destroy()
  131. this.connections.delete(key)
  132. }
  133. if (mode === 'all') {
  134. this.connections.clear()
  135. }
  136. },
  137. /**
  138. * Stop all servers
  139. */
  140. async stopServers () {
  141. this.closeConnections()
  142. if (this.servers.http) {
  143. await Promise.fromCallback(cb => { this.servers.http.close(cb) })
  144. this.servers.http = null
  145. }
  146. if (this.servers.https) {
  147. await Promise.fromCallback(cb => { this.servers.https.close(cb) })
  148. this.servers.https = null
  149. }
  150. this.servers.graph = null
  151. },
  152. /**
  153. * Restart Server
  154. */
  155. async restartServer (srv = 'https') {
  156. this.closeConnections(srv)
  157. switch (srv) {
  158. case 'http':
  159. if (this.servers.http) {
  160. await Promise.fromCallback(cb => { this.servers.http.close(cb) })
  161. this.servers.http = null
  162. }
  163. this.startHTTP()
  164. break
  165. case 'https':
  166. if (this.servers.https) {
  167. await Promise.fromCallback(cb => { this.servers.https.close(cb) })
  168. this.servers.https = null
  169. }
  170. this.startHTTPS()
  171. break
  172. default:
  173. throw new Error('Cannot restart server: Invalid designation')
  174. }
  175. }
  176. }