From 23e619e4cb6925a13078de69c4675694e881fd89 Mon Sep 17 00:00:00 2001 From: subnub Date: Tue, 5 Nov 2024 22:41:55 -0500 Subject: [PATCH] improved zip downloads --- backend/controllers/folder-controller.ts | 2 - backend/express-routers/folder-router.ts | 8 +- .../middleware/folders/folder-middleware.ts | 12 ++ .../services/chunk-service/chunk-service.ts | 106 ++++++++---------- 4 files changed, 68 insertions(+), 60 deletions(-) diff --git a/backend/controllers/folder-controller.ts b/backend/controllers/folder-controller.ts index e9feadf..b025b6e 100644 --- a/backend/controllers/folder-controller.ts +++ b/backend/controllers/folder-controller.ts @@ -219,8 +219,6 @@ class FolderController { const folderIDs = (req.query.folderIDs as string[]) || []; const fileIDs = (req.query.fileIDs as string[]) || []; - console.log("folderIDs", folderIDs); - const { archive } = await chunkService.downloadZip( userID, folderIDs, diff --git a/backend/express-routers/folder-router.ts b/backend/express-routers/folder-router.ts index b6d71ad..41b6b34 100644 --- a/backend/express-routers/folder-router.ts +++ b/backend/express-routers/folder-router.ts @@ -4,6 +4,7 @@ import FolderController from "../controllers/folder-controller"; import { createFolderValidationRules, deleteFolderValidationRules, + downloadZipValidationRules, getFolderInfoValidationRules, getFolderListValidationRules, moveFolderListValidationRules, @@ -39,7 +40,12 @@ router.get( folderController.getMoveFolderList ); -router.get("/folder-service/download-zip", auth, folderController.downloadZip); +router.get( + "/folder-service/download-zip", + auth, + downloadZipValidationRules, + folderController.downloadZip +); // PATCH diff --git a/backend/middleware/folders/folder-middleware.ts b/backend/middleware/folders/folder-middleware.ts index 427e1ab..1281a39 100644 --- a/backend/middleware/folders/folder-middleware.ts +++ b/backend/middleware/folders/folder-middleware.ts @@ -30,6 +30,18 @@ export const getFolderListValidationRules = [ middlewareValidationFunction, ]; +export const downloadZipValidationRules = [ + query("folderIDs") + .optional() + .isArray() + .withMessage("FolderIDs must be an array of strings"), + query("fileIDs") + .optional() + .isArray() + .withMessage("FileIDs must be an array of strings"), + middlewareValidationFunction, +]; + // PATCH export const renameFolderValidationRules = [ diff --git a/backend/services/chunk-service/chunk-service.ts b/backend/services/chunk-service/chunk-service.ts index c9718eb..6a17231 100644 --- a/backend/services/chunk-service/chunk-service.ts +++ b/backend/services/chunk-service/chunk-service.ts @@ -177,6 +177,49 @@ class StorageService { const parentInfoMap = new Map(); const previouslyUsedFileNames = new Map(); + const getParentInfo = async (parentID: string) => { + if (parentInfoMap.has(parentID)) { + return parentInfoMap.get(parentID)!; + } + + const parentFolder = await folderDB.getFolderInfo(parentID, userID); + + if (!parentFolder) { + throw new NotFoundError("Parent Folder Not Found Error"); + } + + parentInfoMap.set(parentID, { + name: parentFolder.name, + }); + + return parentInfoMap.get(parentID)!; + }; + + const getFileName = (file: FileInterface, parentID: string) => { + const key = `${parentID}/${file.filename}`; + + if (!previouslyUsedFileNames.has(key)) { + previouslyUsedFileNames.set(key, 1); + return file.filename; + } else { + const counter = previouslyUsedFileNames.get(key)!; + const extensionSplit = file.filename.split("."); + const extension = extensionSplit[extensionSplit.length - 1]; + + const filenameWithoutExtension = extensionSplit.slice(0, -1).join("."); + + previouslyUsedFileNames.set(key, +counter + 1); + + return `${filenameWithoutExtension}-${counter}${ + extension ? `.${extension}` : "" + }`; + } + }; + + const formatName = (name: string) => { + return name.replace(/[/\\?%*:|"<>]/g, "-").trim(); + }; + for (const folderID of folderIDs) { const folder = await folderDB.getFolderInfo(folderID, userID); @@ -204,50 +247,14 @@ class StorageService { for (const parent of parentSplit) { if (parent === "/") continue; - if (!parentInfoMap.has(parent)) { - const parentFolder = await folderDB.getFolderInfo(parent, userID); - if (!parentFolder) - throw new NotFoundError("Parent Folder Not Found Error"); - parentInfoMap.set(parent, { - name: parentFolder.name, - }); + const parentInfo = await getParentInfo(parent); - directory += parentFolder.name + "/"; - } else { - const savedName = parentInfoMap.get(parent)!.name; - directory += savedName + "/"; - } + directory += formatName(parentInfo.name) + "/"; } - if ( - previouslyUsedFileNames.has( - `${file.metadata.parent}/${file.filename}` - ) - ) { - const counter = previouslyUsedFileNames.get( - `${file.metadata.parent}/${file.filename}` - )!; - const extensionSplit = file.filename.split("."); - const extension = extensionSplit[extensionSplit.length - 1]; + const fileName = formatName(getFileName(file, file.metadata.parent)); - const filenameWithoutExtension = extensionSplit - .slice(0, -1) - .join("."); - - directory += `${filenameWithoutExtension}-${counter}${ - extension ? `.${extension}` : "" - }`; - previouslyUsedFileNames.set( - `${file.metadata.parent}/${file.filename}`, - +counter + 1 - ); - } else { - directory += file.filename; - previouslyUsedFileNames.set( - `${file.metadata.parent}/${file.filename}`, - 1 - ); - } + directory += fileName; const IV = file.metadata.IV; @@ -302,24 +309,9 @@ class StorageService { console.log("decipher stream error", e); }); - if (previouslyUsedFileNames.has(file.filename)) { - const counter = previouslyUsedFileNames.get(file.filename)!; - const extensionSplit = file.filename.split("."); - const extension = extensionSplit[extensionSplit.length - 1]; + const fileName = formatName(getFileName(file, "/")); - const filenameWithoutExtension = extensionSplit.slice(0, -1).join("."); - - archive.append(readStream.pipe(decipher), { - name: `${filenameWithoutExtension}-${counter}${ - extension ? `.${extension}` : "" - }`, - }); - - previouslyUsedFileNames.set(file.filename, +counter + 1); - } else { - archive.append(readStream.pipe(decipher), { name: file.filename }); - previouslyUsedFileNames.set(file.filename, 1); - } + archive.append(readStream.pipe(decipher), { name: fileName }); } archive.finalize();