continued cleaning up events
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user