ProjectHistoryRedisManager.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS101: Remove unnecessary use of Array.from
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * DS103: Rewrite code to no longer use __guard__
  12. * DS201: Simplify complex destructure assignments
  13. * DS207: Consider shorter variations of null checks
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. let ProjectHistoryRedisManager
  17. const Settings = require('@overleaf/settings')
  18. const projectHistoryKeys = __guard__(
  19. Settings.redis != null ? Settings.redis.project_history : undefined,
  20. x => x.key_schema
  21. )
  22. const rclient = require('@overleaf/redis-wrapper').createClient(
  23. Settings.redis.project_history
  24. )
  25. const logger = require('logger-sharelatex')
  26. const metrics = require('./Metrics')
  27. module.exports = ProjectHistoryRedisManager = {
  28. queueOps(project_id, ...rest) {
  29. // Record metric for ops pushed onto queue
  30. const adjustedLength = Math.max(rest.length, 1)
  31. const ops = rest.slice(0, adjustedLength - 1)
  32. const val = rest[adjustedLength - 1]
  33. const callback = val != null ? val : function (error, projectUpdateCount) {}
  34. for (const op of Array.from(ops)) {
  35. metrics.summary('redis.projectHistoryOps', op.length, { status: 'push' })
  36. }
  37. const multi = rclient.multi()
  38. // Push the ops onto the project history queue
  39. multi.rpush(
  40. projectHistoryKeys.projectHistoryOps({ project_id }),
  41. ...Array.from(ops)
  42. )
  43. // To record the age of the oldest op on the queue set a timestamp if not
  44. // already present (SETNX).
  45. multi.setnx(
  46. projectHistoryKeys.projectHistoryFirstOpTimestamp({ project_id }),
  47. Date.now()
  48. )
  49. return multi.exec(function (error, result) {
  50. if (error != null) {
  51. return callback(error)
  52. }
  53. // return the number of entries pushed onto the project history queue
  54. return callback(null, result[0])
  55. })
  56. },
  57. queueRenameEntity(
  58. project_id,
  59. projectHistoryId,
  60. entity_type,
  61. entity_id,
  62. user_id,
  63. projectUpdate,
  64. callback
  65. ) {
  66. projectUpdate = {
  67. pathname: projectUpdate.pathname,
  68. new_pathname: projectUpdate.newPathname,
  69. meta: {
  70. user_id,
  71. ts: new Date(),
  72. },
  73. version: projectUpdate.version,
  74. projectHistoryId,
  75. }
  76. projectUpdate[entity_type] = entity_id
  77. logger.debug(
  78. { project_id, projectUpdate },
  79. 'queue rename operation to project-history'
  80. )
  81. const jsonUpdate = JSON.stringify(projectUpdate)
  82. return ProjectHistoryRedisManager.queueOps(project_id, jsonUpdate, callback)
  83. },
  84. queueAddEntity(
  85. project_id,
  86. projectHistoryId,
  87. entity_type,
  88. entitiy_id,
  89. user_id,
  90. projectUpdate,
  91. callback
  92. ) {
  93. if (callback == null) {
  94. callback = function (error) {}
  95. }
  96. projectUpdate = {
  97. pathname: projectUpdate.pathname,
  98. docLines: projectUpdate.docLines,
  99. url: projectUpdate.url,
  100. meta: {
  101. user_id,
  102. ts: new Date(),
  103. },
  104. version: projectUpdate.version,
  105. projectHistoryId,
  106. }
  107. projectUpdate[entity_type] = entitiy_id
  108. logger.debug(
  109. { project_id, projectUpdate },
  110. 'queue add operation to project-history'
  111. )
  112. const jsonUpdate = JSON.stringify(projectUpdate)
  113. return ProjectHistoryRedisManager.queueOps(project_id, jsonUpdate, callback)
  114. },
  115. queueResyncProjectStructure(
  116. project_id,
  117. projectHistoryId,
  118. docs,
  119. files,
  120. callback
  121. ) {
  122. logger.debug({ project_id, docs, files }, 'queue project structure resync')
  123. const projectUpdate = {
  124. resyncProjectStructure: { docs, files },
  125. projectHistoryId,
  126. meta: {
  127. ts: new Date(),
  128. },
  129. }
  130. const jsonUpdate = JSON.stringify(projectUpdate)
  131. return ProjectHistoryRedisManager.queueOps(project_id, jsonUpdate, callback)
  132. },
  133. queueResyncDocContent(
  134. project_id,
  135. projectHistoryId,
  136. doc_id,
  137. lines,
  138. version,
  139. pathname,
  140. callback
  141. ) {
  142. logger.debug(
  143. { project_id, doc_id, lines, version, pathname },
  144. 'queue doc content resync'
  145. )
  146. const projectUpdate = {
  147. resyncDocContent: {
  148. content: lines.join('\n'),
  149. version,
  150. },
  151. projectHistoryId,
  152. path: pathname,
  153. doc: doc_id,
  154. meta: {
  155. ts: new Date(),
  156. },
  157. }
  158. const jsonUpdate = JSON.stringify(projectUpdate)
  159. return ProjectHistoryRedisManager.queueOps(project_id, jsonUpdate, callback)
  160. },
  161. }
  162. function __guard__(value, transform) {
  163. return typeof value !== 'undefined' && value !== null
  164. ? transform(value)
  165. : undefined
  166. }