DocumentManager.coffee 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. RedisManager = require "./RedisManager"
  2. PersistenceManager = require "./PersistenceManager"
  3. DiffCodec = require "./DiffCodec"
  4. logger = require "logger-sharelatex"
  5. Metrics = require "./Metrics"
  6. HistoryManager = require "./HistoryManager"
  7. WebRedisManager = require "./WebRedisManager"
  8. Errors = require "./Errors"
  9. RangesManager = require "./RangesManager"
  10. module.exports = DocumentManager =
  11. getDoc: (project_id, doc_id, _callback = (error, lines, version, alreadyLoaded) ->) ->
  12. timer = new Metrics.Timer("docManager.getDoc")
  13. callback = (args...) ->
  14. timer.done()
  15. _callback(args...)
  16. RedisManager.getDoc project_id, doc_id, (error, lines, version, ranges) ->
  17. return callback(error) if error?
  18. if !lines? or !version?
  19. logger.log {project_id, doc_id}, "doc not in redis so getting from persistence API"
  20. PersistenceManager.getDoc project_id, doc_id, (error, lines, version, ranges) ->
  21. return callback(error) if error?
  22. logger.log {project_id, doc_id, lines, version}, "got doc from persistence API"
  23. RedisManager.putDocInMemory project_id, doc_id, lines, version, ranges, (error) ->
  24. return callback(error) if error?
  25. callback null, lines, version, ranges, false
  26. else
  27. callback null, lines, version, ranges, true
  28. getDocAndRecentOps: (project_id, doc_id, fromVersion, _callback = (error, lines, version, recentOps, ranges) ->) ->
  29. timer = new Metrics.Timer("docManager.getDocAndRecentOps")
  30. callback = (args...) ->
  31. timer.done()
  32. _callback(args...)
  33. DocumentManager.getDoc project_id, doc_id, (error, lines, version, ranges) ->
  34. return callback(error) if error?
  35. if fromVersion == -1
  36. callback null, lines, version, [], ranges
  37. else
  38. RedisManager.getPreviousDocOps doc_id, fromVersion, version, (error, ops) ->
  39. return callback(error) if error?
  40. callback null, lines, version, ops, ranges
  41. setDoc: (project_id, doc_id, newLines, source, user_id, _callback = (error) ->) ->
  42. timer = new Metrics.Timer("docManager.setDoc")
  43. callback = (args...) ->
  44. timer.done()
  45. _callback(args...)
  46. if !newLines?
  47. return callback(new Error("No lines were provided to setDoc"))
  48. UpdateManager = require "./UpdateManager"
  49. DocumentManager.getDoc project_id, doc_id, (error, oldLines, version, ranges, alreadyLoaded) ->
  50. return callback(error) if error?
  51. if oldLines? and oldLines.length > 0 and oldLines[0].text?
  52. logger.log doc_id: doc_id, project_id: project_id, oldLines: oldLines, newLines: newLines, "document is JSON so not updating"
  53. return callback(null)
  54. logger.log doc_id: doc_id, project_id: project_id, oldLines: oldLines, newLines: newLines, "setting a document via http"
  55. DiffCodec.diffAsShareJsOp oldLines, newLines, (error, op) ->
  56. return callback(error) if error?
  57. update =
  58. doc: doc_id
  59. op: op
  60. v: version
  61. meta:
  62. type: "external"
  63. source: source
  64. user_id: user_id
  65. UpdateManager.applyUpdate project_id, doc_id, update, (error) ->
  66. return callback(error) if error?
  67. # If the document was loaded already, then someone has it open
  68. # in a project, and the usual flushing mechanism will happen.
  69. # Otherwise we should remove it immediately since nothing else
  70. # is using it.
  71. if alreadyLoaded
  72. DocumentManager.flushDocIfLoaded project_id, doc_id, (error) ->
  73. return callback(error) if error?
  74. callback null
  75. else
  76. DocumentManager.flushAndDeleteDoc project_id, doc_id, (error) ->
  77. return callback(error) if error?
  78. callback null
  79. flushDocIfLoaded: (project_id, doc_id, _callback = (error) ->) ->
  80. timer = new Metrics.Timer("docManager.flushDocIfLoaded")
  81. callback = (args...) ->
  82. timer.done()
  83. _callback(args...)
  84. RedisManager.getDoc project_id, doc_id, (error, lines, version, ranges) ->
  85. return callback(error) if error?
  86. if !lines? or !version?
  87. logger.log project_id: project_id, doc_id: doc_id, "doc is not loaded so not flushing"
  88. callback null # TODO: return a flag to bail out, as we go on to remove doc from memory?
  89. else
  90. logger.log project_id: project_id, doc_id: doc_id, version: version, "flushing doc"
  91. PersistenceManager.setDoc project_id, doc_id, lines, version, ranges, (error) ->
  92. return callback(error) if error?
  93. callback null
  94. flushAndDeleteDoc: (project_id, doc_id, _callback = (error) ->) ->
  95. timer = new Metrics.Timer("docManager.flushAndDeleteDoc")
  96. callback = (args...) ->
  97. timer.done()
  98. _callback(args...)
  99. DocumentManager.flushDocIfLoaded project_id, doc_id, (error) ->
  100. return callback(error) if error?
  101. # Flush in the background since it requires and http request
  102. # to track changes
  103. HistoryManager.flushDocChanges project_id, doc_id, (err) ->
  104. if err?
  105. logger.err {err, project_id, doc_id}, "error flushing to track changes"
  106. RedisManager.removeDocFromMemory project_id, doc_id, (error) ->
  107. return callback(error) if error?
  108. callback null
  109. acceptChange: (project_id, doc_id, change_id, _callback = (error) ->) ->
  110. timer = new Metrics.Timer("docManager.acceptChange")
  111. callback = (args...) ->
  112. timer.done()
  113. _callback(args...)
  114. DocumentManager.getDoc project_id, doc_id, (error, lines, version, ranges) ->
  115. return callback(error) if error?
  116. if !lines? or !version?
  117. return callback(new Errors.NotFoundError("document not found: #{doc_id}"))
  118. RangesManager.acceptChange change_id, ranges, (error, new_ranges) ->
  119. return callback(error) if error?
  120. RedisManager.updateDocument doc_id, lines, version, [], new_ranges, (error) ->
  121. return callback(error) if error?
  122. callback()
  123. deleteComment: (project_id, doc_id, comment_id, _callback = (error) ->) ->
  124. timer = new Metrics.Timer("docManager.deleteComment")
  125. callback = (args...) ->
  126. timer.done()
  127. _callback(args...)
  128. DocumentManager.getDoc project_id, doc_id, (error, lines, version, ranges) ->
  129. return callback(error) if error?
  130. if !lines? or !version?
  131. return callback(new Errors.NotFoundError("document not found: #{doc_id}"))
  132. RangesManager.deleteComment comment_id, ranges, (error, new_ranges) ->
  133. return callback(error) if error?
  134. RedisManager.updateDocument doc_id, lines, version, [], new_ranges, (error) ->
  135. return callback(error) if error?
  136. callback()
  137. getDocWithLock: (project_id, doc_id, callback = (error, lines, version) ->) ->
  138. UpdateManager = require "./UpdateManager"
  139. UpdateManager.lockUpdatesAndDo DocumentManager.getDoc, project_id, doc_id, callback
  140. getDocAndRecentOpsWithLock: (project_id, doc_id, fromVersion, callback = (error, lines, version) ->) ->
  141. UpdateManager = require "./UpdateManager"
  142. UpdateManager.lockUpdatesAndDo DocumentManager.getDocAndRecentOps, project_id, doc_id, fromVersion, callback
  143. setDocWithLock: (project_id, doc_id, lines, source, user_id, callback = (error) ->) ->
  144. UpdateManager = require "./UpdateManager"
  145. UpdateManager.lockUpdatesAndDo DocumentManager.setDoc, project_id, doc_id, lines, source, user_id, callback
  146. flushDocIfLoadedWithLock: (project_id, doc_id, callback = (error) ->) ->
  147. UpdateManager = require "./UpdateManager"
  148. UpdateManager.lockUpdatesAndDo DocumentManager.flushDocIfLoaded, project_id, doc_id, callback
  149. flushAndDeleteDocWithLock: (project_id, doc_id, callback = (error) ->) ->
  150. UpdateManager = require "./UpdateManager"
  151. UpdateManager.lockUpdatesAndDo DocumentManager.flushAndDeleteDoc, project_id, doc_id, callback
  152. acceptChangeWithLock: (project_id, doc_id, change_id, callback = (error) ->) ->
  153. UpdateManager = require "./UpdateManager"
  154. UpdateManager.lockUpdatesAndDo DocumentManager.acceptChange, project_id, doc_id, change_id, callback
  155. deleteCommentWithLock: (project_id, doc_id, thread_id, callback = (error) ->) ->
  156. UpdateManager = require "./UpdateManager"
  157. UpdateManager.lockUpdatesAndDo DocumentManager.deleteComment, project_id, doc_id, thread_id, callback