banatie-service/apps/api-service/src/services/StorageFactory.ts

114 lines
3.2 KiB
TypeScript

import { StorageService } from './StorageService';
import { MinioStorageService } from './MinioStorageService';
export class StorageFactory {
private static instance: StorageService | null = null;
private static initializationPromise: Promise<StorageService> | null = null;
static async getInstance(): Promise<StorageService> {
if (this.instance) {
return this.instance;
}
if (this.initializationPromise) {
return await this.initializationPromise;
}
this.initializationPromise = this.createStorageServiceWithRetry();
try {
this.instance = await this.initializationPromise;
return this.instance;
} catch (error) {
this.initializationPromise = null;
throw error;
}
}
static getInstanceSync(): StorageService {
if (!this.instance) {
try {
this.instance = this.createStorageService();
} catch (error) {
throw new Error('Storage service unavailable. Please check MinIO configuration.');
}
}
return this.instance;
}
private static async createStorageServiceWithRetry(): Promise<StorageService> {
const maxRetries = 3;
const baseDelay = 1000; // 1 second
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const service = this.createStorageService();
await service.bucketExists();
return service;
} catch (error) {
if (attempt === maxRetries) {
throw new Error(
`Failed to initialize storage service after ${maxRetries} attempts. ` +
`Last error: ${error instanceof Error ? error.message : 'Unknown error'}`,
);
}
const delay = baseDelay * Math.pow(2, attempt - 1);
await this.sleep(delay);
}
}
throw new Error('Unexpected error in storage service creation');
}
private static sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
private static createStorageService(): StorageService {
const storageType = process.env['STORAGE_TYPE'] || 'minio';
try {
switch (storageType.toLowerCase()) {
case 'minio': {
const endpoint = process.env['MINIO_ENDPOINT'];
const accessKey = process.env['MINIO_ACCESS_KEY'];
const secretKey = process.env['MINIO_SECRET_KEY'];
const useSSL = process.env['MINIO_USE_SSL'] === 'true';
const bucketName = process.env['MINIO_BUCKET_NAME'] || 'banatie';
const publicUrl = process.env['MINIO_PUBLIC_URL'];
console.log(`[StorageFactory] Creating MinIO client with endpoint: ${endpoint}`);
if (!endpoint || !accessKey || !secretKey) {
throw new Error(
'MinIO configuration missing. Required: MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY',
);
}
return new MinioStorageService(
endpoint,
accessKey,
secretKey,
useSSL,
bucketName,
publicUrl,
);
}
default:
throw new Error(`Unsupported storage type: ${storageType}`);
}
} catch (error) {
throw error;
}
}
static resetInstance(): void {
this.instance = null;
this.initializationPromise = null;
}
}