@rytass/storages-adapter-local
Version:
Rytass Utils Storages local adapter
130 lines (127 loc) • 4.65 kB
JavaScript
import { Storage, StorageError, ErrorCode } from '@rytass/storages';
import { v4 } from 'uuid';
import { promisify } from 'util';
import { StorageLocalHelperCommands } from './typings.js';
import { resolve } from 'path';
import { mkdirSync, lstatSync, createWriteStream, createReadStream } from 'fs';
import { writeFile, rename, readFile, unlink } from 'fs/promises';
import { exec as exec$1 } from 'child_process';
// @dev: using the
const exec = promisify(exec$1);
class LocalStorage extends Storage {
directory;
constructor(options){
super(options);
this.directory = options.directory;
if (options.autoMkdir) {
mkdirSync(this.directory, {
recursive: true
});
}
if (!lstatSync(this.directory).isDirectory()) {
throw new StorageError(ErrorCode.DIRECTORY_NOT_FOUND);
}
}
async getUsageInfo() {
const _usage = await this.getFsUsage();
return _usage;
}
// @dev: returns file system usage in 1M-blocks
async getFsUsage() {
const used = Number((await exec(StorageLocalHelperCommands.USED.replace('__DIR__', this.directory))).stdout);
const free = Number((await exec(StorageLocalHelperCommands.FREE.replace('__DIR__', this.directory))).stdout);
const total = Number((await exec(StorageLocalHelperCommands.TOTAL.replace('__DIR__', this.directory))).stdout);
return {
used,
free,
total
};
}
getFileFullPath(key) {
return resolve(this.directory, key);
}
checkFileExists(fullPath) {
try {
if (!lstatSync(fullPath).isFile()) {
throw new StorageError(ErrorCode.FILE_NOT_FOUND);
}
} catch (ex) {
throw new StorageError(ErrorCode.FILE_NOT_FOUND);
}
}
async writeBuffer(buffer, options) {
const convertedBuffer = await this.converterManager.convert(buffer);
const fileInfo = options?.filename || await this.getBufferFilename(buffer);
const filename = Array.isArray(fileInfo) ? fileInfo[0] : fileInfo;
await writeFile(this.getFileFullPath(filename), convertedBuffer);
return {
key: filename
};
}
async writeStream(stream, options) {
return new Promise(async (promiseResolve)=>{
const convertedStream = await this.converterManager.convert(stream);
if (options?.filename) {
const writeStream = createWriteStream(this.getFileFullPath(options.filename));
convertedStream.pipe(writeStream);
await new Promise((pResolve)=>{
stream.on('end', pResolve);
});
promiseResolve({
key: options.filename
});
return;
}
const tempFilename = v4();
const writeStream = createWriteStream(this.getFileFullPath(tempFilename));
this.getStreamFilename(convertedStream).then(async ([filename])=>{
await rename(this.getFileFullPath(tempFilename), this.getFileFullPath(filename));
promiseResolve({
key: filename
});
});
convertedStream.pipe(writeStream);
});
}
readFileBuffer(key) {
const path = this.getFileFullPath(key);
this.checkFileExists(path);
return readFile(path);
}
readFileStream(key) {
const path = this.getFileFullPath(key);
this.checkFileExists(path);
return createReadStream(path);
}
read(key, options) {
if (options?.format === 'buffer') {
return this.readFileBuffer(key);
}
return Promise.resolve(this.readFileStream(key));
}
async write(file, options) {
const convertedFile = await this.converterManager.convert(file);
if (convertedFile instanceof Buffer) {
return this.writeBuffer(convertedFile, options);
}
return this.writeStream(convertedFile, options);
}
batchWrite(files, options) {
return Promise.all(files.map((file, index)=>this.write(file, options?.[index])));
}
remove(key) {
const path = this.getFileFullPath(key);
this.checkFileExists(path);
return unlink(path);
}
async isExists(key) {
const path = this.getFileFullPath(key);
try {
await this.checkFileExists(path);
return true;
} catch (ex) {
return false;
}
}
}
export { LocalStorage };