2026-02-04 20:18:45 +01:00

310 lines
11 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require('discord.js');
const { getConfig, updateConfig, getAllConfig } = require('../../database');
const { getMonitoringStatus } = require('../../ramMonitor');
module.exports = {
data: new SlashCommandBuilder()
.setName('panel')
.setDescription('Panneau de configuration du bot'),
async execute(interaction) {
// Vérifier les permissions
if (!interaction.member.roles.cache.has('1444684935632912394')) {
await interaction.reply({
content: '❌ Il faut avoir le rôle Rygainland pour accéder au panneau de configuration.',
flags: 64
});
return;
}
await showPanel(interaction);
}
};
function hasPanelRole(member) {
return Boolean(member?.roles?.cache?.has('1444684935632912394'));
}
async function buildPanelPayload() {
const config = await getAllConfig();
const monitoringStatus = getMonitoringStatus();
const autoRebootEnabled = config.auto_reboot_enabled === 'true';
const ramThreshold = Number.parseInt(config.ram_threshold_gb, 10);
const consoleMonitorEnabled = config.console_monitor_enabled === 'true';
const embed = new EmbedBuilder()
.setColor(0x0099FF)
.setTitle('⚙️ Panneau de Configuration')
.setDescription('Gérez les paramètres du bot et du serveur')
.addFields(
{
name: '🔄 Redémarrage Automatique',
value: `**État:** ${autoRebootEnabled ? '✅ Activé' : '❌ Désactivé'}\n**Seuil RAM:** ${ramThreshold} Go\n**Surveillance:** ${monitoringStatus.isMonitoring ? '🟢 Active' : '🔴 Inactive'}`,
inline: true
},
{
name: '📊 Surveillance Console',
value: `**État:** ${consoleMonitorEnabled ? '✅ Activée' : '❌ Désactivée'}`,
inline: true
},
{
name: '📈 Statistiques',
value: `**En redémarrage:** ${monitoringStatus.isRebooting ? 'Oui' : 'Non'}\n**Intervalle:** ${monitoringStatus.checkInterval / 1000}s`,
inline: false
}
)
.setTimestamp()
.setFooter({ text: 'Panneau de Configuration' });
const row1 = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('toggle_auto_reboot')
.setLabel(autoRebootEnabled ? 'Désactiver Auto-Reboot' : 'Activer Auto-Reboot')
.setStyle(autoRebootEnabled ? ButtonStyle.Danger : ButtonStyle.Success)
.setEmoji(autoRebootEnabled ? '⏹️' : '▶️'),
new ButtonBuilder()
.setCustomId('toggle_console_monitor')
.setLabel(consoleMonitorEnabled ? 'Désactiver Console' : 'Activer Console')
.setStyle(consoleMonitorEnabled ? ButtonStyle.Danger : ButtonStyle.Success)
.setEmoji(consoleMonitorEnabled ? '📵' : '📱')
);
const row2 = new ActionRowBuilder()
.addComponents(
new StringSelectMenuBuilder()
.setCustomId('change_ram_threshold')
.setPlaceholder(`Seuil RAM actuel: ${ramThreshold} Go`)
.addOptions([
{
label: '15 Go',
description: 'Redémarrage à 15 Go de RAM',
value: '15',
emoji: '🔵'
},
{
label: '17 Go',
description: 'Redémarrage à 17 Go de RAM',
value: '17',
emoji: '🟢'
},
{
label: '19 Go (défaut)',
description: 'Redémarrage à 19 Go de RAM',
value: '19',
emoji: '🟡',
default: ramThreshold === 19
},
{
label: '21 Go',
description: 'Redémarrage à 21 Go de RAM',
value: '21',
emoji: '🟠'
},
{
label: '23 Go',
description: 'Redémarrage à 23 Go de RAM',
value: '23',
emoji: '🔴'
},
{
label: '25 Go',
description: 'Redémarrage à 25 Go de RAM',
value: '25',
emoji: '🔴'
}
])
);
const row3 = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('refresh_panel')
.setLabel('Actualiser')
.setStyle(ButtonStyle.Secondary)
.setEmoji('🔄'),
new ButtonBuilder()
.setCustomId('view_stats')
.setLabel('Voir Stats Détaillées')
.setStyle(ButtonStyle.Primary)
.setEmoji('📊')
);
return { embeds: [embed], components: [row1, row2, row3], content: null };
}
async function buildStatsPayload() {
const config = await getAllConfig();
const monitoringStatus = getMonitoringStatus();
const { checkRAMUsage } = require('../../ramMonitor');
const ramData = await checkRAMUsage();
const embed = new EmbedBuilder()
.setColor(0x00FF00)
.setTitle('📊 Statistiques Détaillées du Monitoring')
.setDescription('Informations en temps réel sur le serveur')
.addFields(
{
name: '🎮 État du Serveur',
value: ramData ? `**État:** ${ramData.currentState}\n**RAM:** ${ramData.ramUsedGB} Go / ${config.ram_threshold_gb} Go` : 'Impossible de récupérer les données',
inline: true
},
{
name: '⚙️ Configuration',
value: `**Auto-Reboot:** ${config.auto_reboot_enabled === 'true' ? 'Oui' : 'Non'}\n**Seuil:** ${config.ram_threshold_gb} Go\n**Console:** ${config.console_monitor_enabled === 'true' ? 'Active' : 'Inactive'}`,
inline: true
},
{
name: '🔄 Surveillance',
value: `**Active:** ${monitoringStatus.isMonitoring ? 'Oui' : 'Non'}\n**En reboot:** ${monitoringStatus.isRebooting ? 'Oui' : 'Non'}\n**Intervalle:** ${monitoringStatus.checkInterval / 1000}s`,
inline: false
}
)
.setTimestamp()
.setFooter({ text: 'Statistiques en temps réel' });
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('back_to_panel')
.setLabel('Retour au Panel')
.setStyle(ButtonStyle.Secondary)
.setEmoji('◀️')
);
return { embeds: [embed], components: [row], content: null };
}
function isIgnorableDiscordRestError(error) {
const code = error?.code ?? error?.rawError?.code;
return code === 10062 || code === 40060;
}
async function safeDeferUpdate(interaction) {
if (interaction?.deferred || interaction?.replied) return;
try {
await interaction.deferUpdate();
} catch (e) {
if (!isIgnorableDiscordRestError(e)) throw e;
}
}
async function renderPanel(interaction) {
const payload = await buildPanelPayload();
// Premier affichage via la commande slash
if (interaction.isChatInputCommand?.()) {
if (interaction.replied || interaction.deferred) {
await interaction.editReply(payload);
return interaction.fetchReply();
}
return interaction.reply({ ...payload, fetchReply: true });
}
// Refresh via composants: on édite directement le message
await safeDeferUpdate(interaction);
return interaction.message.edit(payload);
}
async function renderDetailedStats(interaction) {
// IMPORTANT: defer immédiatement pour éviter 10062 si les appels réseau sont lents
await safeDeferUpdate(interaction);
const payload = await buildStatsPayload();
if (interaction.isChatInputCommand?.()) {
if (interaction.replied || interaction.deferred) {
await interaction.editReply(payload);
return interaction.fetchReply();
}
return interaction.reply({ ...payload, fetchReply: true });
}
return interaction.message.edit(payload);
}
// Point d'entrée: affiche le panel et attache un collector AU message
async function showPanel(interaction) {
const message = await renderPanel(interaction);
const collector = message.createMessageComponentCollector({
time: 300000 // 5 minutes
});
collector.on('collect', async i => {
if (!hasPanelRole(i.member)) {
try {
await i.reply({
content: '❌ Vous n\'avez pas la permission d\'utiliser ce panneau.',
flags: 64
});
} catch {
// ignore
}
return;
}
try {
switch (i.customId) {
case 'toggle_auto_reboot': {
await safeDeferUpdate(i);
const currentState = (await getConfig('auto_reboot_enabled')) === 'true';
await updateConfig('auto_reboot_enabled', (!currentState).toString());
await renderPanel(i);
break;
}
case 'toggle_console_monitor': {
await safeDeferUpdate(i);
const currentState = (await getConfig('console_monitor_enabled')) === 'true';
await updateConfig('console_monitor_enabled', (!currentState).toString());
await renderPanel(i);
break;
}
case 'change_ram_threshold': {
await safeDeferUpdate(i);
const newThreshold = i.values?.[0];
if (newThreshold) {
await updateConfig('ram_threshold_gb', newThreshold);
}
await renderPanel(i);
break;
}
case 'refresh_panel': {
await safeDeferUpdate(i);
await renderPanel(i);
break;
}
case 'view_stats': {
await renderDetailedStats(i);
break;
}
case 'back_to_panel': {
await safeDeferUpdate(i);
await renderPanel(i);
break;
}
default: {
await safeDeferUpdate(i);
break;
}
}
} catch (error) {
console.error('Erreur lors de l\'interaction avec le panel:', error);
if (isIgnorableDiscordRestError(error)) return;
// Ne pas crash le process si une réponse échoue
try {
await i.followUp?.({ content: '❌ Une erreur est survenue', flags: 64 });
} catch {
// ignore
}
}
});
collector.on('end', () => {
console.log('⏰ [Panel] Collector expiré');
});
}