@rytass/storages
Version:
Rytass Utils Storages
103 lines (100 loc) • 3.83 kB
JavaScript
import { PassThrough } from 'stream';
import { createHash } from 'crypto';
import { Buffer } from 'buffer';
import { fileTypeFromBuffer, fileTypeFromStream } 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 fileTypeFromBuffer(file);
}
const extensionStream = new PassThrough();
file.pipe(extensionStream);
return fileTypeFromStream(extensionStream);
}
async getBufferFilename(buffer) {
const extension = await fileTypeFromBuffer(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);
fileTypeFromBuffer(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 };