You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
5.4 KiB

  1. const autoload = require('auto-load')
  2. const bodyParser = require('body-parser')
  3. const compression = require('compression')
  4. const cookieParser = require('cookie-parser')
  5. const cors = require('cors')
  6. const express = require('express')
  7. const favicon = require('serve-favicon')
  8. const http = require('http')
  9. const path = require('path')
  10. const session = require('express-session')
  11. const SessionRedisStore = require('connect-redis')(session)
  12. const graphqlApollo = require('apollo-server-express')
  13. const graphqlSchema = require('./core/graphql')
  14. /* global wiki */
  15. module.exports = async () => {
  16. // ----------------------------------------
  17. // Load core modules
  18. // ----------------------------------------
  19. wiki.auth = require('./core/auth').init()
  20. wiki.lang = require('./core/localization').init()
  21. // ----------------------------------------
  22. // Load middlewares
  23. // ----------------------------------------
  24. var mw = autoload(path.join(wiki.SERVERPATH, '/middlewares'))
  25. var ctrl = autoload(path.join(wiki.SERVERPATH, '/controllers'))
  26. // ----------------------------------------
  27. // Define Express App
  28. // ----------------------------------------
  29. const app = express()
  30. wiki.app = app
  31. app.use(compression())
  32. // ----------------------------------------
  33. // Security
  34. // ----------------------------------------
  35. app.use(mw.security)
  36. app.use(cors(wiki.config.cors))
  37. app.options('*', cors(wiki.config.cors))
  38. app.enable('trust proxy')
  39. // ----------------------------------------
  40. // Public Assets
  41. // ----------------------------------------
  42. app.use(favicon(path.join(wiki.ROOTPATH, 'assets', 'favicon.ico')))
  43. app.use(express.static(path.join(wiki.ROOTPATH, 'assets'), {
  44. index: false,
  45. maxAge: '7d'
  46. }))
  47. // ----------------------------------------
  48. // Passport Authentication
  49. // ----------------------------------------
  50. let sessionStore = new SessionRedisStore({
  51. client: wiki.redis
  52. })
  53. app.use(cookieParser())
  54. app.use(session({
  55. name: 'wikijs.sid',
  56. store: sessionStore,
  57. secret: wiki.config.site.sessionSecret,
  58. resave: false,
  59. saveUninitialized: false
  60. }))
  61. app.use(wiki.auth.passport.initialize())
  62. app.use(wiki.auth.passport.session())
  63. // ----------------------------------------
  64. // SEO
  65. // ----------------------------------------
  66. app.use(mw.seo)
  67. // ----------------------------------------
  68. // View Engine Setup
  69. // ----------------------------------------
  70. app.set('views', path.join(wiki.SERVERPATH, 'views'))
  71. app.set('view engine', 'pug')
  72. app.use(bodyParser.json({ limit: '1mb' }))
  73. app.use(bodyParser.urlencoded({ extended: false, limit: '1mb' }))
  74. // ----------------------------------------
  75. // Localization
  76. // ----------------------------------------
  77. wiki.lang.attachMiddleware(app)
  78. // ----------------------------------------
  79. // View accessible data
  80. // ----------------------------------------
  81. app.locals.basedir = wiki.ROOTPATH
  82. app.locals._ = require('lodash')
  83. app.locals.moment = require('moment')
  84. app.locals.moment.locale(wiki.config.site.lang)
  85. app.locals.config = wiki.config
  86. // ----------------------------------------
  87. // HMR (Dev Mode Only)
  88. // ----------------------------------------
  89. if (global.DEV) {
  90. app.use(global.WP_DEV.devMiddleware)
  91. app.use(global.WP_DEV.hotMiddleware)
  92. }
  93. // ----------------------------------------
  94. // Controllers
  95. // ----------------------------------------
  96. app.use('/', ctrl.auth)
  97. app.use('/graphql', (req, res, next) => {
  98. graphqlApollo.graphqlExpress({
  99. schema: graphqlSchema,
  100. context: { req, res },
  101. formatError: (err) => {
  102. return {
  103. message: err.message
  104. }
  105. }
  106. })(req, res, next)
  107. })
  108. app.use('/graphiql', graphqlApollo.graphiqlExpress({ endpointURL: '/graphql' }))
  109. app.use('/', mw.auth, ctrl.common)
  110. // ----------------------------------------
  111. // Error handling
  112. // ----------------------------------------
  113. app.use((req, res, next) => {
  114. var err = new Error('Not Found')
  115. err.status = 404
  116. next(err)
  117. })
  118. app.use((err, req, res, next) => {
  119. res.status(err.status || 500)
  120. res.render('error', {
  121. message: err.message,
  122. error: wiki.IS_DEBUG ? err : {}
  123. })
  124. })
  125. // ----------------------------------------
  126. // HTTP server
  127. // ----------------------------------------
  128. let srvConnections = {}
  129. wiki.logger.info(`HTTP Server on port: [ ${wiki.config.port} ]`)
  130. app.set('port', wiki.config.port)
  131. wiki.server = http.createServer(app)
  132. wiki.server.listen(wiki.config.port)
  133. wiki.server.on('error', (error) => {
  134. if (error.syscall !== 'listen') {
  135. throw error
  136. }
  137. // handle specific listen errors with friendly messages
  138. switch (error.code) {
  139. case 'EACCES':
  140. wiki.logger.error('Listening on port ' + wiki.config.port + ' requires elevated privileges!')
  141. return process.exit(1)
  142. case 'EADDRINUSE':
  143. wiki.logger.error('Port ' + wiki.config.port + ' is already in use!')
  144. return process.exit(1)
  145. default:
  146. throw error
  147. }
  148. })
  149. wiki.server.on('connection', conn => {
  150. let key = `${conn.remoteAddress}:${conn.remotePort}`
  151. srvConnections[key] = conn
  152. conn.on('close', function() {
  153. delete srvConnections[key]
  154. })
  155. })
  156. wiki.server.on('listening', () => {
  157. wiki.logger.info('HTTP Server: [ RUNNING ]')
  158. })
  159. wiki.server.destroy = (cb) => {
  160. wiki.server.close(cb)
  161. for (let key in srvConnections) {
  162. srvConnections[key].destroy()
  163. }
  164. }
  165. return true
  166. }