diff --git a/backend/launcher.js b/backend/launcher.js index d406cc7..f7692c3 100644 --- a/backend/launcher.js +++ b/backend/launcher.js @@ -7,6 +7,7 @@ const axios = require('axios'); const AdmZip = require('adm-zip'); const { v4: uuidv4 } = require('uuid'); const crypto = require('crypto'); +const logger = require('./logger'); const execAsync = promisify(exec); const execFileAsync = promisify(execFile); @@ -55,8 +56,14 @@ function setupWaylandEnvironment() { const envVars = { SDL_VIDEODRIVER: 'wayland', + GDK_BACKEND: 'wayland', + QT_QPA_PLATFORM: 'wayland', + MOZ_ENABLE_WAYLAND: '1', + _JAVA_AWT_WM_NONREPARENTING: '1' }; + envVars.ELECTRON_OZONE_PLATFORM_HINT = 'wayland'; + console.log('Wayland environment variables:', envVars); return envVars; } @@ -2212,5 +2219,6 @@ module.exports = { markAsLaunched, checkExistingGameInstallation, proposeGameUpdate, - handleFirstLaunchCheck + handleFirstLaunchCheck, + getResolvedAppDir }; diff --git a/backend/logger.js b/backend/logger.js new file mode 100644 index 0000000..2064969 --- /dev/null +++ b/backend/logger.js @@ -0,0 +1,213 @@ +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +class Logger { + constructor() { + this.logDir = null; + this.logFile = null; + this.maxLogSize = 10 * 1024 * 1024; // 10MB + this.maxLogFiles = 5; + this.originalConsole = { + log: console.log, + error: console.error, + warn: console.warn, + info: console.info + }; + + this.initializeLogDirectory(); + } + + getAppDir() { + const home = os.homedir(); + if (process.platform === 'win32') { + return path.join(home, 'AppData', 'Local', 'HytaleF2P'); + } else if (process.platform === 'darwin') { + return path.join(home, 'Library', 'Application Support', 'HytaleF2P'); + } else { + return path.join(home, '.hytalef2p'); + } + } + + getInstallPath() { + try { + const configFile = path.join(this.getAppDir(), 'config.json'); + if (fs.existsSync(configFile)) { + const config = JSON.parse(fs.readFileSync(configFile, 'utf8')); + if (config.installPath && config.installPath.trim()) { + return path.join(config.installPath.trim(), 'HytaleF2P'); + } + } + } catch (err) { + } + return this.getAppDir(); + } + + initializeLogDirectory() { + try { + const installPath = this.getInstallPath(); + this.logDir = path.join(installPath, 'logs'); + + if (!fs.existsSync(this.logDir)) { + fs.mkdirSync(this.logDir, { recursive: true }); + } + + const today = new Date(); + const dateString = today.toISOString().split('T')[0]; // YYYY-MM-DD + const timeString = today.toISOString().split('T')[1].split('.')[0].replace(/:/g, '-'); // HH-MM-SS + this.logFile = path.join(this.logDir, `launcher-${dateString}-${timeString}.log`); + + this.writeToFile(`\n=== NEW LAUNCHER SESSION - ${today.toISOString()} ===\n`); + + } catch (error) { + this.logDir = path.join(os.tmpdir(), 'HytaleF2P-logs'); + if (!fs.existsSync(this.logDir)) { + fs.mkdirSync(this.logDir, { recursive: true }); + } + const today = new Date(); + const dateString = today.toISOString().split('T')[0]; + const timeString = today.toISOString().split('T')[1].split('.')[0].replace(/:/g, '-'); + this.logFile = path.join(this.logDir, `launcher-${dateString}-${timeString}.log`); + this.writeToFile(`\n=== FALLBACK SESSION IN TEMP - ${today.toISOString()} ===\n`); + } + } + + writeToFile(message) { + if (!this.logFile) return; + + try { + if (fs.existsSync(this.logFile)) { + const stats = fs.statSync(this.logFile); + if (stats.size > this.maxLogSize) { + this.rotateLogFile(); + } + } + + fs.appendFileSync(this.logFile, message, 'utf8'); + } catch (error) { + this.originalConsole.error('Impossible d\'écrire dans le fichier de log:', error.message); + } + } + + rotateLogFile() { + try { + const today = new Date(); + const dateString = today.toISOString().split('T')[0]; + const timeString = today.toISOString().split('T')[1].split('.')[0].replace(/:/g, '-'); + + const rotatedFile = path.join(this.logDir, `launcher-${dateString}-${timeString}.log`); + fs.renameSync(this.logFile, rotatedFile); + + this.cleanupOldLogs(); + + const newToday = new Date(); + const newDateString = newToday.toISOString().split('T')[0]; + const newTimeString = newToday.toISOString().split('T')[1].split('.')[0].replace(/:/g, '-'); + this.logFile = path.join(this.logDir, `launcher-${newDateString}-${newTimeString}.log`); + this.writeToFile(`\n=== LOG ROTATION - ${newToday.toISOString()} ===\n`); + + } catch (error) { + this.originalConsole.error('Erreur lors de la rotation des logs:', error.message); + } + } + + cleanupOldLogs() { + try { + const files = fs.readdirSync(this.logDir) + .filter(file => file.startsWith('launcher-') && file.endsWith('.log')) + .map(file => ({ + name: file, + path: path.join(this.logDir, file), + mtime: fs.statSync(path.join(this.logDir, file)).mtime + })) + .sort((a, b) => b.mtime - a.mtime); + + if (files.length > this.maxLogFiles) { + const filesToDelete = files.slice(this.maxLogFiles); + filesToDelete.forEach(file => { + try { + fs.unlinkSync(file.path); + } catch (err) { + this.originalConsole.error(`Impossible de supprimer le fichier de log ${file.name}:`, err.message); + } + }); + } + } catch (error) { + this.originalConsole.error('Erreur lors du nettoyage des logs:', error.message); + } + } + + formatLogMessage(level, ...args) { + const timestamp = new Date().toISOString(); + const message = args.map(arg => { + if (typeof arg === 'object') { + try { + return JSON.stringify(arg, null, 2); + } catch (e) { + return String(arg); + } + } + return String(arg); + }).join(' '); + + return `[${timestamp}] [${level.toUpperCase()}] ${message}\n`; + } + + log(...args) { + const logMessage = this.formatLogMessage('info', ...args); + this.writeToFile(logMessage); + this.originalConsole.log(...args); + } + + error(...args) { + const logMessage = this.formatLogMessage('error', ...args); + this.writeToFile(logMessage); + this.originalConsole.error(...args); + } + + warn(...args) { + const logMessage = this.formatLogMessage('warn', ...args); + this.writeToFile(logMessage); + this.originalConsole.warn(...args); + } + + info(...args) { + const logMessage = this.formatLogMessage('info', ...args); + this.writeToFile(logMessage); + this.originalConsole.info(...args); + } + + interceptConsole() { + console.log = (...args) => this.log(...args); + console.error = (...args) => this.error(...args); + console.warn = (...args) => this.warn(...args); + console.info = (...args) => this.info(...args); + + process.on('uncaughtException', (error) => { + this.error('Uncaught exception:', error.stack || error.message); + }); + + process.on('unhandledRejection', (reason, promise) => { + this.error('Unhandled rejection at', promise, 'reason:', reason); + }); + } + + restoreConsole() { + console.log = this.originalConsole.log; + console.error = this.originalConsole.error; + console.warn = this.originalConsole.warn; + console.info = this.originalConsole.info; + } + + getLogDirectory() { + return this.logDir; + } + + updateInstallPath() { + this.initializeLogDirectory(); + } +} + +const logger = new Logger(); + +module.exports = logger; \ No newline at end of file diff --git a/backend/updateManager.js b/backend/updateManager.js index 3a070a4..9346ab7 100644 --- a/backend/updateManager.js +++ b/backend/updateManager.js @@ -1,7 +1,7 @@ const axios = require('axios'); const UPDATE_CHECK_URL = 'http://3.10.208.30:3002/api/version_launcher'; -const CURRENT_VERSION = '2.0.0'; +const CURRENT_VERSION = '2.0.1'; const GITHUB_DOWNLOAD_URL = 'https://github.com/amiayweb/Hytale-F2P/'; class UpdateManager {