DocumentUpdaterHandler.coffee 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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. slReqIdHelper = require('soa-req-id')
  10. redis = require('redis')
  11. rclient = redis.createClient(settings.redis.web.port, settings.redis.web.host)
  12. rclient.auth(settings.redis.web.password)
  13. Project = require("../../models/Project").Project
  14. ProjectLocator = require('../../Features/Project/ProjectLocator')
  15. module.exports =
  16. queueChange : (project_id, doc_id, change, sl_req_id, callback = ()->)->
  17. {callback, sl_req_id} = slReqIdHelper.getCallbackAndReqId(callback, sl_req_id)
  18. jsonChange = JSON.stringify change
  19. rclient.rpush keys.pendingUpdates(doc_id:doc_id), jsonChange, (error)->
  20. return callback(error) if error?
  21. doc_key = keys.combineProjectIdAndDocId(project_id, doc_id)
  22. rclient.sadd keys.docsWithPendingUpdates, doc_key, (error) ->
  23. return callback(error) if error?
  24. rclient.publish "pending-updates", doc_key, callback
  25. flushProjectToMongo: (project_id, sl_req_id, callback = (error) ->)->
  26. {callback, sl_req_id} = slReqIdHelper.getCallbackAndReqId(callback, sl_req_id)
  27. logger.log project_id:project_id, sl_req_id:sl_req_id, "flushing project from document updater"
  28. timer = new metrics.Timer("flushing.mongo.project")
  29. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/flush"
  30. request.post url, (error, res, body)->
  31. if error?
  32. logger.error err: error, project_id: project_id, sl_req_id: sl_req_id, "error flushing project from document updater"
  33. return callback(error)
  34. else if res.statusCode >= 200 and res.statusCode < 300
  35. logger.log project_id: project_id, sl_req_id: sl_req_id, "flushed project from document updater"
  36. return callback(null)
  37. else
  38. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  39. logger.error err: error, project_id: project_id, sl_req_id: sl_req_id, "document updater returned failure status code: #{res.statusCode}"
  40. return callback(error)
  41. flushProjectToMongoAndDelete: (project_id, sl_req_id, callback = ()->) ->
  42. {callback, sl_req_id} = slReqIdHelper.getCallbackAndReqId(callback, sl_req_id)
  43. logger.log project_id:project_id, sl_req_id:sl_req_id, "deleting project from document updater"
  44. timer = new metrics.Timer("delete.mongo.project")
  45. url = "#{settings.apis.documentupdater.url}/project/#{project_id}"
  46. request.del url, (error, res, body)->
  47. if error?
  48. logger.error err: error, project_id: project_id, sl_req_id: sl_req_id, "error deleting project from document updater"
  49. return callback(error)
  50. else if res.statusCode >= 200 and res.statusCode < 300
  51. logger.log project_id: project_id, sl_req_id: sl_req_id, "deleted project from document updater"
  52. return callback(null)
  53. else
  54. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  55. logger.error err: error, project_id: project_id, sl_req_id: sl_req_id, "document updater returned failure status code: #{res.statusCode}"
  56. return callback(error)
  57. flushDocToMongo: (project_id, doc_id, callback = (error) ->) ->
  58. logger.log project_id:project_id, doc_id: doc_id, "flushing doc from document updater"
  59. timer = new metrics.Timer("flushing.mongo.doc")
  60. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}/flush"
  61. request.post url, (error, res, body)->
  62. if error?
  63. logger.error err: error, project_id: project_id, doc_id: doc_id, "error flushing doc from document updater"
  64. return callback(error)
  65. else if res.statusCode >= 200 and res.statusCode < 300
  66. logger.log project_id: project_id, doc_id: doc_id, "flushed doc from document updater"
  67. return callback(null)
  68. else
  69. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  70. logger.error err: error, project_id: project_id, doc_id: doc_id, "document updater returned failure status code: #{res.statusCode}"
  71. return callback(error)
  72. deleteDoc : (project_id, doc_id, sl_req_id, callback = ()->)->
  73. {callback, sl_req_id} = slReqIdHelper.getCallbackAndReqId(callback, sl_req_id)
  74. logger.log project_id:project_id, doc_id: doc_id, sl_req_id:sl_req_id, "deleting doc from document updater"
  75. timer = new metrics.Timer("delete.mongo.doc")
  76. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}"
  77. request.del url, (error, res, body)->
  78. if error?
  79. logger.error err: error, project_id: project_id, doc_id: doc_id, sl_req_id: sl_req_id, "error deleting doc from document updater"
  80. return callback(error)
  81. else if res.statusCode >= 200 and res.statusCode < 300
  82. logger.log project_id: project_id, doc_id: doc_id, sl_req_id: sl_req_id, "deleted doc from document updater"
  83. return callback(null)
  84. else
  85. error = new Error("document updater returned a failure status code: #{res.statusCode}")
  86. logger.error err: error, project_id: project_id, doc_id: doc_id, sl_req_id: sl_req_id, "document updater returned failure status code: #{res.statusCode}"
  87. return callback(error)
  88. getDocument: (project_id, doc_id, fromVersion, sl_req_id, callback = (error, exists, doclines, version) ->) ->
  89. {callback, sl_req_id} = slReqIdHelper.getCallbackAndReqId(callback, sl_req_id)
  90. timer = new metrics.Timer("get-document")
  91. url = "#{settings.apis.documentupdater.url}/project/#{project_id}/doc/#{doc_id}?fromVersion=#{fromVersion}"
  92. logger.log project_id:project_id, doc_id: doc_id, sl_req_id:sl_req_id, "getting doc from document updater"
  93. request.get url, (error, res, body)->
  94. timer.done()
  95. if error?
  96. logger.error err:error, url:url, project_id:project_id, doc_id:doc_id, "error getting doc from doc updater"
  97. return callback(error)
  98. if res.statusCode >= 200 and res.statusCode < 300
  99. logger.log project_id:project_id, doc_id:doc_id, "got doc from document document updater"
  100. try
  101. body = JSON.parse(body)
  102. catch error
  103. return callback(error)
  104. callback null, body.lines, body.version, body.ops
  105. else
  106. logger.error project_id:project_id, doc_id:doc_id, url: url, "doc updater returned a non-success status code: #{res.statusCode}"
  107. callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
  108. setDocument : (project_id, doc_id, docLines, sl_req_id, callback = (error) ->)->
  109. {callback, sl_req_id} = slReqIdHelper.getCallbackAndReqId(callback, sl_req_id)
  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. logger.log project_id:project_id, doc_id: doc_id, sl_req_id:sl_req_id, "setting doc in document updater"
  117. request.post body, (error, res, body)->
  118. timer.done()
  119. if error?
  120. logger.error err:error, url:url, project_id:project_id, doc_id:doc_id, "error setting doc in doc updater"
  121. return callback(error)
  122. if res.statusCode >= 200 and res.statusCode < 300
  123. logger.log project_id: project_id, doc_id: doc_id, sl_req_id: sl_req_id, "set doc in document updater"
  124. return callback(null)
  125. else
  126. logger.error project_id:project_id, doc_id:doc_id, url: url, "doc updater returned a non-success status code: #{res.statusCode}"
  127. callback new Error("doc updater returned a non-success status code: #{res.statusCode}")
  128. getNumberOfDocsInMemory : (callback)->
  129. request.get "#{settings.apis.documentupdater.url}/total", (err, req, body)->
  130. try
  131. body = JSON.parse body
  132. catch err
  133. logger.err err:err, "error parsing response from doc updater about the total number of docs"
  134. callback(err, body?.total)
  135. PENDINGUPDATESKEY = "PendingUpdates"
  136. DOCLINESKEY = "doclines"
  137. DOCIDSWITHPENDINGUPDATES = "DocsWithPendingUpdates"
  138. keys =
  139. pendingUpdates : (op) -> "#{PENDINGUPDATESKEY}:#{op.doc_id}"
  140. docsWithPendingUpdates: DOCIDSWITHPENDINGUPDATES
  141. docLines : (op) -> "#{DOCLINESKEY}:#{op.doc_id}"
  142. combineProjectIdAndDocId: (project_id, doc_id) -> "#{project_id}:#{doc_id}"