// ======================================== // BATCH CONTROLLER - API ENDPOINTS // Responsabilité: Gestion API pour traitement batch avec configuration pipeline // ======================================== const { logSh } = require('../ErrorReporting'); const fs = require('fs').promises; const path = require('path'); const { BatchProcessor } = require('./BatchProcessor'); const { DigitalOceanTemplates } = require('./DigitalOceanTemplates'); /** * BATCH CONTROLLER * Gestion complète de l'interface de traitement batch */ class BatchController { constructor() { this.configPath = path.join(__dirname, '../../config/batch-config.json'); this.statusPath = path.join(__dirname, '../../config/batch-status.json'); // Initialiser les composants Phase 2 this.batchProcessor = new BatchProcessor(); this.digitalOceanTemplates = new DigitalOceanTemplates(); // Configuration par défaut this.defaultConfig = { selective: 'standardEnhancement', adversarial: 'light', humanSimulation: 'none', patternBreaking: 'none', intensity: 1.0, rowRange: { start: 2, end: 10 }, saveIntermediateSteps: false, lastUpdated: new Date().toISOString() }; // État par défaut this.defaultStatus = { status: 'idle', currentRow: null, totalRows: 0, progress: 0, startTime: null, estimatedEnd: null, errors: [], lastResult: null, config: this.defaultConfig }; this.initializeFiles(); } /** * Initialise les fichiers de configuration */ async initializeFiles() { try { // Créer le dossier config s'il n'existe pas const configDir = path.dirname(this.configPath); await fs.mkdir(configDir, { recursive: true }); // Créer config par défaut si inexistant try { await fs.access(this.configPath); } catch { await fs.writeFile(this.configPath, JSON.stringify(this.defaultConfig, null, 2)); logSh('📝 Configuration batch par défaut créée', 'DEBUG'); } // Créer status par défaut si inexistant try { await fs.access(this.statusPath); } catch { await fs.writeFile(this.statusPath, JSON.stringify(this.defaultStatus, null, 2)); logSh('📊 Status batch par défaut créé', 'DEBUG'); } } catch (error) { logSh(`❌ Erreur initialisation fichiers batch: ${error.message}`, 'ERROR'); } } // ======================================== // ENDPOINTS CONFIGURATION // ======================================== /** * GET /api/batch/config * Récupère la configuration actuelle */ async getConfig(req, res) { try { // Utiliser la nouvelle API du BatchProcessor refactorisé const status = this.batchProcessor.getExtendedStatus(); logSh('📋 Configuration batch récupérée', 'DEBUG'); res.json({ success: true, config: status.config, availableOptions: status.availableOptions }); } catch (error) { logSh(`❌ Erreur récupération config: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur récupération configuration', details: error.message }); } } /** * POST /api/batch/config * Sauvegarde la configuration */ async saveConfig(req, res) { try { const newConfig = req.body; // Utiliser la nouvelle API du BatchProcessor refactorisé const result = await this.batchProcessor.updateConfiguration(newConfig); res.json({ success: true, message: 'Configuration sauvegardée avec succès', config: result.config }); } catch (error) { logSh(`❌ Erreur sauvegarde config: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur sauvegarde configuration', details: error.message }); } } // ======================================== // ENDPOINTS CONTRÔLE TRAITEMENT // ======================================== /** * POST /api/batch/start * Démarre le traitement batch */ async startBatch(req, res) { try { // Démarrer le traitement via BatchProcessor const status = await this.batchProcessor.start(); logSh(`🚀 Traitement batch démarré - ${status.totalRows} lignes`, 'INFO'); res.json({ success: true, message: 'Traitement batch démarré', status: status }); } catch (error) { logSh(`❌ Erreur démarrage batch: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur démarrage traitement', details: error.message }); } } /** * POST /api/batch/stop * Arrête le traitement batch */ async stopBatch(req, res) { try { const status = await this.batchProcessor.stop(); logSh('🛑 Traitement batch arrêté', 'INFO'); res.json({ success: true, message: 'Traitement batch arrêté', status: status }); } catch (error) { logSh(`❌ Erreur arrêt batch: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur arrêt traitement', details: error.message }); } } /** * POST /api/batch/pause * Met en pause le traitement */ async pauseBatch(req, res) { try { const status = await this.batchProcessor.pause(); logSh('⏸️ Traitement batch mis en pause', 'INFO'); res.json({ success: true, message: 'Traitement mis en pause', status: status }); } catch (error) { logSh(`❌ Erreur pause batch: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur pause traitement', details: error.message }); } } /** * POST /api/batch/resume * Reprend le traitement */ async resumeBatch(req, res) { try { const status = await this.batchProcessor.resume(); logSh('▶️ Traitement batch repris', 'INFO'); res.json({ success: true, message: 'Traitement repris', status: status }); } catch (error) { logSh(`❌ Erreur reprise batch: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur reprise traitement', details: error.message }); } } // ======================================== // ENDPOINTS MONITORING // ======================================== /** * GET /api/batch/status * Récupère l'état actuel du traitement */ async getStatus(req, res) { try { const status = this.batchProcessor.getStatus(); res.json({ success: true, status: status, timestamp: new Date().toISOString() }); } catch (error) { logSh(`❌ Erreur récupération status: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur récupération status', details: error.message }); } } /** * GET /api/batch/progress * Récupère la progression détaillée */ async getProgress(req, res) { try { const progress = this.batchProcessor.getProgress(); res.json({ success: true, progress: progress, timestamp: new Date().toISOString() }); } catch (error) { logSh(`❌ Erreur récupération progress: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur récupération progression', details: error.message }); } } // ======================================== // ENDPOINTS DIGITAL OCEAN // ======================================== /** * GET /api/batch/templates * Liste les templates disponibles */ async getTemplates(req, res) { try { const templates = await this.digitalOceanTemplates.listAvailableTemplates(); const stats = this.digitalOceanTemplates.getCacheStats(); res.json({ success: true, templates: templates, cacheStats: stats, timestamp: new Date().toISOString() }); } catch (error) { logSh(`❌ Erreur récupération templates: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur récupération templates', details: error.message }); } } /** * GET /api/batch/templates/:filename * Récupère un template spécifique */ async getTemplate(req, res) { try { const { filename } = req.params; const template = await this.digitalOceanTemplates.getTemplate(filename); res.json({ success: true, filename: filename, template: template, timestamp: new Date().toISOString() }); } catch (error) { logSh(`❌ Erreur récupération template ${req.params.filename}: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur récupération template', details: error.message }); } } /** * DELETE /api/batch/cache * Vide le cache des templates */ async clearCache(req, res) { try { await this.digitalOceanTemplates.clearCache(); res.json({ success: true, message: 'Cache vidé avec succès', timestamp: new Date().toISOString() }); } catch (error) { logSh(`❌ Erreur vidage cache: ${error.message}`, 'ERROR'); res.status(500).json({ success: false, error: 'Erreur vidage cache', details: error.message }); } } } // ============= EXPORTS ============= module.exports = { BatchController };