| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 | const fs = require('fs-extra')const http = require('http')const https = require('https')const { ApolloServer } = require('apollo-server-express')const Promise = require('bluebird')const _ = require('lodash')/* global WIKI */module.exports = {  servers: {    graph: null,    http: null,    https: null  },  connections: new Map(),  le: null,  /**   * Start HTTP Server   */  async startHTTP () {    WIKI.logger.info(`HTTP Server on port: [ ${WIKI.config.port} ]`)    this.servers.http = http.createServer(WIKI.app)    this.servers.graph.installSubscriptionHandlers(this.servers.http)    this.servers.http.listen(WIKI.config.port, WIKI.config.bindIP)    this.servers.http.on('error', (error) => {      if (error.syscall !== 'listen') {        throw error      }      switch (error.code) {        case 'EACCES':          WIKI.logger.error('Listening on port ' + WIKI.config.port + ' requires elevated privileges!')          return process.exit(1)        case 'EADDRINUSE':          WIKI.logger.error('Port ' + WIKI.config.port + ' is already in use!')          return process.exit(1)        default:          throw error      }    })    this.servers.http.on('listening', () => {      WIKI.logger.info('HTTP Server: [ RUNNING ]')    })    this.servers.http.on('connection', conn => {      let connKey = `http:${conn.remoteAddress}:${conn.remotePort}`      this.connections.set(connKey, conn)      conn.on('close', () => {        this.connections.delete(connKey)      })    })  },  /**   * Start HTTPS Server   */  async startHTTPS () {    if (WIKI.config.ssl.provider === 'letsencrypt') {      this.le = require('./letsencrypt')      await this.le.init()    }    WIKI.logger.info(`HTTPS Server on port: [ ${WIKI.config.ssl.port} ]`)    const tlsOpts = {}    try {      if (WIKI.config.ssl.format === 'pem') {        tlsOpts.key = WIKI.config.ssl.inline ? WIKI.config.ssl.key : fs.readFileSync(WIKI.config.ssl.key)        tlsOpts.cert = WIKI.config.ssl.inline ? WIKI.config.ssl.cert : fs.readFileSync(WIKI.config.ssl.cert)      } else {        tlsOpts.pfx = WIKI.config.ssl.inline ? WIKI.config.ssl.pfx : fs.readFileSync(WIKI.config.ssl.pfx)      }      if (!_.isEmpty(WIKI.config.ssl.passphrase)) {        tlsOpts.passphrase = WIKI.config.ssl.passphrase      }      if (!_.isEmpty(WIKI.config.ssl.dhparam)) {        tlsOpts.dhparam = WIKI.config.ssl.dhparam      }    } catch (err) {      WIKI.logger.error('Failed to setup HTTPS server parameters:')      WIKI.logger.error(err)      return process.exit(1)    }    this.servers.https = https.createServer(tlsOpts, WIKI.app)    this.servers.graph.installSubscriptionHandlers(this.servers.https)    this.servers.https.listen(WIKI.config.ssl.port, WIKI.config.bindIP)    this.servers.https.on('error', (error) => {      if (error.syscall !== 'listen') {        throw error      }      switch (error.code) {        case 'EACCES':          WIKI.logger.error('Listening on port ' + WIKI.config.ssl.port + ' requires elevated privileges!')          return process.exit(1)        case 'EADDRINUSE':          WIKI.logger.error('Port ' + WIKI.config.ssl.port + ' is already in use!')          return process.exit(1)        default:          throw error      }    })    this.servers.https.on('listening', () => {      WIKI.logger.info('HTTPS Server: [ RUNNING ]')    })    this.servers.https.on('connection', conn => {      let connKey = `https:${conn.remoteAddress}:${conn.remotePort}`      this.connections.set(connKey, conn)      conn.on('close', () => {        this.connections.delete(connKey)      })    })  },  /**   * Start GraphQL Server   */  async startGraphQL () {    const graphqlSchema = require('../graph')    this.servers.graph = new ApolloServer({      ...graphqlSchema,      context: ({ req, res }) => ({ req, res }),      subscriptions: {        onConnect: (connectionParams, webSocket) => {        },        path: '/graphql-subscriptions'      }    })    this.servers.graph.applyMiddleware({ app: WIKI.app })  },  /**   * Close all active connections   */  closeConnections (mode = 'all') {    for (const [key, conn] of this.connections) {      if (mode !== `all` && key.indexOf(`${mode}:`) !== 0) {        continue      }      conn.destroy()      this.connections.delete(key)    }    if (mode === 'all') {      this.connections.clear()    }  },  /**   * Stop all servers   */  async stopServers () {    this.closeConnections()    if (this.servers.http) {      await Promise.fromCallback(cb => { this.servers.http.close(cb) })      this.servers.http = null    }    if (this.servers.https) {      await Promise.fromCallback(cb => { this.servers.https.close(cb) })      this.servers.https = null    }    this.servers.graph = null  },  /**   * Restart Server   */  async restartServer (srv = 'https') {    this.closeConnections(srv)    switch (srv) {      case 'http':        if (this.servers.http) {          await Promise.fromCallback(cb => { this.servers.http.close(cb) })          this.servers.http = null        }        this.startHTTP()        break      case 'https':        if (this.servers.https) {          await Promise.fromCallback(cb => { this.servers.https.close(cb) })          this.servers.https = null        }        this.startHTTPS()        break      default:        throw new Error('Cannot restart server: Invalid designation')    }  }}
 |