UNPKG

@uploadx/core

Version:
138 lines (137 loc) 5.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DiskStorage = exports.DiskFile = void 0; const path_1 = require("path"); const utils_1 = require("../utils"); const file_1 = require("./file"); const local_meta_storage_1 = require("./local-meta-storage"); const storage_1 = require("./storage"); class DiskFile extends file_1.File { } exports.DiskFile = DiskFile; /** * Local Disk Storage */ class DiskStorage extends storage_1.BaseStorage { constructor(config = {}) { super(config); this.config = config; this.checksumTypes = ['md5', 'sha1', 'sha256']; this.directory = config.directory || this.path.replace(/^\//, ''); if (config.metaStorage) { this.meta = config.metaStorage; } else { const metaConfig = { ...config, ...config.metaStorageConfig }; this.meta = new local_meta_storage_1.LocalMetaStorage(metaConfig); } this.isReady = false; this.accessCheck() .then(() => (this.isReady = true)) .catch(err => { this.logger.error('Storage access check failed: %O', err); }); } normalizeError(err) { return super.normalizeError(err); } accessCheck() { return (0, utils_1.accessCheck)(this.directory); } async create(req, fileInit) { const file = new DiskFile(fileInit); file.name = this.namingFunction(file, req); file.size = Number.isNaN(file.size) ? this.maxUploadSize : file.size; await this.validate(file); const path = this.getFilePath(file.name); file.bytesWritten = await (0, utils_1.ensureFile)(path).catch(err => (0, utils_1.fail)(utils_1.ERRORS.FILE_ERROR, err)); file.status = (0, file_1.getFileStatus)(file); await this.saveMeta(file); return file; } async write(part) { const file = await this.getMeta(part.id); await this.checkIfExpired(file); if (file.status === 'completed') return file; if (part.size) (0, file_1.updateSize)(file, part.size); if (!(0, file_1.partMatch)(part, file)) return (0, utils_1.fail)(utils_1.ERRORS.FILE_CONFLICT); const path = this.getFilePath(file.name); await this.lock(path); try { if ((0, file_1.hasContent)(part)) { if (this.isUnsupportedChecksum(part.checksumAlgorithm)) { return (0, utils_1.fail)(utils_1.ERRORS.UNSUPPORTED_CHECKSUM_ALGORITHM); } const [bytesWritten, errorCode] = await this._write({ ...file, ...part }); if (errorCode) { await (0, utils_1.truncateFile)(path, part.start); return (0, utils_1.fail)(errorCode); } file.bytesWritten = bytesWritten; file.status = (0, file_1.getFileStatus)(file); await this.saveMeta(file); } else { file.bytesWritten = await (0, utils_1.ensureFile)(path); } return file; } catch (err) { return (0, utils_1.fail)(utils_1.ERRORS.FILE_ERROR, err); } finally { await this.unlock(path); } } async delete({ id }) { try { const file = await this.getMeta(id); await (0, utils_1.removeFile)(this.getFilePath(file.name)); await this.deleteMeta(id); return [{ ...file, status: 'deleted' }]; } catch { } return [{ id }]; } /** * Returns path for the uploaded file */ getFilePath(filename) { return (0, path_1.join)(this.directory, filename); } _write(part) { return new Promise((resolve, reject) => { const dest = (0, utils_1.getWriteStream)(this.getFilePath(part.name), part.start); const lengthChecker = (0, utils_1.streamLength)(part.contentLength || part.size - part.start); const checksumChecker = (0, utils_1.streamChecksum)(part.checksum, part.checksumAlgorithm); const keepPartial = !part.checksum; const cleanupStreams = () => { dest.close(); lengthChecker.destroy(); checksumChecker.destroy(); }; const failWithCode = (code) => { cleanupStreams(); resolve([NaN, code]); }; lengthChecker.on('error', () => failWithCode(utils_1.ERRORS.FILE_CONFLICT)); checksumChecker.on('error', () => failWithCode(utils_1.ERRORS.CHECKSUM_MISMATCH)); part.body.on('aborted', () => failWithCode(keepPartial ? undefined : utils_1.ERRORS.REQUEST_ABORTED)); part.body .pipe(lengthChecker) .pipe(checksumChecker) .pipe(dest) .on('error', (err) => { cleanupStreams(); reject(err); }) .on('finish', () => { return resolve([part.start + dest.bytesWritten]); }); }); } } exports.DiskStorage = DiskStorage;