continued cleaning up events

This commit is contained in:
subnub
2024-12-07 20:11:29 -05:00
parent e466ec0d07
commit 0eb8bf12a0
7 changed files with 234 additions and 150 deletions
+15 -68
View File
@@ -7,14 +7,7 @@ import {
} from "../cookies/create-cookies";
import ChunkService from "../services/chunk-service/chunk-service";
import streamToBuffer from "../utils/streamToBuffer";
import env from "../enviroment/env";
import getFileSize from "../services/chunk-service/utils/getFileSize";
import File, { FileMetadateInterface } from "../models/file-model";
import imageChecker from "../utils/imageChecker";
import videoChecker from "../utils/videoChecker";
import createVideoThumbnail from "../services/chunk-service/utils/createVideoThumbnail";
import NotAuthorizedError from "../utils/NotAuthorizedError";
import createThumbnail from "../services/chunk-service/utils/createImageThumbnail";
import { FileListQueryType } from "../types/file-types";
const fileService = new FileService();
@@ -25,7 +18,7 @@ type userAccessType = {
s3Enabled: boolean;
};
interface RequestTypeFullUser extends Request {
export interface RequestTypeFullUser extends Request {
user?: UserInterface;
encryptedToken?: string;
accessTokenStreamVideo?: string;
@@ -43,47 +36,23 @@ class FileController {
this.chunkService = new ChunkService();
}
getThumbnail = async (req: RequestTypeFullUser, res: Response) => {
getThumbnail = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
let responseSent = false;
try {
const user = req.user;
const id = req.params.id;
const { readStream, decipher } = await this.chunkService.getThumbnail(
user,
id
);
readStream.on("error", (e: Error) => {
console.log("Get thumbnail read stream error", e);
if (!responseSent) {
responseSent = true;
res.status(500).send("Server error getting thumbnail");
}
});
decipher.on("error", (e: Error) => {
console.log("Get thumbnail decipher error", e);
if (!responseSent) {
responseSent = true;
res.status(500).send("Server error getting thumbnail");
}
});
const bufferData = await streamToBuffer(readStream.pipe(decipher));
const bufferData = await this.chunkService.getThumbnail(user, id);
res.send(bufferData);
} catch (e: unknown) {
if (e instanceof Error) {
console.log("\nGet Thumbnail Error File Route:", e.message);
}
if (!responseSent) {
responseSent = true;
res.status(500).send("Server error getting thumbnail");
}
next(e);
}
};
@@ -144,12 +113,6 @@ class FileController {
const user = req.user;
const busboy = req.busboy;
req.on("error", (e: Error) => {
next(e);
});
req.pipe(busboy);
const file = await this.chunkService.uploadFile(user, busboy, req);
res.send(file);
@@ -496,7 +459,11 @@ class FileController {
}
};
downloadFile = async (req: RequestTypeFullUser, res: Response) => {
downloadFile = async (
req: RequestTypeFullUser,
res: Response,
next: NextFunction
) => {
if (!req.user) {
return;
}
@@ -505,29 +472,9 @@ class FileController {
const user = req.user;
const fileID = req.params.id;
const { readStream, decipher, file } =
await this.chunkService.downloadFile(user, fileID, res);
readStream.on("error", (e: Error) => {
console.log("read stream error", e);
});
decipher.on("error", (e: Error) => {
console.log("decipher stream errozr", e);
});
res.set("Content-Type", "binary/octet-stream");
res.set(
"Content-Disposition",
'attachment; filename="' + file.filename + '"'
);
res.set("Content-Length", file.metadata.size.toString());
readStream.pipe(decipher).pipe(res);
await this.chunkService.downloadFile(user, fileID, res);
} catch (e: unknown) {
if (e instanceof Error) {
console.log("\nDownload File Error File Route:", e.message);
}
next(e);
}
};
+1 -1
View File
@@ -85,7 +85,7 @@ class FolderController {
const user = req.user;
const busboy = req.busboy;
await chunkService.uploadFolder(user, busboy, req, next);
await chunkService.uploadFolder(user, busboy, req);
res.send();
} catch (e) {
+12 -74
View File
@@ -24,6 +24,8 @@ import archiver from "archiver";
import async from "async";
import getFolderBusboyData from "./utils/getFolderUploadBusboyData";
import { getStorageActions } from "./actions/helper-actions";
import getThumbnailData from "./utils/getThumbnailData";
import getFileData from "./utils/getFileData";
const fileDB = new FileDB();
const folderDB = new FolderDB();
@@ -36,7 +38,7 @@ class StorageService {
constructor() {}
uploadFile = async (user: UserInterface, busboy: any, req: Request) => {
const { parent, file } = await uploadFileToStorage(busboy, user);
const { parent, file } = await uploadFileToStorage(busboy, user, req);
const parentList = [];
@@ -61,25 +63,12 @@ class StorageService {
return file;
};
uploadFolder = async (
user: UserInterface,
busboy: any,
req: Request,
next: NextFunction
) => {
req.on("error", (e: Error) => {
console.log("req error", e);
next(e);
});
busboy.on("error", (e: Error) => {
console.log("busboy error", e);
next(e);
});
req.pipe(busboy);
const { fileDataMap, parent } = await getFolderBusboyData(busboy, user);
uploadFolder = async (user: UserInterface, busboy: any, req: Request) => {
const { fileDataMap, parent } = await getFolderBusboyData(
busboy,
user,
req
);
const keys = Object.keys(fileDataMap);
@@ -179,32 +168,7 @@ class StorageService {
};
downloadFile = async (user: UserInterface, fileID: string, res: Response) => {
const currentFile = await fileDB.getFileInfo(fileID, user._id.toString());
if (!currentFile) throw new NotFoundError("Download File Not Found");
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const IV = currentFile.metadata.IV;
const readStreamParams = createGenericParams({
filePath: currentFile.metadata.filePath,
Key: currentFile.metadata.s3ID,
});
const readStream = storageActions.createReadStream(readStreamParams);
const CIPHER_KEY = crypto.createHash("sha256").update(password).digest();
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, IV);
return {
readStream,
decipher,
file: currentFile,
};
await getFileData(res, fileID, user);
};
downloadZip = async (
@@ -384,34 +348,8 @@ class StorageService {
};
getThumbnail = async (user: UserInterface, id: string) => {
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const thumbnail = await thumbnailDB.getThumbnailInfo(
user._id.toString(),
id
);
if (!thumbnail) throw new NotFoundError("Thumbnail Not Found");
const iv = thumbnail.IV;
const CIPHER_KEY = crypto.createHash("sha256").update(password).digest();
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, iv);
const readStreamParams = createGenericParams({
filePath: thumbnail.path,
Key: thumbnail.s3ID,
});
const readStream = storageActions.createReadStream(readStreamParams);
return {
readStream,
decipher,
};
const bufferData = await getThumbnailData(id, user);
return bufferData;
};
getFullThumbnail = async (user: UserInterface, fileID: string) => {
@@ -14,6 +14,7 @@ import imageChecker from "../../../utils/imageChecker";
import videoChecker from "../../../utils/videoChecker";
import createVideoThumbnail from "./createVideoThumbnail";
import createThumbnail from "./createImageThumbnail";
import { RequestTypeFullUser } from "../../../controllers/file-controller";
// TODO: We should stop using moongoose directly here,
// Also in our fileDB make sure we are actually using File instead
@@ -26,7 +27,11 @@ type FileInfo = {
parent: string;
};
const processData = (busboy: any, user: UserInterface) => {
const processData = (
busboy: any,
user: UserInterface,
req: RequestTypeFullUser
) => {
const eventEmitter = new EventEmitter();
try {
@@ -184,6 +189,12 @@ const processData = (busboy: any, user: UserInterface) => {
busboy.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
req.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
req.pipe(busboy);
} catch (e) {
eventEmitter.emit("error", e);
}
@@ -191,9 +202,13 @@ const processData = (busboy: any, user: UserInterface) => {
return eventEmitter;
};
const uploadFileToStorage = (busboy: any, user: UserInterface) => {
const uploadFileToStorage = (
busboy: any,
user: UserInterface,
req: RequestTypeFullUser
) => {
return new Promise<FileInfo>((resolve, reject) => {
const eventEmitter = processData(busboy, user);
const eventEmitter = processData(busboy, user, req);
eventEmitter.on("finish", (data) => {
resolve(data);
});
@@ -0,0 +1,88 @@
import { EventEmitter } from "stream";
import { UserInterface } from "../../../models/user-model";
import { Response } from "express";
import ForbiddenError from "../../../utils/ForbiddenError";
import NotFoundError from "../../../utils/NotFoundError";
import crypto from "crypto";
import { createGenericParams } from "./storageHelper";
import { getStorageActions } from "../actions/helper-actions";
import FileDB from "../../../db/mongoDB/fileDB";
const fileDB = new FileDB();
const storageActions = getStorageActions();
const proccessData = (res: Response, fileID: string, user: UserInterface) => {
const eventEmitter = new EventEmitter();
const processFile = async () => {
try {
const currentFile = await fileDB.getFileInfo(fileID, user._id.toString());
if (!currentFile) throw new NotFoundError("Download File Not Found");
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const IV = currentFile.metadata.IV;
const readStreamParams = createGenericParams({
filePath: currentFile.metadata.filePath,
Key: currentFile.metadata.s3ID,
});
const readStream = storageActions.createReadStream(readStreamParams);
const CIPHER_KEY = crypto.createHash("sha256").update(password).digest();
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, IV);
decipher.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
readStream.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
res.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
res.set("Content-Type", "binary/octet-stream");
res.set(
"Content-Disposition",
'attachment; filename="' + currentFile.filename + '"'
);
res.set("Content-Length", currentFile.metadata.size.toString());
readStream
.pipe(decipher)
.pipe(res)
.on("finish", () => {
eventEmitter.emit("finish");
});
} catch (e) {
eventEmitter.emit("error", e);
}
};
processFile();
return eventEmitter;
};
const getFileData = (res: Response, fileID: string, user: UserInterface) => {
return new Promise((resolve, reject) => {
const eventEmitter = proccessData(res, fileID, user);
eventEmitter.on("finish", (data) => {
resolve(data);
});
eventEmitter.on("error", (e) => {
reject(e);
});
});
};
export default getFileData;
@@ -17,6 +17,7 @@ import createVideoThumbnail from "./createVideoThumbnail";
import createThumbnail from "./createImageThumbnail";
import { EventEmitter } from "events";
import { getStorageActions } from "../actions/helper-actions";
import { RequestTypeFullUser } from "../../../controllers/file-controller";
type FileDataType = {
name: string;
@@ -32,7 +33,11 @@ const storageActions = getStorageActions();
type dataType = Record<string, FileDataType>;
const processData = (busboy: any, user: UserInterface) => {
const processData = (
busboy: any,
user: UserInterface,
req: RequestTypeFullUser
) => {
const eventEmitter = new EventEmitter();
try {
@@ -209,7 +214,7 @@ const processData = (busboy: any, user: UserInterface) => {
busboy.on(
"file",
async (
(
_: string,
file: Stream,
fileData: {
@@ -227,6 +232,16 @@ const processData = (busboy: any, user: UserInterface) => {
busboy.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
req.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
busboy.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
req.pipe(busboy);
} catch (e) {
eventEmitter.emit("error", e);
}
@@ -234,10 +249,14 @@ const processData = (busboy: any, user: UserInterface) => {
return eventEmitter;
};
const getFolderBusboyData = (busboy: any, user: UserInterface) => {
const getFolderBusboyData = (
busboy: any,
user: UserInterface,
req: RequestTypeFullUser
) => {
return new Promise<{ fileDataMap: dataType; parent: string }>(
(resolve, reject) => {
const fileEventEmitter = processData(busboy, user);
const fileEventEmitter = processData(busboy, user, req);
fileEventEmitter.on("finish", (data) => {
resolve(data);
});
@@ -0,0 +1,77 @@
import { EventEmitter } from "stream";
import { UserInterface } from "../../../models/user-model";
import ForbiddenError from "../../../utils/ForbiddenError";
import ThumbnailDB from "../../../db/mongoDB/thumbnailDB";
import NotFoundError from "../../../utils/NotFoundError";
import crypto from "crypto";
import { createGenericParams } from "./storageHelper";
import { getStorageActions } from "../actions/helper-actions";
import streamToBuffer from "../../../utils/streamToBuffer";
const thumbnailDB = new ThumbnailDB();
const storageActions = getStorageActions();
const processData = (thumbnailID: string, user: UserInterface) => {
const eventEmitter = new EventEmitter();
const processThumbnail = async () => {
try {
const password = user.getEncryptionKey();
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const thumbnail = await thumbnailDB.getThumbnailInfo(
user._id.toString(),
thumbnailID
);
if (!thumbnail) throw new NotFoundError("Thumbnail Not Found");
const iv = thumbnail.IV;
const CIPHER_KEY = crypto.createHash("sha256").update(password).digest();
const decipher = crypto.createDecipheriv("aes256", CIPHER_KEY, iv);
const readStreamParams = createGenericParams({
filePath: thumbnail.path,
Key: thumbnail.s3ID,
});
const readStream = storageActions.createReadStream(readStreamParams);
decipher.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
readStream.on("error", (e: Error) => {
eventEmitter.emit("error", e);
});
const bufferData = await streamToBuffer(readStream.pipe(decipher));
eventEmitter.emit("finish", bufferData);
} catch (e) {
eventEmitter.emit("error", e);
}
};
processThumbnail();
return eventEmitter;
};
const getThumbnailData = (thumbnailID: string, user: UserInterface) => {
return new Promise((resolve, reject) => {
const eventEmitter = processData(thumbnailID, user);
eventEmitter.on("finish", (data) => {
resolve(data);
});
eventEmitter.on("error", (e) => {
reject(e);
});
});
};
export default getThumbnailData;