reworked upload factory
This commit is contained in:
parent
163f732ac7
commit
cf39c03ba3
|
@ -2,136 +2,81 @@ import { S3Client } from '@aws-sdk/client-s3'
|
||||||
import multer from 'multer'
|
import multer from 'multer'
|
||||||
import multerS3 from 'multer-s3'
|
import multerS3 from 'multer-s3'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { nanoid } from 'napi-nanoid'
|
import napiNanoId from 'napi-nanoid'
|
||||||
import axios from 'axios'
|
import { configKeys } from '..'
|
||||||
import FormData from 'form-data'
|
interface UploadFactoryOptions {
|
||||||
import fs from 'fs'
|
region: string
|
||||||
|
bucket: string
|
||||||
type UploadEnvironment = 's3' | 'safe' | 'local'
|
accessKey: string
|
||||||
type napiNanoId = () => string
|
secretKey: 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
interface UploaderConfig {
|
||||||
export class S3UploadFactory {
|
folder: string
|
||||||
private _upload: multer.Multer
|
mimeFilters: string[]
|
||||||
|
|
||||||
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 {
|
export class UploadFactory {
|
||||||
private static _clientMode: UploadEnvironment
|
private options: UploadFactoryOptions & Partial<UploaderConfig>
|
||||||
private static _s3Client: S3Client
|
private s3Client: S3Client
|
||||||
private static _localClient: LocalUploadFactory
|
|
||||||
private static _safeClient: SafeUploadFactory
|
|
||||||
|
|
||||||
static get client() {
|
constructor(options?: Partial<UploadFactoryOptions>) {
|
||||||
return this._clientMode === 's3'
|
this.options = {
|
||||||
? this._s3Client
|
bucket: options?.bucket || configKeys.S3_BUCKET_NAME || '',
|
||||||
: this._clientMode === 'safe'
|
region: options?.region || configKeys.S3_BUCKET_REGION || '',
|
||||||
? this._safeClient
|
accessKey: options?.accessKey || configKeys.S3_CLIENT_ID || '',
|
||||||
: this._localClient
|
secretKey: options?.secretKey || configKeys.S3_CLIENT_SECRET || '',
|
||||||
}
|
|
||||||
|
|
||||||
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`)
|
|
||||||
|
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<UploadFactoryOptions & UploaderConfig>
|
||||||
|
) {
|
||||||
|
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('/'))
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue