DocumentUpdaterHandler.coffee 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. request = require 'request'
  2. request = request.defaults()
  3. settings = require 'settings-sharelatex'
  4. _ = require 'underscore'
  5. async = require 'async'
  6. logger = require('logger-sharelatex')
  7. metrics = require('../../infrastructure/Metrics')
  8. redis = require("redis-sharelatex")
  9. rclient = redis.createClient(settings.redis.web)
  10. Project = require("../../models/Project").Project
  11. ProjectLocator = require('../../Features/Project/ProjectLocator')
  12. module.exports = DocumentUpdaterHandler =
  13. queueChange : (project_id, doc_id, change, callback = ()->)->
  14. jsonChange = JSON.stringify change
  15. doc_key = keys.combineProjectIdAndDocId(project_id, doc_id)
  16. multi = rclient.multi()
  17. multi.rpush keys.pendingUpdates(doc_id:doc_id), jsonChange
  18. multi.sadd keys.docsWithPendingUpdates, doc_key
  19. multi.rpush "pending-updates-list", doc_key
  20. multi.exec (error) ->
  21. return callback(error) if error?
  22. callback()
  23. flushProjectToMongo: (project_id, callback = (error) ->)->
  24. logger.log project_id:project_id, "flushing project from document updater"
  25. timer = new metrics.Timer("flushing.mongo.project")
  26. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/flush"
  27. request.post url, (error, res, body)->
  28. if error?
  29. logger.error err: error, project_id: project_id, "error flushing project from document updater"
  30. return callback(error)
  31. else if res.statusCode >= 200 and res.statusCode < 300
  32. logger.log project_id: project_id, "flushed project from document updater"
  33. return callback(null)
  34. else
  35. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  36. logger.error err: error, project_id: project_id, "document updater returned failure status code: #{res.statusCode}"
  37. return callback(error)
  38. flushMultipleProjectsToMongo: (project_ids, callback = (error) ->) ->
  39. jobs = []
  40. for project_id in project_ids
  41. do (project_id) ->
  42. jobs.push (callback) ->
  43. DocumentUpdaterHandler.flushProjectToMongo project_id, callback
  44. async.series jobs, callback
  45. flushProjectToMongoAndDelete: (project_id, callback = ()->) ->
  46. logger.log project_id:project_id, "deleting project from document updater"
  47. timer = new metrics.Timer("delete.mongo.project")
  48. url = "#{settings.apis.documentupdater.url}/project/#{project_id}"
  49. request.del url, (error, res, body)->
  50. if error?
  51. logger.error err: error, project_id: project_id, "error deleting project from document updater"
  52. return callback(error)
  53. else if res.statusCode >= 200 and res.statusCode < 300
  54. logger.log project_id: project_id, "deleted project from document updater"
  55. return callback(null)
  56. else
  57. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  58. logger.error err: error, project_id: project_id, "document updater returned failure status code: #{res.statusCode}"
  59. return callback(error)
  60. flushDocToMongo: (project_id, doc_id, callback = (error) ->) ->
  61. logger.log project_id:project_id, doc_id: doc_id, "flushing doc from document updater"
  62. timer = new metrics.Timer("flushing.mongo.doc")
  63. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}/flush"
  64. request.post url, (error, res, body)->
  65. if error?
  66. logger.error err: error, project_id: project_id, doc_id: doc_id, "error flushing doc from document updater"
  67. return callback(error)
  68. else if res.statusCode >= 200 and res.statusCode < 300
  69. logger.log project_id: project_id, doc_id: doc_id, "flushed doc from document updater"
  70. return callback(null)
  71. else
  72. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  73. logger.error err: error, project_id: project_id, doc_id: doc_id, "document updater returned failure status code: #{res.statusCode}"
  74. return callback(error)
  75. deleteDoc : (project_id, doc_id, callback = ()->)->
  76. logger.log project_id:project_id, doc_id: doc_id, "deleting doc from document updater"
  77. timer = new metrics.Timer("delete.mongo.doc")
  78. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}"
  79. request.del url, (error, res, body)->
  80. if error?
  81. logger.error err: error, project_id: project_id, doc_id: doc_id, "error deleting doc from document updater"
  82. return callback(error)
  83. else if res.statusCode >= 200 and res.statusCode < 300
  84. logger.log project_id: project_id, doc_id: doc_id, "deleted doc from document updater"
  85. return callback(null)
  86. else
  87. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  88. logger.error err: error, project_id: project_id, doc_id: doc_id, "document updater returned failure status code: #{res.statusCode}"
  89. return callback(error)
  90. getDocument: (project_id, doc_id, fromVersion, callback = (error, doclines, version, ranges, ops) ->) ->
  91. timer = new metrics.Timer("get-document")
  92. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}?fromVersion=#{fromVersion}"
  93. logger.log project_id:project_id, doc_id: doc_id, "getting doc from document updater"
  94. request.get url, (error, res, body)->
  95. timer.done()
  96. if error?
  97. logger.error err:error, url:url, project_id:project_id, doc_id:doc_id, "error getting doc from doc updater"
  98. return callback(error)
  99. if res.statusCode >= 200 and res.statusCode < 300
  100. logger.log project_id:project_id, doc_id:doc_id, "got doc from document document updater"
  101. try
  102. body = JSON.parse(body)
  103. catch error
  104. return callback(error)
  105. callback null, body.lines, body.version, body.ranges, body.ops
  106. else
  107. logger.error project_id:project_id, doc_id:doc_id, url: url, "doc updater returned a non-success status code: #{res.statusCode}"
  108. callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
  109. setDocument : (project_id, doc_id, user_id, docLines, source, callback = (error) ->)->
  110. timer = new metrics.Timer("set-document")
  111. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}"
  112. body =
  113. url: url
  114. json:
  115. lines: docLines
  116. source: source
  117. user_id: user_id
  118. logger.log project_id:project_id, doc_id: doc_id, source: source, user_id: user_id, "setting doc in document updater"
  119. request.post body, (error, res, body)->
  120. timer.done()
  121. if error?
  122. logger.error err:error, url:url, project_id:project_id, doc_id:doc_id, "error setting doc in doc updater"
  123. return callback(error)
  124. if res.statusCode >= 200 and res.statusCode < 300
  125. logger.log project_id: project_id, doc_id: doc_id, "set doc in document updater"
  126. return callback(null)
  127. else
  128. logger.error project_id:project_id, doc_id:doc_id, url: url, "doc updater returned a non-success status code: #{res.statusCode}"
  129. callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
  130. acceptChange: (project_id, doc_id, change_id, callback = (error) ->) ->
  131. timer = new metrics.Timer("accept-change")
  132. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}/change/#{change_id}/accept"
  133. logger.log {project_id, doc_id, change_id}, "accepting change in document updater"
  134. request.post url, (error, res, body)->
  135. timer.done()
  136. if error?
  137. logger.error {err:error, project_id, doc_id, change_id}, "error accepting change in doc updater"
  138. return callback(error)
  139. if res.statusCode >= 200 and res.statusCode < 300
  140. logger.log {project_id, doc_id, change_id}, "accepted change in document updater"
  141. return callback(null)
  142. else
  143. logger.error {project_id, doc_id, change_id}, "doc updater returned a non-success status code: #{res.statusCode}"
  144. callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
  145. deleteThread: (project_id, doc_id, thread_id, callback = (error) ->) ->
  146. timer = new metrics.Timer("delete-thread")
  147. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}/comment/#{thread_id}"
  148. logger.log {project_id, doc_id, thread_id}, "deleting comment range in document updater"
  149. request.del url, (error, res, body)->
  150. timer.done()
  151. if error?
  152. logger.error {err:error, project_id, doc_id, thread_id}, "error deleting comment range in doc updater"
  153. return callback(error)
  154. if res.statusCode >= 200 and res.statusCode < 300
  155. logger.log {project_id, doc_id, thread_id}, "deleted comment rangee in document updater"
  156. return callback(null)
  157. else
  158. logger.error {project_id, doc_id, thread_id}, "doc updater returned a non-success status code: #{res.statusCode}"
  159. callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
  160. PENDINGUPDATESKEY = "PendingUpdates"
  161. DOCLINESKEY = "doclines"
  162. DOCIDSWITHPENDINGUPDATES = "DocsWithPendingUpdates"
  163. keys =
  164. pendingUpdates : (op) -> "#{PENDINGUPDATESKEY}:#{op.doc_id}"
  165. docsWithPendingUpdates: DOCIDSWITHPENDINGUPDATES
  166. docLines : (op) -> "#{DOCLINESKEY}:#{op.doc_id}"
  167. combineProjectIdAndDocId: (project_id, doc_id) -> "#{project_id}:#{doc_id}"