mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
Merge pull request #5355 from overleaf/em-stack-overflow
Avoid stack overflow with synchronous jobs in ProjectZipStreamManager GitOrigin-RevId: b7e948b98c675527a8417247a840ab27690c1027
This commit is contained in:
@@ -1,17 +1,3 @@
|
|||||||
/* eslint-disable
|
|
||||||
camelcase,
|
|
||||||
node/handle-callback-err,
|
|
||||||
max-len,
|
|
||||||
*/
|
|
||||||
// TODO: This file was created by bulk-decaffeinate.
|
|
||||||
// Fix any style issues and re-enable lint.
|
|
||||||
/*
|
|
||||||
* decaffeinate suggestions:
|
|
||||||
* DS101: Remove unnecessary use of Array.from
|
|
||||||
* DS102: Remove unnecessary code created because of implicit returns
|
|
||||||
* DS207: Consider shorter variations of null checks
|
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
||||||
*/
|
|
||||||
let ProjectZipStreamManager
|
let ProjectZipStreamManager
|
||||||
const archiver = require('archiver')
|
const archiver = require('archiver')
|
||||||
const async = require('async')
|
const async = require('async')
|
||||||
@@ -21,162 +7,124 @@ const ProjectGetter = require('../Project/ProjectGetter')
|
|||||||
const FileStoreHandler = require('../FileStore/FileStoreHandler')
|
const FileStoreHandler = require('../FileStore/FileStoreHandler')
|
||||||
|
|
||||||
module.exports = ProjectZipStreamManager = {
|
module.exports = ProjectZipStreamManager = {
|
||||||
createZipStreamForMultipleProjects(project_ids, callback) {
|
createZipStreamForMultipleProjects(projectIds, callback) {
|
||||||
// We'll build up a zip file that contains multiple zip files
|
// We'll build up a zip file that contains multiple zip files
|
||||||
|
|
||||||
if (callback == null) {
|
|
||||||
callback = function (error, stream) {}
|
|
||||||
}
|
|
||||||
const archive = archiver('zip')
|
const archive = archiver('zip')
|
||||||
archive.on('error', err =>
|
archive.on('error', err =>
|
||||||
logger.err(
|
logger.err(
|
||||||
{ err, project_ids },
|
{ err, projectIds },
|
||||||
'something went wrong building archive of project'
|
'something went wrong building archive of project'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
callback(null, archive)
|
callback(null, archive)
|
||||||
|
|
||||||
const jobs = []
|
const jobs = projectIds.map(projectId => cb => {
|
||||||
for (const project_id of Array.from(project_ids || [])) {
|
ProjectGetter.getProject(projectId, { name: true }, (error, project) => {
|
||||||
;(project_id =>
|
if (error) {
|
||||||
jobs.push(callback =>
|
return cb(error)
|
||||||
ProjectGetter.getProject(
|
}
|
||||||
project_id,
|
logger.log(
|
||||||
{ name: true },
|
{ projectId, name: project.name },
|
||||||
function (error, project) {
|
'appending project to zip stream'
|
||||||
if (error != null) {
|
)
|
||||||
return callback(error)
|
ProjectZipStreamManager.createZipStreamForProject(
|
||||||
}
|
projectId,
|
||||||
logger.log(
|
(error, stream) => {
|
||||||
{ project_id, name: project.name },
|
if (error) {
|
||||||
'appending project to zip stream'
|
return cb(error)
|
||||||
)
|
|
||||||
return ProjectZipStreamManager.createZipStreamForProject(
|
|
||||||
project_id,
|
|
||||||
function (error, stream) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
archive.append(stream, { name: `${project.name}.zip` })
|
|
||||||
return stream.on('end', function () {
|
|
||||||
logger.log(
|
|
||||||
{ project_id, name: project.name },
|
|
||||||
'zip stream ended'
|
|
||||||
)
|
|
||||||
return callback()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
archive.append(stream, { name: `${project.name}.zip` })
|
||||||
))(project_id)
|
stream.on('end', () => {
|
||||||
}
|
logger.log({ projectId, name: project.name }, 'zip stream ended')
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return async.series(jobs, function () {
|
async.series(jobs, () => {
|
||||||
logger.log(
|
logger.log(
|
||||||
{ project_ids },
|
{ projectIds },
|
||||||
'finished creating zip stream of multiple projects'
|
'finished creating zip stream of multiple projects'
|
||||||
)
|
)
|
||||||
return archive.finalize()
|
archive.finalize()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
createZipStreamForProject(project_id, callback) {
|
createZipStreamForProject(projectId, callback) {
|
||||||
if (callback == null) {
|
|
||||||
callback = function (error, stream) {}
|
|
||||||
}
|
|
||||||
const archive = archiver('zip')
|
const archive = archiver('zip')
|
||||||
// return stream immediately before we start adding things to it
|
// return stream immediately before we start adding things to it
|
||||||
archive.on('error', err =>
|
archive.on('error', err =>
|
||||||
logger.err(
|
logger.err(
|
||||||
{ err, project_id },
|
{ err, projectId },
|
||||||
'something went wrong building archive of project'
|
'something went wrong building archive of project'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
callback(null, archive)
|
callback(null, archive)
|
||||||
return this.addAllDocsToArchive(project_id, archive, error => {
|
this.addAllDocsToArchive(projectId, archive, error => {
|
||||||
if (error != null) {
|
if (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
{ err: error, project_id },
|
{ err: error, projectId },
|
||||||
'error adding docs to zip stream'
|
'error adding docs to zip stream'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return this.addAllFilesToArchive(project_id, archive, error => {
|
this.addAllFilesToArchive(projectId, archive, error => {
|
||||||
if (error != null) {
|
if (error) {
|
||||||
logger.error(
|
logger.error(
|
||||||
{ err: error, project_id },
|
{ err: error, projectId },
|
||||||
'error adding files to zip stream'
|
'error adding files to zip stream'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return archive.finalize()
|
archive.finalize()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
addAllDocsToArchive(project_id, archive, callback) {
|
addAllDocsToArchive(projectId, archive, callback) {
|
||||||
if (callback == null) {
|
ProjectEntityHandler.getAllDocs(projectId, (error, docs) => {
|
||||||
callback = function (error) {}
|
if (error) {
|
||||||
}
|
|
||||||
return ProjectEntityHandler.getAllDocs(project_id, function (error, docs) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
return callback(error)
|
||||||
}
|
}
|
||||||
const jobs = []
|
const jobs = Object.entries(docs).map(([path, doc]) => cb => {
|
||||||
for (const path in docs) {
|
if (path[0] === '/') {
|
||||||
const doc = docs[path]
|
path = path.slice(1)
|
||||||
;(function (path, doc) {
|
}
|
||||||
if (path[0] === '/') {
|
logger.log({ projectId }, 'Adding doc')
|
||||||
path = path.slice(1)
|
archive.append(doc.lines.join('\n'), { name: path })
|
||||||
}
|
setImmediate(cb)
|
||||||
return jobs.push(function (callback) {
|
})
|
||||||
logger.log({ project_id }, 'Adding doc')
|
async.series(jobs, callback)
|
||||||
archive.append(doc.lines.join('\n'), { name: path })
|
|
||||||
return callback()
|
|
||||||
})
|
|
||||||
})(path, doc)
|
|
||||||
}
|
|
||||||
return async.series(jobs, callback)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
addAllFilesToArchive(project_id, archive, callback) {
|
addAllFilesToArchive(projectId, archive, callback) {
|
||||||
if (callback == null) {
|
ProjectEntityHandler.getAllFiles(projectId, (error, files) => {
|
||||||
callback = function (error) {}
|
if (error) {
|
||||||
}
|
return callback(error)
|
||||||
return ProjectEntityHandler.getAllFiles(
|
|
||||||
project_id,
|
|
||||||
function (error, files) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
const jobs = []
|
|
||||||
for (const path in files) {
|
|
||||||
const file = files[path]
|
|
||||||
;((path, file) =>
|
|
||||||
jobs.push(callback =>
|
|
||||||
FileStoreHandler.getFileStream(
|
|
||||||
project_id,
|
|
||||||
file._id,
|
|
||||||
{},
|
|
||||||
function (error, stream) {
|
|
||||||
if (error != null) {
|
|
||||||
logger.warn(
|
|
||||||
{ err: error, project_id, file_id: file._id },
|
|
||||||
'something went wrong adding file to zip archive'
|
|
||||||
)
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
if (path[0] === '/') {
|
|
||||||
path = path.slice(1)
|
|
||||||
}
|
|
||||||
archive.append(stream, { name: path })
|
|
||||||
return stream.on('end', () => callback())
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))(path, file)
|
|
||||||
}
|
|
||||||
return async.parallelLimit(jobs, 5, callback)
|
|
||||||
}
|
}
|
||||||
)
|
const jobs = Object.entries(files).map(([path, file]) => cb => {
|
||||||
|
FileStoreHandler.getFileStream(
|
||||||
|
projectId,
|
||||||
|
file._id,
|
||||||
|
{},
|
||||||
|
(error, stream) => {
|
||||||
|
if (error) {
|
||||||
|
logger.warn(
|
||||||
|
{ err: error, projectId, file_id: file._id },
|
||||||
|
'something went wrong adding file to zip archive'
|
||||||
|
)
|
||||||
|
return cb(error)
|
||||||
|
}
|
||||||
|
if (path[0] === '/') {
|
||||||
|
path = path.slice(1)
|
||||||
|
}
|
||||||
|
archive.append(stream, { name: path })
|
||||||
|
stream.on('end', () => cb())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
async.parallelLimit(jobs, 5, callback)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user