servers.js 5.7 KB

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