2019-05-29 05:21:06 -04:00
|
|
|
let ProjectZipStreamManager
|
|
|
|
const archiver = require('archiver')
|
|
|
|
const async = require('async')
|
2021-11-10 08:40:18 -05:00
|
|
|
const logger = require('@overleaf/logger')
|
2019-05-29 05:21:06 -04:00
|
|
|
const ProjectEntityHandler = require('../Project/ProjectEntityHandler')
|
|
|
|
const ProjectGetter = require('../Project/ProjectGetter')
|
|
|
|
const FileStoreHandler = require('../FileStore/FileStoreHandler')
|
|
|
|
|
|
|
|
module.exports = ProjectZipStreamManager = {
|
2021-10-06 08:26:25 -04:00
|
|
|
createZipStreamForMultipleProjects(projectIds, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
// We'll build up a zip file that contains multiple zip files
|
|
|
|
const archive = archiver('zip')
|
|
|
|
archive.on('error', err =>
|
|
|
|
logger.err(
|
2021-10-06 08:26:25 -04:00
|
|
|
{ err, projectIds },
|
2019-05-29 05:21:06 -04:00
|
|
|
'something went wrong building archive of project'
|
|
|
|
)
|
|
|
|
)
|
|
|
|
callback(null, archive)
|
|
|
|
|
2021-10-06 08:26:25 -04:00
|
|
|
const jobs = projectIds.map(projectId => cb => {
|
|
|
|
ProjectGetter.getProject(projectId, { name: true }, (error, project) => {
|
|
|
|
if (error) {
|
|
|
|
return cb(error)
|
|
|
|
}
|
2021-11-16 05:29:16 -05:00
|
|
|
if (!project) {
|
|
|
|
logger.log(
|
|
|
|
{ projectId },
|
|
|
|
'cannot append project to zip stream: project not found'
|
|
|
|
)
|
|
|
|
return cb()
|
|
|
|
}
|
2021-10-06 08:26:25 -04:00
|
|
|
logger.log(
|
|
|
|
{ projectId, name: project.name },
|
|
|
|
'appending project to zip stream'
|
|
|
|
)
|
|
|
|
ProjectZipStreamManager.createZipStreamForProject(
|
|
|
|
projectId,
|
|
|
|
(error, stream) => {
|
|
|
|
if (error) {
|
|
|
|
return cb(error)
|
2021-04-14 09:17:21 -04:00
|
|
|
}
|
2021-10-06 08:26:25 -04:00
|
|
|
archive.append(stream, { name: `${project.name}.zip` })
|
|
|
|
stream.on('end', () => {
|
|
|
|
logger.log({ projectId, name: project.name }, 'zip stream ended')
|
|
|
|
cb()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-10-06 08:26:25 -04:00
|
|
|
async.series(jobs, () => {
|
2019-05-29 05:21:06 -04:00
|
|
|
logger.log(
|
2021-10-06 08:26:25 -04:00
|
|
|
{ projectIds },
|
2019-05-29 05:21:06 -04:00
|
|
|
'finished creating zip stream of multiple projects'
|
|
|
|
)
|
2021-10-06 08:26:25 -04:00
|
|
|
archive.finalize()
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2021-10-06 08:26:25 -04:00
|
|
|
createZipStreamForProject(projectId, callback) {
|
2019-05-29 05:21:06 -04:00
|
|
|
const archive = archiver('zip')
|
|
|
|
// return stream immediately before we start adding things to it
|
|
|
|
archive.on('error', err =>
|
|
|
|
logger.err(
|
2021-10-06 08:26:25 -04:00
|
|
|
{ err, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'something went wrong building archive of project'
|
|
|
|
)
|
|
|
|
)
|
|
|
|
callback(null, archive)
|
2021-10-06 08:26:25 -04:00
|
|
|
this.addAllDocsToArchive(projectId, archive, error => {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
logger.error(
|
2021-10-06 08:26:25 -04:00
|
|
|
{ err: error, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'error adding docs to zip stream'
|
|
|
|
)
|
|
|
|
}
|
2021-10-06 08:26:25 -04:00
|
|
|
this.addAllFilesToArchive(projectId, archive, error => {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
logger.error(
|
2021-10-06 08:26:25 -04:00
|
|
|
{ err: error, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'error adding files to zip stream'
|
|
|
|
)
|
|
|
|
}
|
2021-10-06 08:26:25 -04:00
|
|
|
archive.finalize()
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2021-10-06 08:26:25 -04:00
|
|
|
addAllDocsToArchive(projectId, archive, callback) {
|
|
|
|
ProjectEntityHandler.getAllDocs(projectId, (error, docs) => {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
2021-10-06 08:26:25 -04:00
|
|
|
const jobs = Object.entries(docs).map(([path, doc]) => cb => {
|
|
|
|
if (path[0] === '/') {
|
|
|
|
path = path.slice(1)
|
|
|
|
}
|
|
|
|
logger.log({ projectId }, 'Adding doc')
|
|
|
|
archive.append(doc.lines.join('\n'), { name: path })
|
|
|
|
setImmediate(cb)
|
|
|
|
})
|
|
|
|
async.series(jobs, callback)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2021-10-06 08:26:25 -04:00
|
|
|
addAllFilesToArchive(projectId, archive, callback) {
|
|
|
|
ProjectEntityHandler.getAllFiles(projectId, (error, files) => {
|
|
|
|
if (error) {
|
|
|
|
return callback(error)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-10-06 08:26:25 -04:00
|
|
|
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)
|
|
|
|
})
|
2021-04-27 03:52:58 -04:00
|
|
|
},
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|