UNPKG

@intuitionrobotics/file-upload

Version:

File Uploader - Express & Typescript based backend framework

102 lines 4.69 kB
import { auditBy, generateHex, Hour, ImplementationMissingException, Module, ThisShouldNotHappenException } from "@intuitionrobotics/ts-common"; import { FileWrapper, FirebaseModule, StorageWrapper } from "@intuitionrobotics/firebase/backend"; import { fileUploadedKey, UploadResult } from "../../shared/types.js"; import { UploaderTempFileModule } from "./UploaderTempFileModule.js"; import { PushPubSubModule } from "@intuitionrobotics/push-pub-sub/backend"; import {} from "./BucketListener.js"; export const Temp_Path = "files-temp"; export class UploaderModule_Class extends Module { constructor() { super("UploaderModule"); } storage; postProcessor; async __onFileUploaded(filePath) { await this.fileUploaded(filePath); } setPostProcessor = (validator) => { this.postProcessor = validator; }; getProcessor = (k) => { const postProcessorElement = this.postProcessor[k]; if (!postProcessorElement) throw new ImplementationMissingException(`Missing validator for type ${k}`); return postProcessorElement; }; init() { if (!this.postProcessor) throw new ImplementationMissingException("You must set a postProcessor for the UploaderModule"); this.storage = FirebaseModule.createAdminSession(this.config.uploaderProjectId).getStorage(); } async getUrl(body, pathPrefix = Temp_Path, _bucketName) { const bucketName = _bucketName || this.config?.bucketName; const bucket = await this.storage.getOrCreateBucket(bucketName); return Promise.all(body.map(async (_file) => { const key = _file.key || _file.mimeType; this.getProcessor(key); const _id = generateHex(32); const path = `${pathPrefix}/${_id}`; const instance = { _id, feId: _file.feId, name: _file.name, mimeType: _file.mimeType, key, path, _audit: auditBy("be-stub"), bucketName: bucket.bucketName }; if (_file.public) instance.public = _file.public; if (_file.metadata) instance.metadata = _file.metadata; const temp = await UploaderTempFileModule.upsert(instance); const file = await bucket.getFile(temp.path); const url = await file.getWriteSecuredUrl(_file.mimeType, Hour); return { secureUrl: url.securedUrl, tempDoc: temp }; })); } fileUploaded = async (filePath) => { if (!filePath) throw new ThisShouldNotHappenException("Missing file path"); this.logInfo(`Looking for file with path ${filePath}`); // I use collection and not the module directly since I want to handle failure my way const tempMeta = await UploaderTempFileModule.collection.queryUnique({ where: { path: filePath } }); if (!tempMeta) return this.logInfo(`File with path: ${filePath}, not found in temp collection db`); this.logInfo(`Found temp meta with _id: ${tempMeta._id}`, tempMeta); const val = this.postProcessor[tempMeta.key]; this.logInfo(`Found a validator ${!!val}`); if (!val) return this.notifyFrontend(tempMeta.feId, UploadResult.Failure, `Missing a validator for ${tempMeta.key} for file: ${tempMeta.name}`); const bucket = await this.storage.getOrCreateBucket(tempMeta.bucketName); const file = await bucket.getFile(tempMeta.path); if (tempMeta.public) { try { await file.makePublic(); } catch (e) { await this.notifyFrontend(tempMeta.feId, UploadResult.Failure, `Failed to make the file public: ${tempMeta.name}`, e); } } try { await val(file, tempMeta); } catch (e) { //TODO delete the file and the temp doc return await this.notifyFrontend(tempMeta.feId, UploadResult.Failure, `Post-processing failed for file: ${tempMeta.name}`, e); } return this.notifyFrontend(tempMeta.feId, UploadResult.Success, `Successfully parsed and processed file ${tempMeta.name}`); }; notifyFrontend = async (feId, result, message, cause) => { if (cause) this.logWarning(cause); const data = { message, result, cause }; await PushPubSubModule.pushToKey(fileUploadedKey, { feId }, data); }; } export const UploaderModule = new UploaderModule_Class(); //# sourceMappingURL=UploaderModule.js.map