136 lines
5.5 KiB
JavaScript
136 lines
5.5 KiB
JavaScript
"use strict";
|
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
};
|
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
};
|
|
var StorageService_1;
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.StorageService = void 0;
|
|
const common_1 = require("@nestjs/common");
|
|
const config_1 = require("@nestjs/config");
|
|
const crypto_1 = require("crypto");
|
|
const Minio = require("minio");
|
|
let StorageService = StorageService_1 = class StorageService {
|
|
configService;
|
|
logger = new common_1.Logger(StorageService_1.name);
|
|
client;
|
|
publicBucket;
|
|
privateBucket;
|
|
publicUrl;
|
|
constructor(configService) {
|
|
this.configService = configService;
|
|
this.client = new Minio.Client({
|
|
endPoint: this.configService.getOrThrow('minio.endpoint'),
|
|
port: this.configService.get('minio.port', 9000),
|
|
useSSL: this.configService.get('minio.useSsl', false),
|
|
accessKey: this.configService.getOrThrow('minio.accessKey'),
|
|
secretKey: this.configService.getOrThrow('minio.secretKey'),
|
|
});
|
|
this.publicBucket = this.configService.getOrThrow('minio.publicBucket');
|
|
this.privateBucket = this.configService.getOrThrow('minio.privateBucket');
|
|
this.publicUrl = this.configService.get('minio.publicUrl');
|
|
}
|
|
async onModuleInit() {
|
|
await this.ensureBucket(this.publicBucket, true);
|
|
await this.ensureBucket(this.privateBucket, false);
|
|
}
|
|
async uploadPublicFile(file, folder = 'products') {
|
|
return this.upload(file, this.publicBucket, folder);
|
|
}
|
|
async uploadPrivateFile(file, folder = 'products') {
|
|
return this.upload(file, this.privateBucket, folder);
|
|
}
|
|
async deleteFile(bucket, objectName) {
|
|
try {
|
|
await this.client.removeObject(bucket, objectName);
|
|
}
|
|
catch (error) {
|
|
this.logger.warn(`Failed to delete object ${bucket}/${objectName}: ${error instanceof Error ? error.message : 'unknown error'}`);
|
|
}
|
|
}
|
|
async deletePublicFileByUrl(fileUrl) {
|
|
if (!fileUrl) {
|
|
return;
|
|
}
|
|
const objectName = this.extractObjectName(fileUrl, this.publicBucket);
|
|
if (objectName) {
|
|
await this.deleteFile(this.publicBucket, objectName);
|
|
}
|
|
}
|
|
extractObjectName(fileUrl, bucket) {
|
|
if (!fileUrl) {
|
|
return null;
|
|
}
|
|
try {
|
|
const parsedUrl = new URL(fileUrl);
|
|
const prefix = `/${bucket}/`;
|
|
const path = parsedUrl.pathname.startsWith(prefix)
|
|
? parsedUrl.pathname.slice(prefix.length)
|
|
: parsedUrl.pathname.replace(/^\//, '');
|
|
return decodeURIComponent(path);
|
|
}
|
|
catch {
|
|
return null;
|
|
}
|
|
}
|
|
async upload(file, bucket, folder) {
|
|
if (!file) {
|
|
throw new common_1.InternalServerErrorException('File upload payload is empty');
|
|
}
|
|
const objectName = `${folder}/${(0, crypto_1.randomUUID)()}-${file.originalname.replace(/\s+/g, '-')}`;
|
|
try {
|
|
await this.client.putObject(bucket, objectName, file.buffer, file.size, {
|
|
'Content-Type': file.mimetype,
|
|
});
|
|
}
|
|
catch (error) {
|
|
throw new common_1.InternalServerErrorException(`File upload failed: ${error instanceof Error ? error.message : 'unknown error'}`);
|
|
}
|
|
return {
|
|
bucket,
|
|
objectName,
|
|
url: this.buildPublicUrl(bucket, objectName),
|
|
};
|
|
}
|
|
async ensureBucket(bucketName, makePublic) {
|
|
const exists = await this.client.bucketExists(bucketName);
|
|
if (!exists) {
|
|
await this.client.makeBucket(bucketName);
|
|
}
|
|
if (makePublic) {
|
|
await this.client.setBucketPolicy(bucketName, JSON.stringify({
|
|
Version: '2012-10-17',
|
|
Statement: [
|
|
{
|
|
Effect: 'Allow',
|
|
Principal: { AWS: ['*'] },
|
|
Action: ['s3:GetObject'],
|
|
Resource: [`arn:aws:s3:::${bucketName}/*`],
|
|
},
|
|
],
|
|
}));
|
|
}
|
|
}
|
|
buildPublicUrl(bucket, objectName) {
|
|
if (this.publicUrl) {
|
|
return `${this.publicUrl.replace(/\/$/, '')}/${bucket}/${objectName}`;
|
|
}
|
|
const protocol = this.configService.get('minio.useSsl', false)
|
|
? 'https'
|
|
: 'http';
|
|
const endpoint = this.configService.getOrThrow('minio.endpoint');
|
|
const port = this.configService.get('minio.port', 9000);
|
|
return `${protocol}://${endpoint}:${port}/${bucket}/${objectName}`;
|
|
}
|
|
};
|
|
exports.StorageService = StorageService;
|
|
exports.StorageService = StorageService = StorageService_1 = __decorate([
|
|
(0, common_1.Injectable)(),
|
|
__metadata("design:paramtypes", [config_1.ConfigService])
|
|
], StorageService);
|
|
//# sourceMappingURL=storage.service.js.map
|