b68/packages/api/helpers/upload.factory.ts

138 lines
3.7 KiB
TypeScript

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
}
}
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
}
}
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
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()
}
console.log(`Upload Client initialized in '${env}' environment`)
}
}