app.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. const Metrics = require('metrics-sharelatex')
  2. const logger = require('logger-sharelatex')
  3. Metrics.initialize('filestore')
  4. logger.initialize('filestore')
  5. const settings = require('settings-sharelatex')
  6. const express = require('express')
  7. const bodyParser = require('body-parser')
  8. const fileController = require('./app/js/FileController')
  9. const bucketController = require('./app/js/BucketController')
  10. const keyBuilder = require('./app/js/KeyBuilder')
  11. const healthCheckController = require('./app/js/HealthCheckController')
  12. const ExceptionHandler = require('./app/js/ExceptionHandler')
  13. const exceptionHandler = new ExceptionHandler()
  14. const app = express()
  15. app.exceptionHandler = exceptionHandler
  16. if (settings.sentry && settings.sentry.dsn) {
  17. logger.initializeErrorReporting(settings.sentry.dsn)
  18. }
  19. Metrics.open_sockets.monitor(logger)
  20. Metrics.memory.monitor(logger)
  21. if (Metrics.event_loop) {
  22. Metrics.event_loop.monitor(logger)
  23. }
  24. app.use(Metrics.http.monitor(logger))
  25. app.use(function(req, res, next) {
  26. Metrics.inc('http-request')
  27. next()
  28. })
  29. exceptionHandler.addMiddleware(app)
  30. Metrics.injectMetricsRoute(app)
  31. app.head(
  32. '/project/:project_id/file/:file_id',
  33. keyBuilder.userFileKeyMiddleware,
  34. fileController.getFileHead
  35. )
  36. app.get(
  37. '/project/:project_id/file/:file_id',
  38. keyBuilder.userFileKeyMiddleware,
  39. fileController.getFile
  40. )
  41. app.post(
  42. '/project/:project_id/file/:file_id',
  43. keyBuilder.userFileKeyMiddleware,
  44. fileController.insertFile
  45. )
  46. app.put(
  47. '/project/:project_id/file/:file_id',
  48. keyBuilder.userFileKeyMiddleware,
  49. bodyParser.json(),
  50. fileController.copyFile
  51. )
  52. app.delete(
  53. '/project/:project_id/file/:file_id',
  54. keyBuilder.userFileKeyMiddleware,
  55. fileController.deleteFile
  56. )
  57. app.head(
  58. '/template/:template_id/v/:version/:format',
  59. keyBuilder.templateFileKeyMiddleware,
  60. fileController.getFileHead
  61. )
  62. app.get(
  63. '/template/:template_id/v/:version/:format',
  64. keyBuilder.templateFileKeyMiddleware,
  65. fileController.getFile
  66. )
  67. app.get(
  68. '/template/:template_id/v/:version/:format/:sub_type',
  69. keyBuilder.templateFileKeyMiddleware,
  70. fileController.getFile
  71. )
  72. app.post(
  73. '/template/:template_id/v/:version/:format',
  74. keyBuilder.templateFileKeyMiddleware,
  75. fileController.insertFile
  76. )
  77. app.head(
  78. '/project/:project_id/public/:public_file_id',
  79. keyBuilder.publicFileKeyMiddleware,
  80. fileController.getFileHead
  81. )
  82. app.get(
  83. '/project/:project_id/public/:public_file_id',
  84. keyBuilder.publicFileKeyMiddleware,
  85. fileController.getFile
  86. )
  87. app.post(
  88. '/project/:project_id/public/:public_file_id',
  89. keyBuilder.publicFileKeyMiddleware,
  90. fileController.insertFile
  91. )
  92. app.put(
  93. '/project/:project_id/public/:public_file_id',
  94. keyBuilder.publicFileKeyMiddleware,
  95. bodyParser.json(),
  96. fileController.copyFile
  97. )
  98. app.delete(
  99. '/project/:project_id/public/:public_file_id',
  100. keyBuilder.publicFileKeyMiddleware,
  101. fileController.deleteFile
  102. )
  103. app.get(
  104. '/project/:project_id/size',
  105. keyBuilder.publicProjectKeyMiddleware,
  106. fileController.directorySize
  107. )
  108. app.get('/bucket/:bucket/key/*', bucketController.getFile)
  109. app.get('/heapdump', (req, res, next) =>
  110. require('heapdump').writeSnapshot(
  111. '/tmp/' + Date.now() + '.filestore.heapsnapshot',
  112. (err, filename) => {
  113. if (err) {
  114. return next(err)
  115. }
  116. res.send(filename)
  117. }
  118. )
  119. )
  120. app.post('/shutdown', function(req, res) {
  121. exceptionHandler.setNotOk()
  122. res.sendStatus(200)
  123. })
  124. app.get('/status', function(req, res) {
  125. if (exceptionHandler.appIsOk()) {
  126. res.send('filestore sharelatex up')
  127. } else {
  128. logger.log('app is not ok - shutting down')
  129. res.send('server is being shut down').status(500)
  130. }
  131. })
  132. app.get('/health_check', healthCheckController.check)
  133. app.get('*', (req, res) => res.sendStatus(404))
  134. const port = settings.internal.filestore.port || 3009
  135. const host = '0.0.0.0'
  136. if (!module.parent) {
  137. // Called directly
  138. app.listen(port, host, error => {
  139. if (error) {
  140. logger.error('Error starting Filestore', error)
  141. throw error
  142. }
  143. logger.info(`Filestore starting up, listening on ${host}:${port}`)
  144. })
  145. exceptionHandler.server = server
  146. }
  147. module.exports = app
  148. process.on('SIGTERM', function() {
  149. logger.log('filestore got SIGTERM, shutting down gracefully')
  150. exceptionHandler.beginShutdown()
  151. })
  152. if (global.gc) {
  153. const oneMinute = 60 * 1000
  154. const gcTimer = setInterval(function() {
  155. global.gc()
  156. logger.log(process.memoryUsage(), 'global.gc')
  157. }, 3 * oneMinute)
  158. gcTimer.unref()
  159. }