UNPKG

@rytass/storages

Version:
102 lines (99 loc) 3.74 kB
import { PassThrough } from 'stream'; import { createHash } from 'crypto'; import { fromBuffer, fromStream } from 'file-type'; import { ConverterManager } from '@rytass/file-converter'; const MIN_BUFFER_LENGTH = 16; class Storage { converterManager; hashAlgorithm; constructor(options){ this.converterManager = new ConverterManager(options?.converters ?? []); this.hashAlgorithm = options?.hashAlgorithm || 'sha256'; } getExtension(file) { if (file instanceof Buffer) { return fromBuffer(file); } const extensionStream = new PassThrough(); file.pipe(extensionStream); return fromStream(extensionStream); } async getBufferFilename(buffer) { const extension = await fromBuffer(buffer); return [ `${createHash(this.hashAlgorithm).update(buffer).digest('hex')}${extension?.ext ? `.${extension.ext}` : ''}`, extension?.mime ?? undefined ]; } getStreamFilename(stream) { return new Promise((resolve, reject)=>{ const hashStream = new PassThrough(); const extensionStream = new PassThrough(); const getStreamHash = new Promise((subResolve)=>{ const hash = createHash(this.hashAlgorithm); hashStream.on('data', (buffer)=>{ hash.update(buffer); }); hashStream.on('end', ()=>{ subResolve(hash.digest('hex')); }); }); const getStreamFileType = new Promise((subResolve)=>{ let resolved = false; let isEnd = false; const bufferStorage = []; const waitingTasks = []; extensionStream.on('data', (buffer)=>{ if (resolved) return; bufferStorage.push(buffer); const targetBuffer = Buffer.concat(bufferStorage); if (targetBuffer.length >= MIN_BUFFER_LENGTH) { const taskIndex = waitingTasks.length; waitingTasks.push(true); fromBuffer(targetBuffer).then((result)=>{ waitingTasks[taskIndex] = false; if (!result && !isEnd) return; resolved = true; subResolve(result); }); } else { waitingTasks.push(false); } }); extensionStream.on('end', ()=>{ isEnd = true; if (waitingTasks.every((task)=>!task) && !resolved) { resolved = true; subResolve(undefined); } }); }); Promise.all([ getStreamHash, getStreamFileType ]).then(([filename, extension])=>{ resolve([ `${filename}${extension?.ext ? `.${extension.ext}` : ''}`, extension?.mime ?? undefined ]); }).catch(reject); stream.pipe(hashStream).pipe(extensionStream); }); } write(file, options) { throw new Error('Method not implemented.'); } batchWrite(files, options) { throw new Error('Method not implemented.'); } read(key, options) { throw new Error('Method not implemented.'); } remove(key) { throw new Error('Method not implemented.'); } isExists(key) { throw new Error('Method not implemented.'); } } export { Storage };