@namatery/multer-minio
Version:
A simple storage engine for Multer to upload files on Minio storage.
105 lines (86 loc) • 2.99 kB
text/typescript
import { posix } from 'node:path';
import { StorageEngine } from 'multer';
import { randomUUID } from 'node:crypto';
import { IStorageOptions } from './storage.options';
import { Client, DEFAULT_REGION, RemoveOptions } from 'minio';
export class MinioStorageEngine implements StorageEngine {
/**
* @param minio An instance of `Minio` clinet.
* @param bucket Name of the bucket on `Minio`.
* @param options Storage options.
*/
constructor(
public minio: Client,
public bucket: string,
public options: IStorageOptions
) {
this.options = this.options || {
bucket: undefined,
path: undefined,
region: undefined,
};
this.options.bucket = this.options.bucket || {
init: false,
forceDelete: false,
versioning: false,
};
this.options.object = this.options.object || {
name: undefined,
useOriginalFilename: false,
};
this._init();
}
private async _init() {
const { bucket, region } = this.options;
const exists = await this.minio.bucketExists(this.bucket);
if (!exists && !bucket.init) {
throw new Error(`Bucket [${this.bucket}] does not exists.`);
}
if (!exists && bucket.init) {
await this.minio.makeBucket(this.bucket, region || DEFAULT_REGION);
console.log(`Bucket [${this.bucket}] created.`);
}
if (bucket.versioning) {
await this.minio.setBucketVersioning(this.bucket, { Status: bucket.versioning });
console.log(`Bucket [${this.bucket}] has versioning status [${bucket.versioning}]`);
}
}
private _getObjectName(req: Express.Request, file: Express.Multer.File) {
const { object } = this.options;
if (object.useOriginalFilename) {
return file.originalname;
}
return object.name ? object.name(req, file) : randomUUID();
}
private _getObjectPath(objectName: string) {
const { path } = this.options;
return posix.join(path || '/', objectName);
}
async _handleFile(req: Express.Request, file: Express.Multer.File, callback: any) {
try {
file.filename = this._getObjectName(req, file);
file.path = this._getObjectPath(file.filename);
await this.minio.putObject(this.bucket, file.path, file.stream, {
'Content-Type': file.mimetype,
});
callback(null, { bucket: this.bucket });
} catch (error) {
callback(error);
}
}
async _removeFile(req: Express.Request, file: Express.Multer.File, callback: any) {
const { bucket } = this.options;
try {
const removeOptions: RemoveOptions = {
forceDelete: false,
};
if (bucket.versioning === 'Enabled' && bucket.forceDelete) {
removeOptions.forceDelete = true;
}
await this.minio.removeObject(this.bucket, file.path, removeOptions);
callback(null);
} catch (error) {
callback(error);
}
}
}