const axios = require('axios'); const { getConfig } = require('./database'); let isMonitoring = false; let checkInterval = null; let isRebooting = false; let reconnectCallback = null; // Callback pour resync le WebSocket const CHECK_INTERVAL_MS = 60 * 1000; // Vérifier toutes les 60 secondes /** * Vérifie l'utilisation actuelle de la RAM du serveur */ const checkRAMUsage = async () => { try { const response = await axios.get( `${process.env.PTERODACTYL_API_URL}/api/client/servers/${process.env.PTERODACTYL_SERVER_ID}/resources`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.PTERODACTYL_API_TOKEN}` } } ); const resources = response.data.attributes.resources; const ramUsedMB = resources.memory_bytes / (1024 * 1024); // Convertir en MB const ramUsedGB = (ramUsedMB / 1024).toFixed(2); // Convertir en GB pour l'affichage const currentState = response.data.attributes.current_state; console.log(`🔍 [RAM Monitor] Utilisation RAM: ${ramUsedGB} Go / État: ${currentState}`); // Récupérer la configuration depuis la base de données const autoRebootEnabled = (await getConfig('auto_reboot_enabled')) === 'true'; const ramThresholdGB = parseInt(await getConfig('ram_threshold_gb')) || 19; const RAM_THRESHOLD_MB = ramThresholdGB * 1024; // Vérifier si on dépasse le seuil ET que le serveur est en cours d'exécution ET que l'auto-reboot est activé if (autoRebootEnabled && ramUsedMB > RAM_THRESHOLD_MB && currentState === 'running' && !isRebooting) { console.log(`⚠️ [RAM Monitor] SEUIL DÉPASSÉ ! ${ramUsedGB} Go > ${ramThresholdGB} Go`); console.log(`🔄 [RAM Monitor] Déclenchement du redémarrage automatique...`); await rebootServer(); } else if (!autoRebootEnabled && ramUsedMB > RAM_THRESHOLD_MB) { console.log(`⚠️ [RAM Monitor] Seuil dépassé mais auto-reboot désactivé (${ramUsedGB} Go > ${ramThresholdGB} Go)`); } return { ramUsedMB, ramUsedGB, currentState }; } catch (error) { console.error('❌ [RAM Monitor] Erreur lors de la vérification RAM:', error.message); return null; } }; /** * Redémarre le serveur automatiquement */ const rebootServer = async () => { if (isRebooting) { console.log('⚠️ [RAM Monitor] Redémarrage déjà en cours, annulation...'); return; } isRebooting = true; try { const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.PTERODACTYL_API_TOKEN}` }; const serverUrl = `${process.env.PTERODACTYL_API_URL}/api/client/servers/${process.env.PTERODACTYL_SERVER_ID}`; console.log('💾 [RAM Monitor] Sauvegarde du serveur...'); await axios.post(`${serverUrl}/command`, { command: 'save' }, { headers }); // Annoncer le redémarrage aux joueurs console.log('📢 [RAM Monitor] Annonce du redémarrage...'); await axios.post(`${serverUrl}/command`, { command: "broadcast 'Redémarrage automatique (RAM élevée - 60 secondes)'" }, { headers }); // Attendre la sauvegarde await new Promise(resolve => setTimeout(resolve, 3000)); console.log('⏹️ [RAM Monitor] Arrêt du serveur...'); await axios.post(`${serverUrl}/power`, { signal: 'stop' }, { headers }); // Attendre 60 secondes console.log('⏳ [RAM Monitor] Attente de 60 secondes...'); await new Promise(resolve => setTimeout(resolve, 60000)); console.log('🚀 [RAM Monitor] Redémarrage du serveur...'); await axios.post(`${serverUrl}/power`, { signal: 'start' }, { headers }); // Attendre que le serveur soit opérationnel let isRunning = false; let attempts = 0; const maxAttempts = 30; // 30 tentatives * 5 secondes = 2.5 minutes max while (!isRunning && attempts < maxAttempts) { attempts++; await new Promise(resolve => setTimeout(resolve, 5000)); try { const checkResponse = await axios.get(`${serverUrl}/resources`, { headers }); const state = checkResponse.data.attributes.current_state; if (state === 'running') { isRunning = true; console.log('✅ [RAM Monitor] Serveur redémarré avec succès !'); // Resynchroniser le WebSocket si un callback est défini if (reconnectCallback) { console.log('🔄 [RAM Monitor] Resynchronisation du WebSocket...'); await new Promise(resolve => setTimeout(resolve, 5000)); // Attendre 5s de plus reconnectCallback(); } } } catch (error) { console.error(`❌ [RAM Monitor] Tentative ${attempts}/${maxAttempts} échouée:`, error.message); } } if (!isRunning) { console.error('❌ [RAM Monitor] Le serveur n\'a pas redémarré après le délai maximum'); } } catch (error) { console.error('❌ [RAM Monitor] Erreur lors du redémarrage:', error.message); } finally { isRebooting = false; } }; /** * Démarre la surveillance de la RAM */ const startRAMMonitoring = async (websocketReconnectCallback = null) => { if (isMonitoring) { console.log('⚠️ [RAM Monitor] Surveillance déjà active'); return; } reconnectCallback = websocketReconnectCallback; const ramThresholdGB = parseInt(await getConfig('ram_threshold_gb')) || 19; console.log(`🚀 [RAM Monitor] Démarrage de la surveillance RAM (seuil: ${ramThresholdGB} Go)`); console.log(`⏱️ [RAM Monitor] Intervalle de vérification: ${CHECK_INTERVAL_MS / 1000}s`); isMonitoring = true; // Première vérification immédiate checkRAMUsage(); // Vérifications périodiques checkInterval = setInterval(async () => { if (!isRebooting) { await checkRAMUsage(); } }, CHECK_INTERVAL_MS); }; /** * Arrête la surveillance de la RAM */ const stopRAMMonitoring = () => { if (!isMonitoring) { console.log('⚠️ [RAM Monitor] Surveillance déjà inactive'); return; } console.log('⏹️ [RAM Monitor] Arrêt de la surveillance RAM'); isMonitoring = false; if (checkInterval) { clearInterval(checkInterval); checkInterval = null; } }; /** * Obtenir le statut de la surveillance */ const getMonitoringStatus = async () => { const ramThresholdGB = parseInt(await getConfig('ram_threshold_gb')) || 19; return { isMonitoring, isRebooting, threshold: ramThresholdGB * 1024, // En MB checkInterval: CHECK_INTERVAL_MS }; }; module.exports = { startRAMMonitoring, stopRAMMonitoring, checkRAMUsage, getMonitoringStatus };