HttpController.coffee 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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, pathname) ->
  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. pathname: pathname
  30. _getTotalSizeOfLines: (lines) ->
  31. size = 0
  32. for line in lines
  33. size += (line.length + 1)
  34. return size
  35. getProjectDocsAndFlushIfOld: (req, res, next = (error) ->) ->
  36. project_id = req.params.project_id
  37. projectStateHash = req.query?.state
  38. # exclude is string of existing docs "id:version,id:version,..."
  39. excludeItems = req.query?.exclude?.split(',') or []
  40. logger.log project_id: project_id, exclude: excludeItems, "getting docs via http"
  41. timer = new Metrics.Timer("http.getAllDocs")
  42. excludeVersions = {}
  43. for item in excludeItems
  44. [id,version] = item?.split(':')
  45. excludeVersions[id] = version
  46. logger.log {project_id: project_id, projectStateHash: projectStateHash, excludeVersions: excludeVersions}, "excluding versions"
  47. ProjectManager.getProjectDocsAndFlushIfOld project_id, projectStateHash, excludeVersions, (error, result) ->
  48. timer.done()
  49. if error instanceof Errors.ProjectStateChangedError
  50. res.send 409 # conflict
  51. else if error?
  52. return next(error)
  53. else
  54. logger.log project_id: project_id, result: ("#{doc._id}:#{doc.v}" for doc in result), "got docs via http"
  55. res.send result
  56. clearProjectState: (req, res, next = (error) ->) ->
  57. project_id = req.params.project_id
  58. timer = new Metrics.Timer("http.clearProjectState")
  59. logger.log project_id: project_id, "clearing project state via http"
  60. ProjectManager.clearProjectState project_id, (error) ->
  61. timer.done()
  62. if error?
  63. return next(error)
  64. else
  65. res.send 200
  66. setDoc: (req, res, next = (error) ->) ->
  67. doc_id = req.params.doc_id
  68. project_id = req.params.project_id
  69. {lines, source, user_id, undoing} = req.body
  70. lineSize = HttpController._getTotalSizeOfLines(lines)
  71. if lineSize > TWO_MEGABYTES
  72. logger.log {project_id, doc_id, source, lineSize, user_id}, "document too large, returning 406 response"
  73. return res.send 406
  74. logger.log {project_id, doc_id, lines, source, user_id, undoing}, "setting doc via http"
  75. timer = new Metrics.Timer("http.setDoc")
  76. DocumentManager.setDocWithLock project_id, doc_id, lines, source, user_id, undoing, (error) ->
  77. timer.done()
  78. return next(error) if error?
  79. logger.log project_id: project_id, doc_id: doc_id, "set doc via http"
  80. res.send 204 # No Content
  81. flushDocIfLoaded: (req, res, next = (error) ->) ->
  82. doc_id = req.params.doc_id
  83. project_id = req.params.project_id
  84. logger.log project_id: project_id, doc_id: doc_id, "flushing doc via http"
  85. timer = new Metrics.Timer("http.flushDoc")
  86. DocumentManager.flushDocIfLoadedWithLock project_id, doc_id, (error) ->
  87. timer.done()
  88. return next(error) if error?
  89. logger.log project_id: project_id, doc_id: doc_id, "flushed doc via http"
  90. res.send 204 # No Content
  91. flushAndDeleteDoc: (req, res, next = (error) ->) ->
  92. doc_id = req.params.doc_id
  93. project_id = req.params.project_id
  94. logger.log project_id: project_id, doc_id: doc_id, "deleting doc via http"
  95. timer = new Metrics.Timer("http.deleteDoc")
  96. DocumentManager.flushAndDeleteDocWithLock project_id, doc_id, (error) ->
  97. timer.done()
  98. return next(error) if error?
  99. logger.log project_id: project_id, doc_id: doc_id, "deleted doc via http"
  100. res.send 204 # No Content
  101. flushProject: (req, res, next = (error) ->) ->
  102. project_id = req.params.project_id
  103. logger.log project_id: project_id, "flushing project via http"
  104. timer = new Metrics.Timer("http.flushProject")
  105. ProjectManager.flushProjectWithLocks project_id, (error) ->
  106. timer.done()
  107. return next(error) if error?
  108. logger.log project_id: project_id, "flushed project via http"
  109. res.send 204 # No Content
  110. deleteProject: (req, res, next = (error) ->) ->
  111. project_id = req.params.project_id
  112. logger.log project_id: project_id, "deleting project via http"
  113. timer = new Metrics.Timer("http.deleteProject")
  114. ProjectManager.flushAndDeleteProjectWithLocks project_id, (error) ->
  115. timer.done()
  116. return next(error) if error?
  117. logger.log project_id: project_id, "deleted project via http"
  118. res.send 204 # No Content
  119. acceptChanges: (req, res, next = (error) ->) ->
  120. {project_id, doc_id} = req.params
  121. change_ids = req.body?.change_ids
  122. if !change_ids?
  123. change_ids = [ req.params.change_id ]
  124. logger.log {project_id, doc_id}, "accepting #{ change_ids.length } changes via http"
  125. timer = new Metrics.Timer("http.acceptChanges")
  126. DocumentManager.acceptChangesWithLock project_id, doc_id, change_ids, (error) ->
  127. timer.done()
  128. return next(error) if error?
  129. logger.log {project_id, doc_id}, "accepted #{ change_ids.length } changes via http"
  130. res.send 204 # No Content
  131. deleteComment: (req, res, next = (error) ->) ->
  132. {project_id, doc_id, comment_id} = req.params
  133. logger.log {project_id, doc_id, comment_id}, "deleting comment via http"
  134. timer = new Metrics.Timer("http.deleteComment")
  135. DocumentManager.deleteCommentWithLock project_id, doc_id, comment_id, (error) ->
  136. timer.done()
  137. return next(error) if error?
  138. logger.log {project_id, doc_id, comment_id}, "deleted comment via http"
  139. res.send 204 # No Content
  140. updateProject: (req, res, next = (error) ->) ->
  141. timer = new Metrics.Timer("http.updateProject")
  142. project_id = req.params.project_id
  143. {userId, docUpdates, fileUpdates} = req.body
  144. logger.log {project_id, docUpdates, fileUpdates}, "updating project via http"
  145. ProjectManager.updateProjectWithLocks project_id, userId, docUpdates, fileUpdates, (error) ->
  146. timer.done()
  147. return next(error) if error?
  148. logger.log project_id: project_id, "updated project via http"
  149. res.send 204 # No Content