const mysql = require('mysql2/promise'); let pool; const initDatabase = async () => { try { pool = mysql.createPool({ host: process.env.DB_HOST, port: process.env.DB_PORT, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, waitForConnections: true, connectionLimit: 10, queueLimit: 0 }); console.log('✅ Base de données connectée'); await createTables(); console.log('✅ Tables créées/vérifiées'); } catch (error) { console.error('❌ Erreur de connexion à la base de données:', error); throw error; } }; const getConnection = () => { if (!pool) { throw new Error('La base de données n\'est pas initialisée'); } return pool; }; const createTables = async () => { const connection = getConnection(); // Table pour les codes de liaison temporaires await connection.execute(` CREATE TABLE IF NOT EXISTS link_codes ( id INT AUTO_INCREMENT PRIMARY KEY, discord_id VARCHAR(20) NOT NULL, code VARCHAR(6) NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP NOT NULL, used BOOLEAN DEFAULT FALSE, INDEX idx_code (code), INDEX idx_discord_id (discord_id) ) `); // Table pour les liaisons confirmées await connection.execute(` CREATE TABLE IF NOT EXISTS user_links ( id INT AUTO_INCREMENT PRIMARY KEY, discord_id VARCHAR(20) NOT NULL UNIQUE, discord_username VARCHAR(100) NOT NULL, steam_id VARCHAR(50) NOT NULL, player_id VARCHAR(50), palworld_username VARCHAR(100) NOT NULL, linked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, lastConnection TIMESTAMP NULL DEFAULT NULL, INDEX idx_discord_id (discord_id), INDEX idx_steam_id (steam_id), INDEX idx_player_id (player_id) ) `); // Table pour la configuration du bot await connection.execute(` CREATE TABLE IF NOT EXISTS bot_config ( id INT AUTO_INCREMENT PRIMARY KEY, config_key VARCHAR(50) NOT NULL UNIQUE, config_value VARCHAR(255) NOT NULL, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_config_key (config_key) ) `); // Initialiser les valeurs par défaut await connection.execute(` INSERT IGNORE INTO bot_config (config_key, config_value) VALUES ('auto_reboot_enabled', 'true'), ('ram_threshold_gb', '19'), ('console_monitor_enabled', 'true') `); }; const generateLinkCode = async (discordId) => { const connection = getConnection(); const code = Math.random().toString(36).substring(2, 8).toUpperCase(); const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes await connection.execute( 'INSERT INTO link_codes (discord_id, code, expires_at) VALUES (?, ?, ?)', [discordId, code, expiresAt] ); return code; }; const verifyLinkCode = async (code, steamId, palworldUsername, playerId = null) => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT * FROM link_codes WHERE code = ? AND used = FALSE AND expires_at > NOW()', [code] ); if (rows.length === 0) { return { success: false, message: 'Code invalide ou expiré' }; } const linkData = rows[0]; // Créer la liaison avec player_id await connection.execute( 'INSERT INTO user_links (discord_id, discord_username, steam_id, player_id, palworld_username) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE steam_id = ?, player_id = ?, palworld_username = ?', [linkData.discord_id, 'temp', steamId, playerId, palworldUsername, steamId, playerId, palworldUsername] ); // Marquer le code comme utilisé await connection.execute( 'UPDATE link_codes SET used = TRUE WHERE code = ?', [code] ); return { success: true, discordId: linkData.discord_id }; }; const getAllLinks = async () => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT discord_id, discord_username, steam_id, player_id, palworld_username, lastConnection, linked_at FROM user_links ORDER BY discord_username' ); return rows; }; const getUserLink = async (discordId) => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT * FROM user_links WHERE discord_id = ?', [discordId] ); return rows.length > 0 ? rows[0] : null; }; const updateUserLinkWithUsername = async (discordId, discordUsername) => { const connection = getConnection(); await connection.execute( 'UPDATE user_links SET discord_username = ? WHERE discord_id = ?', [discordUsername, discordId] ); }; const deleteUserLink = async (discordId) => { const connection = getConnection(); await connection.execute( 'DELETE FROM user_links WHERE discord_id = ?', [discordId] ); }; const getPendingPlayer = async (steamId) => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT * FROM pending_players WHERE steam_id = ?', [steamId] ); return rows.length > 0 ? rows[0] : null; }; const hasActiveLinkCodes = async () => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT COUNT(*) as count FROM link_codes WHERE used = FALSE AND expires_at > NOW()' ); return rows[0].count > 0; }; const cleanExpiredCodes = async () => { const connection = getConnection(); await connection.execute( 'DELETE FROM link_codes WHERE expires_at < NOW()' ); }; const updateLastConnection = async (steamId) => { const connection = getConnection(); const [result] = await connection.execute( 'UPDATE user_links SET lastConnection = NOW() WHERE steam_id = ?', [steamId] ); return { success: true, changes: result.affectedRows }; }; const getConfig = async (key) => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT config_value FROM bot_config WHERE config_key = ?', [key] ); return rows.length > 0 ? rows[0].config_value : null; }; const getAllConfig = async () => { const connection = getConnection(); const [rows] = await connection.execute( 'SELECT config_key, config_value FROM bot_config' ); const config = {}; rows.forEach(row => { config[row.config_key] = row.config_value; }); return config; }; const updateConfig = async (key, value) => { const connection = getConnection(); await connection.execute( 'UPDATE bot_config SET config_value = ? WHERE config_key = ?', [value, key] ); }; module.exports = { initDatabase, getConnection, createTables, generateLinkCode, verifyLinkCode, getAllLinks, getUserLink, updateUserLinkWithUsername, deleteUserLink, getPendingPlayer, hasActiveLinkCodes, cleanExpiredCodes, updateLastConnection, getConfig, getAllConfig, updateConfig };