|
|
@@ -0,0 +1,81 @@
|
|
|
+import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|
|
+import { FileStorage } from './file-storage.interface';
|
|
|
+import { ConfigService } from '@nestjs/config';
|
|
|
+import { v4 as uuidV4 } from 'uuid';
|
|
|
+import * as COS from 'cos-nodejs-sdk-v5';
|
|
|
+import { FileVo } from '../../vo/file.vo';
|
|
|
+
|
|
|
+@Injectable()
|
|
|
+export class CosStrategy implements FileStorage {
|
|
|
+ private client: COS;
|
|
|
+ private readonly bucket: string;
|
|
|
+ private readonly region: string;
|
|
|
+
|
|
|
+ constructor(private readonly configService: ConfigService) {
|
|
|
+ this.bucket = configService.get<string>('COS_BUCKET');
|
|
|
+ this.region = configService.get<string>('COS_REGION');
|
|
|
+ this.client = new COS({
|
|
|
+ SecretId: this.configService.get<string>('COS_SECRET_ID'),
|
|
|
+ SecretKey: this.configService.get<string>('COS_SECRET_KEY'),
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ async uploadFile(
|
|
|
+ file: Express.Multer.File,
|
|
|
+ options?: { folder?: string },
|
|
|
+ ): Promise<FileVo> {
|
|
|
+ const folder = options.folder || 'uploads';
|
|
|
+ const key = `${folder}/${uuidV4()}-${file.originalname}`;
|
|
|
+ const result = await new Promise<COS.PutObjectResult>((resolve, reject) => {
|
|
|
+ this.client.putObject(
|
|
|
+ {
|
|
|
+ Bucket: this.bucket,
|
|
|
+ Region: this.region,
|
|
|
+ Key: key,
|
|
|
+ Body: file.buffer,
|
|
|
+ ContentType: file.mimetype,
|
|
|
+ },
|
|
|
+ (err, data) => {
|
|
|
+ if (err) {
|
|
|
+ reject(err);
|
|
|
+ } else {
|
|
|
+ resolve(data);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
+ });
|
|
|
+ if ('Location' in result) {
|
|
|
+ return { url: 'https://' + result.Location };
|
|
|
+ } else {
|
|
|
+ throw new HttpException(
|
|
|
+ 'Failed to retrieve file URL from COS response',
|
|
|
+ HttpStatus.INTERNAL_SERVER_ERROR,
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async deleteFile(filePath: string): Promise<void> {
|
|
|
+ const key = filePath.split('.com/')[1];
|
|
|
+
|
|
|
+ if (!key) {
|
|
|
+ throw new Error('Invalid filePath provided');
|
|
|
+ }
|
|
|
+
|
|
|
+ await new Promise<void>((resolve, reject) => {
|
|
|
+ this.client.deleteObject(
|
|
|
+ {
|
|
|
+ Bucket: this.bucket,
|
|
|
+ Region: this.region,
|
|
|
+ Key: key,
|
|
|
+ },
|
|
|
+ (err) => {
|
|
|
+ if (err) {
|
|
|
+ reject(err);
|
|
|
+ } else {
|
|
|
+ resolve();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|