import { ConfigService, S3 } from '@config/env.config'; import { Logger } from '@config/logger.config'; import { BadRequestException } from '@exceptions'; import * as MinIo from 'minio'; import { join } from 'path'; import { Readable, Transform } from 'stream'; const logger = new Logger('S3 Service'); const BUCKET = new ConfigService().get('S3'); interface Metadata extends MinIo.ItemBucketMetadata { 'Content-Type': string; } const minioClient = (() => { if (BUCKET?.ENABLE) { return new MinIo.Client({ endPoint: BUCKET.ENDPOINT, port: BUCKET.PORT, useSSL: BUCKET.USE_SSL, accessKey: BUCKET.ACCESS_KEY, secretKey: BUCKET.SECRET_KEY, region: BUCKET.REGION, }); } })(); const bucketName = BUCKET.BUCKET_NAME; const bucketExists = async () => { if (minioClient) { try { const list = await minioClient.listBuckets(); return list.find((bucket) => bucket.name === bucketName); } catch { return false; } } }; const setBucketPolicy = async () => { if (minioClient) { const policy = { Version: '2012-10-17', Statement: [ { Effect: 'Allow', Principal: '*', Action: ['s3:GetObject'], Resource: [`arn:aws:s3:::${bucketName}/*`], }, ], }; await minioClient.setBucketPolicy(bucketName, JSON.stringify(policy)); } }; const createBucket = async () => { if (minioClient) { try { const exists = await bucketExists(); if (!exists) { await minioClient.makeBucket(bucketName); } if (!BUCKET.SKIP_POLICY) { await setBucketPolicy(); } logger.info(`S3 Bucket ${bucketName} - ON`); return true; } catch (error) { logger.error('S3 ERROR:'); logger.error(error); return false; } } }; createBucket(); const uploadFile = async (fileName: string, file: Buffer | Transform | Readable, size: number, metadata: Metadata) => { if (minioClient) { const objectName = join('evolution-api', fileName); try { metadata['custom-header-application'] = 'evolution-api'; return await minioClient.putObject(bucketName, objectName, file, size, metadata); } catch (error) { logger.error(error); return error; } } }; const getObjectUrl = async (fileName: string, expiry?: number) => { if (minioClient) { try { const objectName = join('evolution-api', fileName); if (expiry) { return await minioClient.presignedGetObject(bucketName, objectName, expiry); } return await minioClient.presignedGetObject(bucketName, objectName); } catch (error) { throw new BadRequestException(error?.message); } } }; const uploadTempFile = async ( folder: string, fileName: string, file: Buffer | Transform | Readable, size: number, metadata: Metadata, ) => { if (minioClient) { const objectName = join(folder, fileName); try { metadata['custom-header-application'] = 'evolution-api'; return await minioClient.putObject(bucketName, objectName, file, size, metadata); } catch (error) { logger.error(error); return error; } } }; const deleteFile = async (folder: string, fileName: string) => { if (minioClient) { const objectName = join(folder, fileName); try { return await minioClient.removeObject(bucketName, objectName); } catch (error) { logger.error(error); return error; } } }; export { BUCKET, deleteFile, getObjectUrl, uploadFile, uploadTempFile };