import { StorageService } from './StorageService'; import { MinioStorageService } from './MinioStorageService'; export class StorageFactory { private static instance: StorageService | null = null; private static initializationPromise: Promise | null = null; static async getInstance(): Promise { 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 { 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 { 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; } }