CompileManager.coffee 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. Settings = require('settings-sharelatex')
  2. redis = require("redis-sharelatex")
  3. rclient = redis.createClient(Settings.redis.web)
  4. DocumentUpdaterHandler = require "../DocumentUpdater/DocumentUpdaterHandler"
  5. Project = require("../../models/Project").Project
  6. ProjectRootDocManager = require "../Project/ProjectRootDocManager"
  7. UserGetter = require "../User/UserGetter"
  8. ClsiManager = require "./ClsiManager"
  9. Metrics = require('../../infrastructure/Metrics')
  10. logger = require("logger-sharelatex")
  11. rateLimiter = require("../../infrastructure/RateLimiter")
  12. module.exports = CompileManager =
  13. compile: (project_id, user_id, options = {}, _callback = (error) ->) ->
  14. timer = new Metrics.Timer("editor.compile")
  15. callback = (args...) ->
  16. timer.done()
  17. _callback(args...)
  18. @_checkIfAutoCompileLimitHasBeenHit options.isAutoCompile, (err, canCompile)->
  19. if !canCompile
  20. return callback null, "autocompile-backoff", []
  21. logger.log project_id: project_id, user_id: user_id, "compiling project"
  22. CompileManager._checkIfRecentlyCompiled project_id, user_id, (error, recentlyCompiled) ->
  23. return callback(error) if error?
  24. if recentlyCompiled
  25. logger.warn {project_id, user_id}, "project was recently compiled so not continuing"
  26. return callback null, "too-recently-compiled", []
  27. CompileManager._ensureRootDocumentIsSet project_id, (error) ->
  28. return callback(error) if error?
  29. DocumentUpdaterHandler.flushProjectToMongo project_id, (error) ->
  30. return callback(error) if error?
  31. CompileManager.getProjectCompileLimits project_id, (error, limits) ->
  32. return callback(error) if error?
  33. for key, value of limits
  34. options[key] = value
  35. # only pass user_id down to clsi if this is a per-user compile
  36. compileAsUser = if Settings.disablePerUserCompiles then undefined else user_id
  37. ClsiManager.sendRequest project_id, compileAsUser, options, (error, status, outputFiles, clsiServerId, validationProblems) ->
  38. return callback(error) if error?
  39. logger.log files: outputFiles, "output files"
  40. callback(null, status, outputFiles, clsiServerId, limits, validationProblems)
  41. stopCompile: (project_id, user_id, callback = (error) ->) ->
  42. CompileManager.getProjectCompileLimits project_id, (error, limits) ->
  43. return callback(error) if error?
  44. ClsiManager.stopCompile project_id, user_id, limits, callback
  45. deleteAuxFiles: (project_id, user_id, callback = (error) ->) ->
  46. CompileManager.getProjectCompileLimits project_id, (error, limits) ->
  47. return callback(error) if error?
  48. ClsiManager.deleteAuxFiles project_id, user_id, limits, callback
  49. getProjectCompileLimits: (project_id, callback = (error, limits) ->) ->
  50. Project.findById project_id, {owner_ref: 1}, (error, project) ->
  51. return callback(error) if error?
  52. UserGetter.getUser project.owner_ref, {"features":1}, (err, owner)->
  53. return callback(error) if error?
  54. callback null, {
  55. timeout: owner.features?.compileTimeout || Settings.defaultFeatures.compileTimeout
  56. compileGroup: owner.features?.compileGroup || Settings.defaultFeatures.compileGroup
  57. }
  58. COMPILE_DELAY: 1 # seconds
  59. _checkIfRecentlyCompiled: (project_id, user_id, callback = (error, recentlyCompiled) ->) ->
  60. key = "compile:#{project_id}:#{user_id}"
  61. rclient.set key, true, "EX", @COMPILE_DELAY, "NX", (error, ok) ->
  62. return callback(error) if error?
  63. if ok == "OK"
  64. return callback null, false
  65. else
  66. return callback null, true
  67. _checkIfAutoCompileLimitHasBeenHit: (isAutoCompile, callback = (err, canCompile)->)->
  68. if !isAutoCompile
  69. return callback(null, true)
  70. opts =
  71. endpointName:"auto_compile"
  72. timeInterval:20
  73. subjectName:"everyone"
  74. throttle: 25
  75. rateLimiter.addCount opts, (err, canCompile)->
  76. if err?
  77. canCompile = false
  78. logger.log canCompile:canCompile, opts:opts, "checking if auto compile limit has been hit"
  79. callback err, canCompile
  80. _ensureRootDocumentIsSet: (project_id, callback = (error) ->) ->
  81. Project.findById project_id, 'rootDoc_id', (error, project)=>
  82. return callback(error) if error?
  83. if !project?
  84. return callback new Error("project not found")
  85. if project.rootDoc_id?
  86. callback()
  87. else
  88. ProjectRootDocManager.setRootDocAutomatically project_id, callback
  89. wordCount: (project_id, user_id, file, callback = (error) ->) ->
  90. CompileManager.getProjectCompileLimits project_id, (error, limits) ->
  91. return callback(error) if error?
  92. ClsiManager.wordCount project_id, user_id, file, limits, callback