couteau_suisse/ramMonitor.js
2026-02-03 22:00:54 +01:00

210 lines
7.2 KiB
JavaScript

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
};