ClsiStateManager.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. /* eslint-disable
  2. node/handle-callback-err,
  3. max-len,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS101: Remove unnecessary use of Array.from
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * DS205: Consider reworking code to avoid use of IIFEs
  13. * DS207: Consider shorter variations of null checks
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. let ClsiStateManager
  17. const Settings = require('@overleaf/settings')
  18. const logger = require('@overleaf/logger')
  19. const crypto = require('crypto')
  20. const ProjectEntityHandler = require('../Project/ProjectEntityHandler')
  21. // The "state" of a project is a hash of the relevant attributes in the
  22. // project object in this case we only need the rootFolder.
  23. //
  24. // The idea is that it will change if any doc or file is
  25. // created/renamed/deleted, and also if the content of any file (not
  26. // doc) changes.
  27. //
  28. // When the hash changes the full set of files on the CLSI will need to
  29. // be updated. If it doesn't change then we can overwrite changed docs
  30. // in place on the clsi, getting them from the docupdater.
  31. //
  32. // The docupdater is responsible for setting the key in redis, and
  33. // unsetting it if it removes any documents from the doc updater.
  34. const buildState = s =>
  35. crypto.createHash('sha1').update(s, 'utf8').digest('hex')
  36. module.exports = ClsiStateManager = {
  37. computeHash(project, options, callback) {
  38. if (callback == null) {
  39. callback = function () {}
  40. }
  41. return ProjectEntityHandler.getAllEntitiesFromProject(
  42. project,
  43. function (err, docs, files) {
  44. const fileList = Array.from(files || []).map(
  45. f => `${f.file._id}:${f.file.rev}:${f.file.created}:${f.path}`
  46. )
  47. const docList = Array.from(docs || []).map(
  48. d => `${d.doc._id}:${d.path}`
  49. )
  50. const sortedEntityList = [
  51. ...Array.from(docList),
  52. ...Array.from(fileList),
  53. ].sort()
  54. // ignore the isAutoCompile options as it doesn't affect the
  55. // output, but include all other options e.g. draft
  56. const optionsList = (() => {
  57. const result = []
  58. const object = options || {}
  59. for (const key in object) {
  60. const value = object[key]
  61. if (!['isAutoCompile'].includes(key)) {
  62. result.push(`option ${key}:${value}`)
  63. }
  64. }
  65. return result
  66. })()
  67. const sortedOptionsList = optionsList.sort()
  68. const hash = buildState(
  69. [
  70. ...Array.from(sortedEntityList),
  71. ...Array.from(sortedOptionsList),
  72. ].join('\n')
  73. )
  74. return callback(null, hash)
  75. }
  76. )
  77. },
  78. }