@nu-art/file-upload
Version:
File Uploader - Express & Typescript based backend framework
142 lines • 5.72 kB
JavaScript
/*
* Permissions management system, define access level for each of
* your server apis, and restrict users by giving them access levels
*
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { __stringify, _keys, BadImplementationException, Dispatcher, Minute, Module, Queue } from '@nu-art/ts-common';
import { HeaderKey_ContentType } from '@nu-art/thunderstorm';
import { ApiDef_UploadFile, FileStatus, PushKey_FileUploaded } from '../../shared/index.js';
export class ModuleBase_AssetUploader extends Module {
vv1;
files = {};
uploadQueue = new Queue('File Uploader').setParallelCount(1);
dispatch_fileStatusChange = new Dispatcher('__onFileStatusChanged');
constructor() {
super();
this.setDefaultConfig({ manualProcessTriggering: false });
}
__onMessageReceived(notification) {
if (notification.topic !== PushKey_FileUploaded)
return;
const data = notification.message;
if (!data)
return this.logError('file upload push without data');
const feId = data.asset.feId;
if (!feId)
return this.logError('file upload push without feId');
this.setFileInfo(feId, data);
}
init() {
if (this.config.uploadQueueParallelCount)
this.uploadQueue.setParallelCount(this.config.uploadQueueParallelCount);
}
getFileInfo(id, key) {
return this.files[id] && this.files[id][key];
}
getFullFileInfo(id) {
if (!id)
return undefined;
return this.files[id];
}
setFileInfo(feId, values) {
const fileInfo = this.files[feId];
if (!fileInfo)
return this.logError(`file upload push received, but no file info exists for ${feId}`);
_keys(values).forEach(key => fileInfo[key] = values[key]);
this.dispatchFileStatusChange(feId);
}
dispatchFileStatusChange(id) {
this.dispatch_fileStatusChange.dispatchModule(id);
}
uploadImpl(files) {
const body = files.map(fileData => {
const { file, ...fileInfo } = fileData;
this.files[fileInfo.feId] = {
file,
status: FileStatus.ObtainingUrl,
name: fileData.name
};
return fileInfo;
});
this.vv1.getUploadUrl?.(body)
.execute(async (response) => {
body.forEach(f => this.setFileInfo(f.feId, { status: FileStatus.UrlObtained }));
if (!response)
return;
// Not a relevant await but still...
await this.uploadFiles(response);
});
return body;
}
uploadFiles = async (response) => {
// Subscribe
await this.subscribeToPush(response);
response.forEach(r => {
const feId = r.asset.feId;
this.uploadQueue.addItem(async () => {
await this.uploadFile(r);
delete this.files[feId].file;
this.setFileInfo(feId, { progress: 0 });
//TODO: Probably need to set a timer here in case we dont get a push back (contingency)
}, () => {
this.setFileInfo(feId, { status: FileStatus.WaitingForProcessing });
if (this.config.manualProcessTriggering)
this.processAssetManually(feId);
}, error => {
this.setFileInfo(feId, {
messageStatus: __stringify(error),
status: FileStatus.Error
});
});
});
};
uploadFile = async (response) => {
const feId = response.asset.feId;
this.setFileInfo(feId, {
status: FileStatus.UploadingFile,
asset: response.asset
});
const fileInfo = this.files[feId];
if (!fileInfo)
throw new BadImplementationException(`Missing file with id ${feId} and name: ${response.asset.name}`);
const request = this.createRequest(ApiDef_UploadFile)
.setUrl(response.signedUrl)
.setHeader(HeaderKey_ContentType, response.asset.mimeType)
.setTimeout(20 * Minute)
.setBody(fileInfo.file)
.setOnProgressListener((ev) => {
this.setFileInfo(feId, { progress: ev.loaded / ev.total });
});
fileInfo.request = request;
await request.executeSync();
// const request = this.vv1.uploadFile(fileInfo.file, undefined as never)
// .setUrl(response.signedUrl);
// const request = this
// .httpModule
// .createRequest(HttpMethod.PUT, RequestKey_UploadFile, feId)
};
processAssetManually = (feId) => {
const request = this.vv1.processAssetManually({ feId });
// const request = this
// .httpModule
// .createRequest<Api_ProcessAssetManually>(HttpMethod.GET, RequestKey_ProcessAssetManually, feId)
// .setRelativeUrl('v1/upload/process-asset-manually');
if (feId)
request.setUrlParam('feId', feId);
request.execute();
};
}
//# sourceMappingURL=ModuleBase_AssetUploader.js.map