diff --git a/server/queues/tasks/ExportDocumentTreeTask.ts b/server/queues/tasks/ExportDocumentTreeTask.ts index 5bc018963..556bee033 100644 --- a/server/queues/tasks/ExportDocumentTreeTask.ts +++ b/server/queues/tasks/ExportDocumentTreeTask.ts @@ -34,6 +34,7 @@ export default abstract class ExportDocumentTreeTask extends ExportTask { format: FileOperationFormat; pathMap: Map; }) { + Logger.debug("task", `Adding document to archive`, { documentId }); const document = await Document.findByPk(documentId); if (!document) { return; @@ -43,18 +44,27 @@ export default abstract class ExportDocumentTreeTask extends ExportTask { format === FileOperationFormat.HTMLZip ? await DocumentHelper.toHTML(document, { centered: true }) : await DocumentHelper.toMarkdown(document); - const attachments = await Attachment.findAll({ - where: { - teamId: document.teamId, - id: parseAttachmentIds(document.text), - }, - }); + + const attachmentIds = parseAttachmentIds(document.text); + const attachments = attachmentIds.length + ? await Attachment.findAll({ + where: { + teamId: document.teamId, + id: attachmentIds, + }, + }) + : []; // Add any referenced attachments to the zip file and replace the // reference in the document with the path to the attachment in the zip await Promise.all( attachments.map(async (attachment) => { try { + Logger.debug("task", `Adding attachment to archive`, { + documentId, + key: attachment.key, + }); + const stream = getFileByKey(attachment.key); const dir = path.dirname(pathInZip); if (stream) { @@ -119,6 +129,10 @@ export default abstract class ExportDocumentTreeTask extends ExportTask { format: FileOperationFormat ) { const pathMap = this.createPathMap(collections, format); + Logger.debug( + "task", + `Start adding ${Object.values(pathMap).length} documents to archive` + ); for (const path of pathMap) { const documentId = path[0].replace("/doc/", ""); @@ -133,7 +147,9 @@ export default abstract class ExportDocumentTreeTask extends ExportTask { }); } - return ZipHelper.toTmpFile(zip); + Logger.debug("task", "Completed adding documents to archive"); + + return await ZipHelper.toTmpFile(zip); } /** diff --git a/server/utils/ZipHelper.ts b/server/utils/ZipHelper.ts index f8bf3e95d..e516cf939 100644 --- a/server/utils/ZipHelper.ts +++ b/server/utils/ZipHelper.ts @@ -4,6 +4,7 @@ import JSZip from "jszip"; import { find } from "lodash"; import tmp from "tmp"; import { ValidationError } from "@server/errors"; +import Logger from "@server/logging/Logger"; import { trace } from "@server/logging/tracing"; import { deserializeFilename } from "./fs"; @@ -83,6 +84,7 @@ export default class ZipHelper { * @returns pathname of the temporary file where the zip was written to disk */ public static async toTmpFile(zip: JSZip): Promise { + Logger.debug("utils", "Creating tmp file…"); return new Promise((resolve, reject) => { tmp.file( { @@ -93,13 +95,38 @@ export default class ZipHelper { if (err) { return reject(err); } + + let previousMetadata: JSZip.JSZipMetadata = { + percent: 0, + currentFile: null, + }; + zip - .generateNodeStream({ - type: "nodebuffer", - streamFiles: true, - }) + .generateNodeStream( + { + type: "nodebuffer", + streamFiles: true, + }, + (metadata) => { + const percent = Math.round(metadata.percent); + if (percent !== previousMetadata.percent) { + previousMetadata = { + currentFile: metadata.currentFile, + percent, + }; + Logger.debug( + "utils", + `Writing zip file progress… %${percent}`, + { currentFile: metadata.currentFile } + ); + } + } + ) .pipe(fs.createWriteStream(path)) - .on("finish", () => resolve(path)) + .on("finish", () => { + Logger.debug("utils", "Writing zip complete", { path }); + return resolve(path); + }) .on("error", reject); } );