app.coffee 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. express = require('express')
  2. logger = require('logger-sharelatex')
  3. logger.initialize("filestore")
  4. settings = require("settings-sharelatex")
  5. request = require("request")
  6. fileController = require("./app/js/FileController")
  7. keyBuilder = require("./app/js/KeyBuilder")
  8. domain = require("domain")
  9. appIsOk = true
  10. app = express()
  11. streamBuffers = require("stream-buffers")
  12. Metrics = require "metrics-sharelatex"
  13. Metrics.initialize("filestore")
  14. Metrics.open_sockets.monitor(logger)
  15. Metrics.event_loop?.monitor(logger)
  16. app.configure ->
  17. app.use express.bodyParser()
  18. app.use Metrics.http.monitor(logger)
  19. app.configure 'development', ->
  20. console.log "Development Enviroment"
  21. app.use express.errorHandler({ dumpExceptions: true, showStack: true })
  22. app.configure 'production', ->
  23. console.log "Production Enviroment"
  24. app.use express.errorHandler()
  25. Metrics.inc "startup"
  26. app.use (req, res, next)->
  27. Metrics.inc "http-request"
  28. next()
  29. app.use (req, res, next) ->
  30. requestDomain = domain.create()
  31. requestDomain.add req
  32. requestDomain.add res
  33. requestDomain.on "error", (err)->
  34. try
  35. appIsOk = false
  36. # request a shutdown to prevent memory leaks
  37. beginShutdown()
  38. if !res.headerSent
  39. res.send(500, "uncaught exception")
  40. logger = require('logger-sharelatex')
  41. req =
  42. body:req.body
  43. headers:req.headers
  44. url:req.url
  45. key: req.key
  46. statusCode: req.statusCode
  47. err =
  48. message: err.message
  49. stack: err.stack
  50. name: err.name
  51. type: err.type
  52. arguments: err.arguments
  53. logger.err err:err, req:req, res:res, "uncaught exception thrown on request"
  54. catch exception
  55. logger.err err: exception, "exception in request domain handler"
  56. requestDomain.run next
  57. app.use (req, res, next) ->
  58. if not appIsOk
  59. # when shutting down, close any HTTP keep-alive connections
  60. res.set 'Connection', 'close'
  61. next()
  62. app.get "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.getFile
  63. app.post "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.insertFile
  64. app.put "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.copyFile
  65. app.del "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.deleteFile
  66. app.get "/template/:template_id/v/:version/:format", keyBuilder.templateFileKey, fileController.getFile
  67. app.get "/template/:template_id/v/:version/:format/:sub_type", keyBuilder.templateFileKey, fileController.getFile
  68. app.post "/template/:template_id/v/:version/:format", keyBuilder.templateFileKey, fileController.insertFile
  69. app.get "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.getFile
  70. app.post "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.insertFile
  71. app.put "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.copyFile
  72. app.del "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.deleteFile
  73. app.get "/heapdump", (req, res)->
  74. require('heapdump').writeSnapshot '/tmp/' + Date.now() + '.filestore.heapsnapshot', (err, filename)->
  75. res.send filename
  76. app.post "/shutdown", (req, res)->
  77. appIsOk = false
  78. res.send()
  79. app.get '/status', (req, res)->
  80. if appIsOk
  81. res.send('filestore sharelatex up')
  82. else
  83. logger.log "app is not ok - shutting down"
  84. res.send("server is being shut down", 500)
  85. app.get "/health_check", (req, res)->
  86. req.params.project_id = settings.health_check.project_id
  87. req.params.file_id = settings.health_check.file_id
  88. myWritableStreamBuffer = new streamBuffers.WritableStreamBuffer(initialSize: 100)
  89. keyBuilder.userFileKey req, res, ->
  90. fileController.getFile req, myWritableStreamBuffer
  91. myWritableStreamBuffer.on "close", ->
  92. if myWritableStreamBuffer.size() > 0
  93. res.send(200)
  94. else
  95. res.send(503)
  96. app.get '*', (req, res)->
  97. res.send 404
  98. server = require('http').createServer(app)
  99. port = settings.internal.filestore.port or 3009
  100. host = settings.internal.filestore.host or "localhost"
  101. beginShutdown = () ->
  102. if appIsOk
  103. appIsOk = false
  104. # hard-terminate this process if graceful shutdown fails
  105. killTimer = setTimeout () ->
  106. process.exit 1
  107. , 120*1000
  108. killTimer.unref?() # prevent timer from keeping process alive
  109. server.close () ->
  110. logger.log "closed all connections"
  111. Metrics.close()
  112. process.disconnect?()
  113. logger.log "server will stop accepting connections"
  114. server.listen port, host, ->
  115. logger.info "Filestore starting up, listening on #{host}:#{port}"
  116. process.on 'SIGTERM', () ->
  117. logger.log("filestore got SIGTERM, shutting down gracefully")
  118. beginShutdown()