UNPKG

@intuitionrobotics/file-upload

Version:

File Uploader - Express & Typescript based backend framework

158 lines 7.51 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseUploaderModule_Class = exports.FileStatus = void 0; const ts_common_1 = require("@intuitionrobotics/ts-common"); const thunderstorm_1 = require("@intuitionrobotics/thunderstorm"); const RequestKey_UploadUrl = 'get-upload-url'; const RequestKey_UploadFile = 'upload-file'; var FileStatus; (function (FileStatus) { FileStatus["ObtainingUrl"] = "ObtainingUrl"; FileStatus["UrlObtained"] = "UrlObtained"; FileStatus["UploadingFile"] = "UploadingFile"; // I can assume that in between I upload and I get // the push I'm processing the file in the be FileStatus["PostProcessing"] = "PostProcessing"; FileStatus["Completed"] = "Completed"; FileStatus["Error"] = "Error"; })(FileStatus || (exports.FileStatus = FileStatus = {})); class BaseUploaderModule_Class extends ts_common_1.Module { constructor(httpModule, moduleName) { super(moduleName); this.files = {}; this.uploadQueue = new ts_common_1.Queue("File Uploader").setParallelCount(2); this.uploadFiles = (response) => __awaiter(this, void 0, void 0, function* () { // Subscribe yield this.subscribeToPush(response); response.forEach(r => { const feId = r.tempDoc.feId; this.uploadQueue.addItem(() => __awaiter(this, void 0, void 0, function* () { yield this.uploadFile(r); delete this.files[feId].file; this.setFileInfo(feId, "progress", undefined); //TODO: Probably need to set a timer here in case we dont get a push back (contingency) }), () => { this.setFileInfo(feId, "status", FileStatus.PostProcessing); }, error => { this.setFileInfo(feId, "status", FileStatus.Error); this.setFileInfo(feId, "messageStatus", (0, ts_common_1.__stringify)(error)); }); }); }); this.uploadFile = (response) => __awaiter(this, void 0, void 0, function* () { const feId = response.tempDoc.feId; this.setFileInfo(feId, "status", FileStatus.UploadingFile); this.setFileInfo(feId, "tempDoc", response.tempDoc); const fileInfo = this.files[feId]; if (!fileInfo) throw new ts_common_1.BadImplementationException(`Missing file with id ${feId} and name: ${response.tempDoc.name}`); const request = this .httpModule .createRequest(thunderstorm_1.HttpMethod.PUT, RequestKey_UploadFile) .setUrl(response.secureUrl) // Don't change this because it replaces the default headers which we dont need .setDefaultHeaders({ 'Content-Type': response.tempDoc.mimeType }) .setTimeout(20 * ts_common_1.Minute) .setBody(fileInfo.file) .setOnProgressListener((ev) => { this.setFileInfo(feId, "progress", ev.loaded / ev.total); }); this.setFileInfo(feId, "request", request); yield request.executeSync(); }); this.httpModule = httpModule; } init() { if (this.config.uploadQueueParallelCount) this.uploadQueue.setParallelCount(this.config.uploadQueueParallelCount); } getFileInfo(id, key) { return this.files[id] && this.files[id][key]; } getFullFileInfo(id) { return this.files[id]; } setFileInfo(id, key, value) { if (!this.files[id]) throw new ts_common_1.BadImplementationException(`Trying to set ${key} for non existent file with id: ${id}`); this.files[id][key] = value; this.files[id].statusCallBack(id, this.files[id].status); } uploadImpl(files, _bucketName, _pathPrefix) { const body = files.map(fileData => { const fileInfo = { name: fileData.name, mimeType: fileData.mimeType, feId: (0, ts_common_1.generateHex)(32) }; if (fileData.key) fileInfo.key = fileData.key; if (fileData.public) fileInfo.public = fileData.public; this.files[fileInfo.feId] = { file: fileData.file, fileName: fileData.file.name, status: FileStatus.ObtainingUrl, name: fileData.name, statusCallBack: fileData.onFileStatusChanged }; return fileInfo; }); if (_bucketName) this.getUrlEndpointWithBucketName({ files: body, pathPrefix: _pathPrefix, bucketName: _bucketName }); else this.getUrlEndpoint(body); return body; } getUrlEndpoint(body) { this .httpModule .createRequest(thunderstorm_1.HttpMethod.POST, RequestKey_UploadUrl) .setRelativeUrl('/v1/upload/get-url') .setJsonBody(body) .setOnError((request, resError) => { body.forEach(f => { this.setFileInfo(f.feId, "messageStatus", (0, ts_common_1.__stringify)(resError === null || resError === void 0 ? void 0 : resError.debugMessage)); this.setFileInfo(f.feId, "status", FileStatus.Error); }); }) .execute((response) => __awaiter(this, void 0, void 0, function* () { body.forEach(f => this.setFileInfo(f.feId, "status", FileStatus.UrlObtained)); if (!response) return; // Not a relevant await but still... yield this.uploadFiles(response); })); } getUrlEndpointWithBucketName(body) { this .httpModule .createRequest(thunderstorm_1.HttpMethod.POST, RequestKey_UploadUrl) .setRelativeUrl('/v1/upload/get-url-with-bucket-name') .setJsonBody(body) .setOnError((request, resError) => { body.files.forEach(f => { this.setFileInfo(f.feId, "messageStatus", (0, ts_common_1.__stringify)(resError === null || resError === void 0 ? void 0 : resError.debugMessage)); this.setFileInfo(f.feId, "status", FileStatus.Error); }); }) .execute((response) => __awaiter(this, void 0, void 0, function* () { body.files.forEach(f => this.setFileInfo(f.feId, "status", FileStatus.UrlObtained)); if (!response) return; // Not a relevant await but still... yield this.uploadFiles(response); })); } } exports.BaseUploaderModule_Class = BaseUploaderModule_Class; //# sourceMappingURL=BaseUploaderModule.js.map