DocumentUpdaterHandler.coffee 7.3 KB

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