couteau_suisse/consoleMonitor.js
2025-12-08 21:40:12 +01:00

212 lines
7.3 KiB
JavaScript

const axios = require('axios');
const WebSocket = require('ws');
const { verifyLinkCode, updateUserLinkWithUsername } = require('./database.js');
let ws = null;
let reconnectTimeout = null;
let client = null;
let heartbeatInterval = null;
const parseLogMessage = (log) => {
// Exemple de format de log Palworld:
// [2024.01.15-12:34:56] PlayerName (76561198012345678): !link ABC123
const linkRegex = /\[.*?\]\s*(.+?)\s*\((\d{17})\).*?!link\s+([A-Z0-9]{6})/i;
const match = log.match(linkRegex);
if (match) {
return {
playerName: match[1].trim(),
steamId: match[2],
code: match[3].toUpperCase()
};
}
return null;
};
const handleLinkCommand = async (playerName, steamId, code) => {
try {
console.log(`🔗 Tentative de liaison détectée: ${playerName} (${steamId}) avec le code ${code}`);
const result = await verifyLinkCode(code, steamId, playerName);
if (result.success) {
console.log(`✅ Liaison réussie pour ${playerName}`);
// Envoyer un message de confirmation à l'utilisateur Discord
if (client) {
const user = await client.users.fetch(result.discordId).catch(() => null);
if (user) {
await updateUserLinkWithUsername(result.discordId, user.tag);
await user.send(
`✅ **Liaison réussie !**\n\n` +
`Votre compte Discord a été lié avec succès à votre compte Palworld:\n` +
`🎮 Nom Palworld: **${playerName}**\n` +
`🆔 Steam ID: \`${steamId}\``
).catch(() => {});
}
}
} else {
console.log(`❌ Échec de la liaison: ${result.message}`);
}
} catch (error) {
console.error('Erreur lors du traitement de la commande !link:', error);
}
};
const getWebSocketCredentials = async (pterodactylToken, serverId) => {
try {
const response = await axios({
method: 'get',
url: `${process.env.PTERODACTYL_API_URL}/api/client/servers/${serverId}/websocket`,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${pterodactylToken}`
}
});
return response.data.data;
} catch (error) {
console.error('Erreur lors de la récupération des credentials WebSocket:', error.message);
throw error;
}
};
const connectWebSocket = async (pterodactylToken, serverId) => {
try {
const credentials = await getWebSocketCredentials(pterodactylToken, serverId);
ws = new WebSocket(credentials.socket, {
origin: process.env.PTERODACTYL_API_URL
});
ws.on('open', () => {
console.log('✅ WebSocket Pterodactyl connecté');
// Authentification selon la documentation
ws.send(JSON.stringify({
event: 'auth',
args: [credentials.token]
}));
});
ws.on('message', (data) => {
try {
const message = JSON.parse(data.toString());
// Gérer l'événement d'authentification réussie
if (message.event === 'auth success') {
console.log('✅ Authentification WebSocket réussie');
// S'abonner aux logs de la console
ws.send(JSON.stringify({
event: 'send logs',
args: [null]
}));
// Démarrer le heartbeat (toutes les 30 secondes)
if (heartbeatInterval) clearInterval(heartbeatInterval);
heartbeatInterval = setInterval(() => {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
event: 'send heartbeat',
args: []
}));
}
}, 30000);
}
// Gérer les logs de la console
if (message.event === 'console output') {
const log = message.args[0];
// Afficher le log pour debug
console.log('📝 Log:', log);
// Détecter les commandes !link
const linkData = parseLogMessage(log);
if (linkData) {
handleLinkCommand(linkData.playerName, linkData.steamId, linkData.code);
}
}
// Gérer les événements de statut
if (message.event === 'status') {
console.log('📊 Statut du serveur:', message.args[0]);
}
} catch (error) {
// Message non-JSON ou erreur de parsing, on ignore
console.error('Erreur parsing message WebSocket:', error);
}
});
ws.on('error', (error) => {
console.error('❌ Erreur WebSocket:', error.message);
});
ws.on('close', (code, reason) => {
console.log(`⚠️ WebSocket Pterodactyl déconnecté (Code: ${code}, Raison: ${reason})`);
ws = null;
// Arrêter le heartbeat
if (heartbeatInterval) {
clearInterval(heartbeatInterval);
heartbeatInterval = null;
}
// Reconnexion automatique
if (reconnectTimeout) clearTimeout(reconnectTimeout);
reconnectTimeout = setTimeout(() => {
console.log('🔄 Tentative de reconnexion...');
connectWebSocket(pterodactylToken, serverId);
}, 10000);
});
} catch (error) {
console.error('Erreur lors de la connexion WebSocket:', error);
// Réessayer dans 30 secondes
if (reconnectTimeout) clearTimeout(reconnectTimeout);
reconnectTimeout = setTimeout(() => {
console.log('🔄 Tentative de reconnexion...');
connectWebSocket(pterodactylToken, serverId);
}, 30000);
}
};
const startConsoleMonitoring = (discordClient, pterodactylToken) => {
client = discordClient;
const serverId = process.env.PTERODACTYL_SERVER_ID;
if (!serverId) {
console.error('❌ PTERODACTYL_SERVER_ID non défini dans .env');
return;
}
console.log('🔍 Surveillance de la console Pterodactyl démarrée');
connectWebSocket(pterodactylToken, serverId);
};
const stopConsoleMonitoring = () => {
if (heartbeatInterval) {
clearInterval(heartbeatInterval);
heartbeatInterval = null;
}
if (reconnectTimeout) {
clearTimeout(reconnectTimeout);
reconnectTimeout = null;
}
if (ws) {
ws.close();
ws = null;
}
};
module.exports = { startConsoleMonitoring, stopConsoleMonitoring };