ProjectHistoryRedisManager.js 4.5 KB

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