// ======================================== // FICHIER: server.js - POINT D'ENTRÉE MODES EXCLUSIFS // RESPONSABILITÉ: Démarrage serveur avec sélection mode MANUAL/AUTO // MODES: MANUAL (interface client) | AUTO (batch GSheets) // ======================================== require('dotenv').config(); const { logSh } = require('./lib/ErrorReporting'); const { ModeManager } = require('./lib/modes/ModeManager'); /** * SERVEUR SEO GENERATOR - MODES EXCLUSIFS * Point d'entrée unique pour démarrer en mode MANUAL ou AUTO */ class SEOGeneratorServer { constructor() { this.startTime = Date.now(); this.isShuttingDown = false; } /** * Démarrage principal du serveur */ async start() { try { // Banner de démarrage this.displayStartupBanner(); // Gestion signaux système this.setupSignalHandlers(); // Initialisation du gestionnaire de modes const mode = await ModeManager.initialize(); logSh(`🎯 Serveur démarré en mode ${mode.toUpperCase()}`, 'INFO'); logSh(`⏱️ Temps de démarrage: ${Date.now() - this.startTime}ms`, 'DEBUG'); // Monitoring périodique this.startHealthMonitoring(); return mode; } catch (error) { logSh(`❌ ÉCHEC DÉMARRAGE SERVEUR: ${error.message}`, 'ERROR'); logSh(`Stack trace: ${error.stack}`, 'ERROR'); await this.gracefulShutdown(1); } } /** * Affiche la bannière de démarrage */ displayStartupBanner() { const version = require('./package.json').version || '1.0.0'; const nodeVersion = process.version; const platform = process.platform; console.log(` ╔════════════════════════════════════════════════════════════╗ ║ SEO GENERATOR SERVER ║ ║ MODES EXCLUSIFS ║ ╠════════════════════════════════════════════════════════════╣ ║ Version: ${version.padEnd(10)} │ Node: ${nodeVersion.padEnd(10)} │ OS: ${platform.padEnd(8)} ║ ║ ║ ║ 🎯 MANUAL MODE: Interface Client + API + WebSocket ║ ║ 🤖 AUTO MODE: Traitement Batch Google Sheets ║ ║ ║ ║ 💡 Utilisation: ║ ║ npm start (défaut: MANUAL) ║ ║ npm start -- --mode=manual ║ ║ npm start -- --mode=auto ║ ║ SERVER_MODE=auto npm start ║ ╚════════════════════════════════════════════════════════════╝ `); logSh('🚀 === SEO GENERATOR SERVER - DÉMARRAGE ===', 'INFO'); logSh(`📦 Version: ${version} | Node: ${nodeVersion}`, 'INFO'); } /** * Configure la gestion des signaux système */ setupSignalHandlers() { // Arrêt propre sur SIGTERM/SIGINT process.on('SIGTERM', () => this.handleShutdownSignal('SIGTERM')); process.on('SIGINT', () => this.handleShutdownSignal('SIGINT')); // Gestion erreurs non capturées process.on('uncaughtException', (error) => { logSh(`❌ ERREUR NON CAPTURÉE: ${error.message}`, 'ERROR'); logSh(`Stack: ${error.stack}`, 'ERROR'); this.gracefulShutdown(1); }); process.on('unhandledRejection', (reason, promise) => { logSh(`❌ PROMESSE REJETÉE: ${reason}`, 'ERROR'); logSh(`Promise: ${promise}`, 'DEBUG'); // Ne pas arrêter pour les rejections non gérées, juste logger }); } /** * Gère les signaux d'arrêt */ async handleShutdownSignal(signal) { logSh(`🛑 Signal reçu: ${signal}`, 'INFO'); await this.gracefulShutdown(0); } /** * Arrêt propre du serveur */ async gracefulShutdown(exitCode = 0) { if (this.isShuttingDown) { logSh('⚠️ Arrêt déjà en cours...', 'WARNING'); return; } this.isShuttingDown = true; const shutdownStart = Date.now(); logSh('🛑 ARRÊT SERVEUR EN COURS...', 'INFO'); try { // Arrêter le monitoring if (this.healthInterval) { clearInterval(this.healthInterval); } // Arrêter le mode actuel via ModeManager await ModeManager.stopCurrentMode(); // Nettoyage final await this.finalCleanup(); const shutdownDuration = Date.now() - shutdownStart; const totalUptime = Date.now() - this.startTime; logSh(`✅ Arrêt terminé (${shutdownDuration}ms)`, 'INFO'); logSh(`⏱️ Uptime total: ${Math.floor(totalUptime / 1000)}s`, 'INFO'); logSh('👋 Au revoir !', 'INFO'); } catch (error) { logSh(`❌ Erreur durant arrêt: ${error.message}`, 'ERROR'); exitCode = 1; } // Attendre un peu pour que les logs se finalisent setTimeout(() => { process.exit(exitCode); }, 100); } /** * Nettoyage final avant arrêt */ async finalCleanup() { try { // Sauvegarder l'état final ModeManager.saveModeState(); // Autres nettoyages si nécessaire } catch (error) { logSh(`⚠️ Erreur nettoyage final: ${error.message}`, 'WARNING'); } } /** * Démarre le monitoring de santé */ startHealthMonitoring() { const HEALTH_CHECK_INTERVAL = 30000; // 30 secondes this.healthInterval = setInterval(() => { try { this.performHealthCheck(); } catch (error) { logSh(`⚠️ Erreur health check: ${error.message}`, 'WARNING'); } }, HEALTH_CHECK_INTERVAL); logSh('💓 Health monitoring démarré', 'DEBUG'); } /** * Vérifie la santé du système */ performHealthCheck() { const status = ModeManager.getStatus(); const memUsage = process.memoryUsage(); const uptime = process.uptime(); // Log périodique de l'état logSh(`💓 Health Check - Mode: ${status.currentMode} | Uptime: ${Math.floor(uptime)}s | RAM: ${Math.round(memUsage.rss / 1024 / 1024)}MB`, 'TRACE'); // Vérifications critiques if (memUsage.rss > 1024 * 1024 * 1024) { // > 1GB logSh('⚠️ Utilisation mémoire élevée', 'WARNING'); } if (!status.currentMode) { logSh('⚠️ Aucun mode actif détecté', 'WARNING'); } } /** * API pour changer de mode (si nécessaire) */ async switchMode(newMode, force = false) { logSh(`🔄 Demande changement mode vers: ${newMode}`, 'INFO'); try { await ModeManager.switchToMode(newMode, force); logSh(`✅ Changement mode réussi vers: ${newMode}`, 'INFO'); return true; } catch (error) { logSh(`❌ Échec changement mode: ${error.message}`, 'ERROR'); throw error; } } /** * Retourne le statut actuel */ getStatus() { return { server: { startTime: this.startTime, uptime: Date.now() - this.startTime, isShuttingDown: this.isShuttingDown, nodeVersion: process.version, platform: process.platform, pid: process.pid }, mode: ModeManager.getStatus(), memory: process.memoryUsage(), timestamp: new Date().toISOString() }; } } // ======================================== // DÉMARRAGE AUTOMATIQUE // ======================================== // Démarrer le serveur si ce fichier est exécuté directement if (require.main === module) { const server = new SEOGeneratorServer(); server.start().catch((error) => { console.error('💥 ERREUR CRITIQUE DÉMARRAGE:', error.message); process.exit(1); }); } // ============= EXPORTS ============= module.exports = { SEOGeneratorServer };