79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import {
|
|
DeleteObjectCommand,
|
|
PutObjectCommand,
|
|
S3Client,
|
|
} from '@aws-sdk/client-s3';
|
|
import { BadRequestRpcException } from '@freeblox/shared';
|
|
import { HttpRequest } from '@aws-sdk/protocol-http';
|
|
import { S3RequestPresigner } from '@aws-sdk/s3-request-presigner';
|
|
import { parseUrl } from '@aws-sdk/url-parser';
|
|
import { formatUrl } from '@aws-sdk/util-format-url';
|
|
import { Hash } from '@aws-sdk/hash-node';
|
|
import { fromEnv } from '@aws-sdk/credential-providers';
|
|
|
|
@Injectable()
|
|
export class S3Service implements OnModuleInit {
|
|
private s3: S3Client;
|
|
private presigner: S3RequestPresigner;
|
|
|
|
constructor(private config: ConfigService) {}
|
|
|
|
onModuleInit() {
|
|
const s3Config = this.config.get('s3');
|
|
this.s3 = new S3Client({
|
|
...s3Config,
|
|
});
|
|
this.presigner = new S3RequestPresigner({
|
|
credentials: fromEnv(),
|
|
region: s3Config.region,
|
|
sha256: Hash.bind(null, 'sha256'),
|
|
});
|
|
}
|
|
|
|
async uploadFile(key: string, data: Buffer, bucket?: string) {
|
|
try {
|
|
const command = new PutObjectCommand({
|
|
Key: key,
|
|
Bucket: bucket || this.config.get('s3.bucket'),
|
|
Body: data,
|
|
});
|
|
await this.s3.send(command);
|
|
} catch (error) {
|
|
throw new BadRequestRpcException(`Upload failed: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async getFileUrl(key: string, bucket?: string) {
|
|
const s3Config = this.config.get('s3');
|
|
bucket = bucket || s3Config.bucket;
|
|
|
|
let url: ReturnType<typeof parseUrl>;
|
|
if (s3Config.endpoint) {
|
|
url = parseUrl(`${s3Config.endpoint}/${bucket}/${key}`);
|
|
} else {
|
|
url = parseUrl(
|
|
`https://${bucket}.s3${
|
|
s3Config.region ? '-' + s3Config.region : ''
|
|
}.amazonaws.com/${key}`,
|
|
);
|
|
}
|
|
|
|
const signedUrlObject = await this.presigner.presign(new HttpRequest(url));
|
|
return formatUrl(signedUrlObject);
|
|
}
|
|
|
|
async deleteFile(key: string, bucket?: string) {
|
|
try {
|
|
const command = new DeleteObjectCommand({
|
|
Key: key,
|
|
Bucket: bucket || this.config.get('s3.bucket'),
|
|
});
|
|
await this.s3.send(command);
|
|
} catch {
|
|
throw new BadRequestRpcException('Delete failed');
|
|
}
|
|
}
|
|
}
|