HttpController.coffee 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. DocumentManager = require "./DocumentManager"
  2. ProjectManager = require "./ProjectManager"
  3. Errors = require "./Errors"
  4. logger = require "logger-sharelatex"
  5. Metrics = require "./Metrics"
  6. TWO_MEGABYTES = 2 * 1024 * 1024
  7. module.exports = HttpController =
  8. getDoc: (req, res, next = (error) ->) ->
  9. doc_id = req.params.doc_id
  10. project_id = req.params.project_id
  11. logger.log project_id: project_id, doc_id: doc_id, "getting doc via http"
  12. timer = new Metrics.Timer("http.getDoc")
  13. if req.query?.fromVersion?
  14. fromVersion = parseInt(req.query.fromVersion, 10)
  15. else
  16. fromVersion = -1
  17. DocumentManager.getDocAndRecentOpsWithLock project_id, doc_id, fromVersion, (error, lines, version, ops, ranges) ->
  18. timer.done()
  19. return next(error) if error?
  20. logger.log project_id: project_id, doc_id: doc_id, "got doc via http"
  21. if !lines? or !version?
  22. return next(new Errors.NotFoundError("document not found"))
  23. res.send JSON.stringify
  24. id: doc_id
  25. lines: lines
  26. version: version
  27. ops: ops
  28. ranges: ranges
  29. _getTotalSizeOfLines: (lines) ->
  30. size = 0
  31. for line in lines
  32. size += (line.length + 1)
  33. return size
  34. getProjectDocsAndFlushIfOld: (req, res, next = (error) ->) ->
  35. project_id = req.params.project_id
  36. projectStateHash = req.query?.state
  37. # exclude is string of existing docs "id:version,id:version,..."
  38. excludeItems = req.query?.exclude?.split(',') or []
  39. logger.log project_id: project_id, exclude: excludeItems, "getting docs via http"
  40. timer = new Metrics.Timer("http.getAllDocs")
  41. excludeVersions = {}
  42. for item in excludeItems
  43. [id,version] = item?.split(':')
  44. excludeVersions[id] = version
  45. logger.log {project_id: project_id, projectStateHash: projectStateHash, excludeVersions: excludeVersions}, "excluding versions"
  46. ProjectManager.getProjectDocsAndFlushIfOld project_id, projectStateHash, excludeVersions, (error, result) ->
  47. timer.done()
  48. if error instanceof Errors.ProjectStateChangedError
  49. res.send 409 # conflict
  50. else if error?
  51. return next(error)
  52. else
  53. logger.log project_id: project_id, result: ("#{doc._id}:#{doc.v}" for doc in result), "got docs via http"
  54. res.send result
  55. clearProjectState: (req, res, next = (error) ->) ->
  56. project_id = req.params.project_id
  57. timer = new Metrics.Timer("http.clearProjectState")
  58. logger.log project_id: project_id, "clearing project state via http"
  59. ProjectManager.clearProjectState project_id, (error) ->
  60. timer.done()
  61. if error?
  62. return next(error)
  63. else
  64. res.send 200
  65. setDoc: (req, res, next = (error) ->) ->
  66. doc_id = req.params.doc_id
  67. project_id = req.params.project_id
  68. {lines, source, user_id, undoing} = req.body
  69. lineSize = HttpController._getTotalSizeOfLines(lines)
  70. if lineSize > TWO_MEGABYTES
  71. logger.log {project_id, doc_id, source, lineSize, user_id}, "document too large, returning 406 response"
  72. return res.send 406
  73. logger.log {project_id, doc_id, lines, source, user_id, undoing}, "setting doc via http"
  74. timer = new Metrics.Timer("http.setDoc")
  75. DocumentManager.setDocWithLock project_id, doc_id, lines, source, user_id, undoing, (error) ->
  76. timer.done()
  77. return next(error) if error?
  78. logger.log project_id: project_id, doc_id: doc_id, "set doc via http"
  79. res.send 204 # No Content
  80. flushDocIfLoaded: (req, res, next = (error) ->) ->
  81. doc_id = req.params.doc_id
  82. project_id = req.params.project_id
  83. logger.log project_id: project_id, doc_id: doc_id, "flushing doc via http"
  84. timer = new Metrics.Timer("http.flushDoc")
  85. DocumentManager.flushDocIfLoadedWithLock project_id, doc_id, (error) ->
  86. timer.done()
  87. return next(error) if error?
  88. logger.log project_id: project_id, doc_id: doc_id, "flushed doc via http"
  89. res.send 204 # No Content
  90. flushAndDeleteDoc: (req, res, next = (error) ->) ->
  91. doc_id = req.params.doc_id
  92. project_id = req.params.project_id
  93. logger.log project_id: project_id, doc_id: doc_id, "deleting doc via http"
  94. timer = new Metrics.Timer("http.deleteDoc")
  95. DocumentManager.flushAndDeleteDocWithLock project_id, doc_id, (error) ->
  96. timer.done()
  97. return next(error) if error?
  98. logger.log project_id: project_id, doc_id: doc_id, "deleted doc via http"
  99. res.send 204 # No Content
  100. flushProject: (req, res, next = (error) ->) ->
  101. project_id = req.params.project_id
  102. logger.log project_id: project_id, "flushing project via http"
  103. timer = new Metrics.Timer("http.flushProject")
  104. ProjectManager.flushProjectWithLocks project_id, (error) ->
  105. timer.done()
  106. return next(error) if error?
  107. logger.log project_id: project_id, "flushed project via http"
  108. res.send 204 # No Content
  109. deleteProject: (req, res, next = (error) ->) ->
  110. project_id = req.params.project_id
  111. logger.log project_id: project_id, "deleting project via http"
  112. timer = new Metrics.Timer("http.deleteProject")
  113. ProjectManager.flushAndDeleteProjectWithLocks project_id, (error) ->
  114. timer.done()
  115. return next(error) if error?
  116. logger.log project_id: project_id, "deleted project via http"
  117. res.send 204 # No Content
  118. acceptChanges: (req, res, next = (error) ->) ->
  119. {project_id, doc_id} = req.params
  120. change_ids = req.body?.change_ids
  121. if !change_ids?
  122. change_ids = [ req.params.change_id ]
  123. logger.log {project_id, doc_id}, "accepting #{ change_ids.length } changes via http"
  124. timer = new Metrics.Timer("http.acceptChanges")
  125. DocumentManager.acceptChangesWithLock project_id, doc_id, change_ids, (error) ->
  126. timer.done()
  127. return next(error) if error?
  128. logger.log {project_id, doc_id}, "accepted #{ change_ids.length } changes via http"
  129. res.send 204 # No Content
  130. deleteComment: (req, res, next = (error) ->) ->
  131. {project_id, doc_id, comment_id} = req.params
  132. logger.log {project_id, doc_id, comment_id}, "deleting comment via http"
  133. timer = new Metrics.Timer("http.deleteComment")
  134. DocumentManager.deleteCommentWithLock project_id, doc_id, comment_id, (error) ->
  135. timer.done()
  136. return next(error) if error?
  137. logger.log {project_id, doc_id, comment_id}, "deleted comment via http"
  138. res.send 204 # No Content