mirror of
https://github.com/codex-team/codex.docs.git
synced 2025-07-30 10:39:43 +02:00
S3 uploads support (#273)
* finish s3 uploads implementation * remove unnecessary file * fix docs * update DEVELOPMENT.md * update doc * update default uploads path
This commit is contained in:
parent
55b4b3ee61
commit
8c794304b6
16 changed files with 1373 additions and 248 deletions
10
src/backend/uploads/index.ts
Normal file
10
src/backend/uploads/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import appConfig from '../utils/appConfig.js';
|
||||
import S3UploadsDriver from './s3.js';
|
||||
import LocalUploadsDriver from './local.js';
|
||||
|
||||
/**
|
||||
* Initialize the uploads driver based on the configuration
|
||||
*/
|
||||
export const uploadsDriver = appConfig.uploads.driver === 'local'
|
||||
? new LocalUploadsDriver(appConfig.uploads)
|
||||
: new S3UploadsDriver(appConfig.uploads);
|
72
src/backend/uploads/local.ts
Normal file
72
src/backend/uploads/local.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { UploadsDriver } from './types.js';
|
||||
import multer from 'multer';
|
||||
import mkdirp from 'mkdirp';
|
||||
import { random16 } from '../utils/crypto.js';
|
||||
import mime from 'mime';
|
||||
import appConfig, { LocalUploadsConfig } from '../utils/appConfig.js';
|
||||
import fs from 'fs';
|
||||
import fileType from 'file-type';
|
||||
import { FileData } from '../models/file.js';
|
||||
|
||||
/**
|
||||
* Uploads driver for local storage
|
||||
*/
|
||||
export default class LocalUploadsDriver implements UploadsDriver {
|
||||
/**
|
||||
* Configuration for local uploads
|
||||
*/
|
||||
private readonly config: LocalUploadsConfig;
|
||||
|
||||
/**
|
||||
* Create a new instance of LocalUploadsDriver
|
||||
*
|
||||
* @param config - configuration for local uploads
|
||||
*/
|
||||
constructor(config: LocalUploadsConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates multer storage engine for local uploads
|
||||
*/
|
||||
public createStorageEngine(): multer.StorageEngine {
|
||||
return multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const dir: string = this.config.local.path;
|
||||
|
||||
mkdirp(dir);
|
||||
cb(null, dir);
|
||||
},
|
||||
filename: async (req, file, cb) => {
|
||||
const filename = await random16();
|
||||
|
||||
cb(null, `${filename}.${mime.getExtension(file.mimetype)}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves passed file to the local storage
|
||||
*
|
||||
* @param data - file data to save
|
||||
* @param mimetype - file mimetype
|
||||
* @param possibleExtension
|
||||
*/
|
||||
public async save(data: Buffer, mimetype?: string, possibleExtension?: string): Promise<FileData> {
|
||||
const filename = await random16();
|
||||
|
||||
const type = await fileType.fromBuffer(data);
|
||||
const ext = type ? type.ext : possibleExtension;
|
||||
const fullName = `${filename}.${ext}`;
|
||||
|
||||
fs.writeFileSync(`${appConfig.uploads}/${fullName}`, data);
|
||||
|
||||
return {
|
||||
name: fullName,
|
||||
filename: fullName,
|
||||
size: data.length,
|
||||
mimetype,
|
||||
};
|
||||
}
|
||||
}
|
88
src/backend/uploads/s3.ts
Normal file
88
src/backend/uploads/s3.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import { UploadsDriver } from './types.js';
|
||||
import multerS3 from 'multer-s3';
|
||||
import { random16 } from '../utils/crypto.js';
|
||||
import path from 'path';
|
||||
import mime from 'mime';
|
||||
import multer from 'multer';
|
||||
import { S3UploadsConfig } from '../utils/appConfig.js';
|
||||
import { FileData } from '../models/file.js';
|
||||
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
||||
import fileType from 'file-type';
|
||||
|
||||
/**
|
||||
* Uploads driver for S3 storage
|
||||
*/
|
||||
export default class S3UploadsDriver implements UploadsDriver {
|
||||
/**
|
||||
* Configuration for S3 uploads
|
||||
*/
|
||||
private readonly config: S3UploadsConfig;
|
||||
|
||||
/**
|
||||
* S3 client for uploads
|
||||
*/
|
||||
private readonly s3Client: S3Client;
|
||||
|
||||
/**
|
||||
* Create a new instance of S3UploadsDriver
|
||||
*
|
||||
* @param config - configuration for s3 uploads
|
||||
*/
|
||||
constructor(config: S3UploadsConfig) {
|
||||
this.config = config;
|
||||
this.s3Client = new S3Client({
|
||||
region: this.config.s3.region,
|
||||
credentials: {
|
||||
accessKeyId: this.config.s3.accessKeyId,
|
||||
secretAccessKey: this.config.s3.secretAccessKey,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates multer storage engine for S3
|
||||
*/
|
||||
public createStorageEngine(): multer.StorageEngine {
|
||||
const config = this.config;
|
||||
|
||||
return multerS3({
|
||||
s3: this.s3Client,
|
||||
bucket: config.s3.bucket,
|
||||
key: async function (req, file, cb) {
|
||||
const filename = await random16();
|
||||
|
||||
cb(null, path.posix.join(config.s3.keyPrefix, `${filename}.${mime.getExtension(file.mimetype)}`));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves passed file to the storage
|
||||
*
|
||||
* @param data - file data to save
|
||||
* @param mimetype - file mimetype
|
||||
* @param possibleExtension - possible file extension
|
||||
*/
|
||||
public async save(data: Buffer, mimetype?: string, possibleExtension?: string): Promise<FileData> {
|
||||
const filename = await random16();
|
||||
|
||||
const type = await fileType.fromBuffer(data);
|
||||
const ext = type ? type.ext : possibleExtension;
|
||||
const fullName = `${filename}.${ext}`;
|
||||
const fileKey = path.posix.join(this.config.s3.keyPrefix, fullName);
|
||||
|
||||
await this.s3Client.send(new PutObjectCommand({
|
||||
Bucket: this.config.s3.bucket,
|
||||
Key: fileKey,
|
||||
Body: data,
|
||||
ContentType: mimetype,
|
||||
}));
|
||||
|
||||
return {
|
||||
name: fileKey,
|
||||
filename: fileKey,
|
||||
size: data.length,
|
||||
mimetype,
|
||||
};
|
||||
}
|
||||
}
|
21
src/backend/uploads/types.ts
Normal file
21
src/backend/uploads/types.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import multer from 'multer';
|
||||
import { FileData } from '../models/file.js';
|
||||
|
||||
/**
|
||||
* Represents common uploads driver functionality
|
||||
*/
|
||||
export interface UploadsDriver {
|
||||
/**
|
||||
* Returns multer storage instance
|
||||
*/
|
||||
createStorageEngine(): multer.StorageEngine
|
||||
|
||||
/**
|
||||
* Saves passed file
|
||||
*
|
||||
* @param data - file data to save
|
||||
* @param mimetype - file mimetype
|
||||
* @param possibleExtension - possible file extension
|
||||
*/
|
||||
save(data: Buffer, mimetype?: string, possibleExtension?: string): Promise<FileData>;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue