From cf39c03ba31bce63c8fc8dbc527a887cbcd79579 Mon Sep 17 00:00:00 2001 From: "Jyotirmoy Bandyopadhyaya [Bravo68]" Date: Wed, 3 May 2023 18:38:19 +0530 Subject: [PATCH] reworked upload factory --- packages/api/helpers/upload.factory.ts | 197 +++++++++---------------- 1 file changed, 71 insertions(+), 126 deletions(-) diff --git a/packages/api/helpers/upload.factory.ts b/packages/api/helpers/upload.factory.ts index d7dc510..9bd5250 100644 --- a/packages/api/helpers/upload.factory.ts +++ b/packages/api/helpers/upload.factory.ts @@ -2,136 +2,81 @@ import { S3Client } from '@aws-sdk/client-s3' import multer from 'multer' import multerS3 from 'multer-s3' import path from 'path' -import { nanoid } from 'napi-nanoid' -import axios from 'axios' -import FormData from 'form-data' -import fs from 'fs' - -type UploadEnvironment = 's3' | 'safe' | 'local' -type napiNanoId = () => string - -export default class LocalUploadFactory { - private _upload: multer.Multer - - constructor() { - this._upload = multer({ - storage: multer.diskStorage({ - destination: (req, file, cb) => { - cb(null, path.join(__dirname, '..', 'uploads')) - }, - filename: (req, file, cb) => { - cb(null, nanoid() + path.extname(file.originalname)) - }, - }), - }) - } - - get upload() { - return this._upload - } +import napiNanoId from 'napi-nanoid' +import { configKeys } from '..' +interface UploadFactoryOptions { + region: string + bucket: string + accessKey: string + secretKey: string } - -export class S3UploadFactory { - private _upload: multer.Multer - - constructor(client: S3Client) { - this._upload = multer({ - storage: multerS3({ - s3: client, - bucket: process.env.AWS_BUCKET!, - acl: 'public-read', - key: (req, file, cb) => { - cb(null, nanoid() + path.extname(file.originalname)) - }, - }), - }) - } - - get upload() { - return this._upload - } +interface UploaderConfig { + folder: string + mimeFilters: string[] } - -export class SafeUploadFactory { - // Safe is a http file upload service at https://safe.b68dev.xyz - // Upload API at https://safe.b68dev.xyz/api/upload - - private _upload: multer.Multer - - constructor() { - this._upload = multer({ - storage: multer.memoryStorage(), - }) - this._upload.single('file') - } - - get upload() { - return this._upload - } - - async uploadFile(file: any) { - const form = new FormData() - form.append('files[]', file.buffer, { filename: file.originalname }) - const { data } = await axios.post( - 'https://safe.b68dev.xyz/api/upload', - form, - { - headers: { - token: process.env.SAFE_TOKEN!, - ...form.getHeaders(), - }, - } - ) - return data - } -} - export class UploadFactory { - private static _clientMode: UploadEnvironment - private static _s3Client: S3Client - private static _localClient: LocalUploadFactory - private static _safeClient: SafeUploadFactory + private options: UploadFactoryOptions & Partial + private s3Client: S3Client - static get client() { - return this._clientMode === 's3' - ? this._s3Client - : this._clientMode === 'safe' - ? this._safeClient - : this._localClient - } - - static get env() { - return this._clientMode - } - - static init(forceEnv?: UploadEnvironment) { - const env = - forceEnv || - process.env.UPLOAD_ENV || - process.env.NODE_ENV || - 'local' - - if (!['s3', 'local', 'safe'].includes(env)) - throw new Error( - "Invalid Upload Environment, expected - ['s3', 'local', 'safe'], received - " + - env - ) - - this._clientMode = env as UploadEnvironment - - if (env === 'safe') { - this._safeClient = new SafeUploadFactory() - } else if (env === 's3') { - this._s3Client = new S3Client({ - region: process.env.AWS_REGION, - credentials: { - accessKeyId: process.env.AWS_ACCESS_KEY_ID!, - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, - }, - }) - } else { - this._localClient = new LocalUploadFactory() + constructor(options?: Partial) { + this.options = { + bucket: options?.bucket || configKeys.S3_BUCKET_NAME || '', + region: options?.region || configKeys.S3_BUCKET_REGION || '', + accessKey: options?.accessKey || configKeys.S3_CLIENT_ID || '', + secretKey: options?.secretKey || configKeys.S3_CLIENT_SECRET || '', } - console.log(`Upload Client initialized in '${env}' environment`) + + this.s3Client = new S3Client({ + region: this.options.region, + credentials: { + accessKeyId: this.options.accessKey, + secretAccessKey: this.options.secretKey, + }, + }) + } + + public get serviceName(): string { + return 'aws:' + this.options.bucket + } + + public getUploader( + config?: Partial + ) { + const finalOptions = { + ...this.options, + ...(config || {}), + } + + return multer({ + fileFilter(_req, file, cb) { + const res = finalOptions.mimeFilters + ? finalOptions.mimeFilters.includes(file.mimetype) + : true + cb(null, res) + }, + storage: multerS3({ + s3: this.s3Client, + bucket: this.options.bucket, + acl: 'public-read', + contentType: multerS3.AUTO_CONTENT_TYPE, + metadata: function (_req, file, cb) { + const meta = { + fieldName: file.fieldname, + fileName: file.originalname, + uploadOn: new Date().toISOString(), + } + cb(null, meta) + }, + key: function (_req, file, cb) { + const key: string[] = [] + if (finalOptions.folder) key.push(finalOptions.folder) + const value = napiNanoId.nanoid() + const ext = path.extname(file.originalname) + key.push(value + ext) + + cb(null, key.join('/')) + }, + }), + }) } }