ProjectZipStreamManager.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /* eslint-disable
  2. camelcase,
  3. node/handle-callback-err,
  4. max-len,
  5. no-undef,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS101: Remove unnecessary use of Array.from
  12. * DS102: Remove unnecessary code created because of implicit returns
  13. * DS207: Consider shorter variations of null checks
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. let ProjectZipStreamManager
  17. const archiver = require('archiver')
  18. const async = require('async')
  19. const logger = require('logger-sharelatex')
  20. const ProjectEntityHandler = require('../Project/ProjectEntityHandler')
  21. const ProjectGetter = require('../Project/ProjectGetter')
  22. const FileStoreHandler = require('../FileStore/FileStoreHandler')
  23. module.exports = ProjectZipStreamManager = {
  24. createZipStreamForMultipleProjects(project_ids, callback) {
  25. // We'll build up a zip file that contains multiple zip files
  26. if (callback == null) {
  27. callback = function (error, stream) {}
  28. }
  29. const archive = archiver('zip')
  30. archive.on('error', err =>
  31. logger.err(
  32. { err, project_ids },
  33. 'something went wrong building archive of project'
  34. )
  35. )
  36. callback(null, archive)
  37. const jobs = []
  38. for (const project_id of Array.from(project_ids || [])) {
  39. ;(project_id =>
  40. jobs.push(callback =>
  41. ProjectGetter.getProject(
  42. project_id,
  43. { name: true },
  44. function (error, project) {
  45. if (error != null) {
  46. return callback(error)
  47. }
  48. logger.log(
  49. { project_id, name: project.name },
  50. 'appending project to zip stream'
  51. )
  52. return ProjectZipStreamManager.createZipStreamForProject(
  53. project_id,
  54. function (error, stream) {
  55. if (error != null) {
  56. return callback(error)
  57. }
  58. archive.append(stream, { name: `${project.name}.zip` })
  59. return stream.on('end', function () {
  60. logger.log(
  61. { project_id, name: project.name },
  62. 'zip stream ended'
  63. )
  64. return callback()
  65. })
  66. }
  67. )
  68. }
  69. )
  70. ))(project_id)
  71. }
  72. return async.series(jobs, function () {
  73. logger.log(
  74. { project_ids },
  75. 'finished creating zip stream of multiple projects'
  76. )
  77. return archive.finalize()
  78. })
  79. },
  80. createZipStreamForProject(project_id, callback) {
  81. if (callback == null) {
  82. callback = function (error, stream) {}
  83. }
  84. const archive = archiver('zip')
  85. // return stream immediately before we start adding things to it
  86. archive.on('error', err =>
  87. logger.err(
  88. { err, project_id },
  89. 'something went wrong building archive of project'
  90. )
  91. )
  92. callback(null, archive)
  93. return this.addAllDocsToArchive(project_id, archive, error => {
  94. if (error != null) {
  95. logger.error(
  96. { err: error, project_id },
  97. 'error adding docs to zip stream'
  98. )
  99. }
  100. return this.addAllFilesToArchive(project_id, archive, error => {
  101. if (error != null) {
  102. logger.error(
  103. { err: error, project_id },
  104. 'error adding files to zip stream'
  105. )
  106. }
  107. return archive.finalize()
  108. })
  109. })
  110. },
  111. addAllDocsToArchive(project_id, archive, callback) {
  112. if (callback == null) {
  113. callback = function (error) {}
  114. }
  115. return ProjectEntityHandler.getAllDocs(project_id, function (error, docs) {
  116. if (error != null) {
  117. return callback(error)
  118. }
  119. const jobs = []
  120. for (const path in docs) {
  121. const doc = docs[path]
  122. ;(function (path, doc) {
  123. if (path[0] === '/') {
  124. path = path.slice(1)
  125. }
  126. return jobs.push(function (callback) {
  127. logger.log({ project_id }, 'Adding doc')
  128. archive.append(doc.lines.join('\n'), { name: path })
  129. return callback()
  130. })
  131. })(path, doc)
  132. }
  133. return async.series(jobs, callback)
  134. })
  135. },
  136. addAllFilesToArchive(project_id, archive, callback) {
  137. if (callback == null) {
  138. callback = function (error) {}
  139. }
  140. return ProjectEntityHandler.getAllFiles(
  141. project_id,
  142. function (error, files) {
  143. if (error != null) {
  144. return callback(error)
  145. }
  146. const jobs = []
  147. for (const path in files) {
  148. const file = files[path]
  149. ;((path, file) =>
  150. jobs.push(callback =>
  151. FileStoreHandler.getFileStream(
  152. project_id,
  153. file._id,
  154. {},
  155. function (error, stream) {
  156. if (error != null) {
  157. logger.warn(
  158. { err: error, project_id, file_id: file._id },
  159. 'something went wrong adding file to zip archive'
  160. )
  161. return callback(err)
  162. }
  163. if (path[0] === '/') {
  164. path = path.slice(1)
  165. }
  166. archive.append(stream, { name: path })
  167. return stream.on('end', () => callback())
  168. }
  169. )
  170. ))(path, file)
  171. }
  172. return async.parallelLimit(jobs, 5, callback)
  173. }
  174. )
  175. },
  176. }