import express from 'express';
import { createServer } from 'http';
import { Server as SocketIOServer } from 'socket.io';
import cors from 'cors';
import helmet from 'helmet';
import dotenv from 'dotenv';
import path from 'path';
import os from 'os';
import { fileURLToPath } from 'url';
import winston from 'winston';
import { promises as fs } from 'fs';
import { TerminalManager } from './modules/terminal/TerminalManager.js';
import { GameManager } from './modules/game/GameManager.js';
import { SystemManager } from './modules/system/SystemManager.js';
import { ConfigManager } from './modules/config/ConfigManager.js';
import { AuthManager } from './modules/auth/AuthManager.js';
import { InstanceManager } from './modules/instance/InstanceManager.js';
import { SteamCMDManager } from './modules/steamcmd/SteamCMDManager.js';
import { SchedulerManager } from './modules/scheduler/SchedulerManager.js';
import { PluginManager } from './modules/plugin/PluginManager.js';
import { FileWatchManager } from './modules/file/FileWatchManager.js';
import { setupTerminalRoutes } from './routes/terminal.js';
import { setupGameRoutes } from './routes/games.js';
import { setupSystemRoutes } from './routes/system.js';
import { setupAuthRoutes } from './routes/auth.js';
import { setupScheduledTaskRoutes } from './routes/scheduledTasks.js';
import { setupConfigRoutes } from './routes/config.js';
import { setupSettingsRoutes } from './routes/settings.js';
import { setAuthManager } from './middleware/auth.js';
import filesRouter from './routes/files.js';
import { setupInstanceRoutes } from './routes/instances.js';
import steamcmdRouter, { setSteamCMDManager } from './routes/steamcmd.js';
import gameDeploymentRouter, { setGameDeploymentManagers } from './routes/gameDeployment.js';
import { minecraftRouter, setMinecraftDependencies } from './routes/minecraft.js';
import moreGamesRouter from './routes/moreGames.js';
import weatherRouter from './routes/weather.js';
import pluginsRouter, { setPluginManager } from './routes/plugins.js';
import backupRoutes from './routes/backup.js';
import pluginApiRouter, { setPluginApiDependencies } from './routes/pluginApi.js';
import sponsorRouter, { setSponsorDependencies } from './routes/sponsor.js';
import onlineDeployRouter from './routes/onlineDeploy.js';
import gameConfigRouter from './routes/gameconfig.js';
import rconRouter from './routes/rcon.js';
import environmentRouter, { setEnvironmentSocketIO, setEnvironmentConfigManager } from './routes/environment.js';
import { setupDeveloperRoutes } from './routes/developer.js';
import wallpaperRouter from './routes/wallpaper.js';
import networkRouter from './routes/network.js';
import cloudBuildRouter from './routes/cloudBuild.js';
import fileDeployRouter, { setFileDeployDependencies } from './routes/fileDeploy.js';
import { consoleLogBuffer } from './utils/logger.js';
import { zipToolsManager } from './utils/zipToolsManager.js';
import { ptyManager } from './utils/ptyManager.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
dotenv.config({ path: path.join(__dirname, '../../.env') });
dotenv.config();
const logger = winston.createLogger({
    level: process.env.LOG_LEVEL || 'info',
    format: winston.format.combine(winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json()),
    defaultMeta: { service: 'gsm3-server' },
    transports: [
        new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
        new winston.transports.File({ filename: 'logs/combined.log' }),
        new winston.transports.Console({
            format: winston.format.combine(winston.format.colorize(), winston.format.simple())
        })
    ]
});
const app = express();
const server = createServer(app);
const io = new SocketIOServer(server, {
    cors: {
        origin: process.env.SOCKET_CORS_ORIGIN || '*',
        methods: ['GET', 'POST'],
    },
    transports: ['websocket', 'polling'],
});
const sockets = new Set();
server.on('connection', socket => {
    sockets.add(socket);
    socket.on('close', () => {
        sockets.delete(socket);
    });
});
app.use(helmet({
    contentSecurityPolicy: false,
    crossOriginOpenerPolicy: false
}));
app.use(cors({
    origin: process.env.CORS_ORIGIN || '*',
    credentials: true,
    allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH']
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use('/static', express.static(path.join(__dirname, '../public')));
app.use(express.static(path.join(__dirname, '../public')));
let configManager;
let authManager;
let terminalManager;
let gameManager;
let systemManager;
let instanceManager;
let steamcmdManager;
let schedulerManager;
let pluginManager;
let fileWatchManager;
app.get('/api/health', (req, res) => {
    res.json({
        status: 'ok',
        timestamp: new Date().toISOString(),
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        version: process.env.npm_package_version || '1.0.0'
    });
});
app.get('/', (req, res) => {
    res.json({
        name: 'GSM3 Server',
        version: '1.0.0',
        description: '游戏面板后端服务',
        endpoints: {
            health: '/api/health',
            terminal: '/api/terminal',
            game: '/api/game',
            system: '/api/system'
        }
    });
});
app.use((err, req, res, next) => {
    logger.error('未处理的错误:', err);
    res.status(500).json({
        error: '服务器内部错误',
        message: process.env.NODE_ENV === 'development' ? err.message : '请稍后重试'
    });
});
let shuttingDown = false;
function gracefulShutdown(signal) {
    if (shuttingDown) {
        logger.warn('已在关闭中，忽略重复信号。');
        return;
    }
    shuttingDown = true;
    logger.info(`收到${signal}信号，开始优雅关闭...`);
    logger.info('开始清理管理器...');
    try {
        if (terminalManager) {
            terminalManager.cleanup();
            logger.info('TerminalManager 已清理');
        }
        if (gameManager) {
            gameManager.cleanup();
            logger.info('GameManager 已清理');
        }
        if (systemManager) {
            systemManager.cleanup();
            logger.info('SystemManager 已清理');
        }
        if (fileWatchManager) {
            fileWatchManager.cleanup();
            logger.info('FileWatchManager 已清理');
        }
        if (instanceManager) {
            instanceManager.cleanup();
            logger.info('InstanceManager 已清理');
        }
        if (steamcmdManager) {
            logger.info('SteamCMDManager 已清理');
        }
        if (schedulerManager) {
            schedulerManager.destroy();
            logger.info('SchedulerManager 已清理');
        }
        if (pluginManager) {
            pluginManager.cleanup();
            logger.info('PluginManager 已清理');
        }
        logger.info('管理器清理完成。');
    }
    catch (cleanupErr) {
        logger.error('清理管理器时出错:', cleanupErr);
    }
    logger.info('开始关闭服务器...');
    logger.info(`正在销毁 ${sockets.size} 个活动的socket...`);
    for (const socket of sockets) {
        socket.destroy();
    }
    server.close(err => {
        if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') {
            logger.error('关闭HTTP服务器时出错:', err);
        }
        else {
            logger.info('HTTP服务器已关闭。');
        }
        logger.info('优雅关闭完成，服务器退出。');
        process.exit(0);
    });
    io.close(() => {
        logger.info('Socket.IO 服务器已关闭');
    });
    setTimeout(() => {
        logger.error('优雅关闭超时，强制退出！');
        process.exit(1);
    }, 5000);
}
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
process.on('uncaughtException', (error) => {
    logger.error('未捕获的异常:', error);
    process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
    logger.error('未处理的Promise拒绝:', reason);
    process.exit(1);
});
function printAsciiArt() {
    const terminalWidth = process.stdout.columns || 120;
    const mainArtLines = [
        '______   _____    __  ___                                               ',
        '   / ____/  / ___/   /  |/  /  ____ _   ____   ____ _   ____ _  ___    _____ ',
        '  / / __    \\__ \\   / /|_/ /  / __ `/  / __ \\ / __ `/  / __ `/ / _ \\  / ___/ ',
        ' / /_/ /   ___/ /  / /  / /  / /_/ /  / / / // /_/ /  / /_/ / /  __/ / /    ',
        ' \\____/   /____/  /_/  /_/   \\__,_/  /_/ /_/ \\__,_/   \\__, /  \\___/ /_/     ',
        '                                                     /____/                 ',
        '                                                                            '
    ];
    const subtitle = '🎮 游戏服务器管理面板 v3.0 🎮';
    const startupText = '正在启动服务器...';
    console.log('');
    mainArtLines.forEach(line => {
        const padding = Math.max(0, Math.floor((terminalWidth - line.length) / 2));
        console.log(' '.repeat(padding) + line);
    });
    console.log('');
    const subtitlePadding = Math.max(0, Math.floor((terminalWidth - subtitle.length) / 2));
    console.log(' '.repeat(subtitlePadding) + subtitle);
    const platformArt = getPlatformArt();
    const platformLines = platformArt.split('\n').filter(line => line.trim());
    platformLines.forEach(line => {
        const cleanLine = line.trim();
        if (cleanLine) {
            const padding = Math.max(0, Math.floor((terminalWidth - cleanLine.length) / 2));
            console.log(' '.repeat(padding) + cleanLine);
        }
    });
    console.log('');
    const startupPadding = Math.max(0, Math.floor((terminalWidth - startupText.length) / 2));
    console.log(' '.repeat(startupPadding) + startupText);
    console.log('');
}
function displayConnectionInfo(host, port) {
    const terminalWidth = process.stdout.columns || 80;
    console.log('');
    console.log('='.repeat(terminalWidth));
    console.log('');
    const title = '🚀 GSM面板启动完成！';
    const titlePadding = Math.max(0, Math.floor((terminalWidth - title.length) / 2));
    console.log(' '.repeat(titlePadding) + title);
    console.log('');
    const localUrl = `http://localhost:${port}`;
    const localText = `📍 本地访问: ${localUrl}`;
    const localPadding = Math.max(0, Math.floor((terminalWidth - localText.length) / 2));
    console.log(' '.repeat(localPadding) + localText);
    const networkInterfaces = os.networkInterfaces();
    const networkIPs = [];
    for (const [interfaceName, interfaces] of Object.entries(networkInterfaces)) {
        if (interfaces) {
            for (const iface of interfaces) {
                if (iface.family === 'IPv4' && !iface.internal && !iface.address.startsWith('169.254.')) {
                    networkIPs.push(iface.address);
                }
                if (iface.family === 'IPv6' && !iface.internal && !iface.address.startsWith('fe80:')) {
                    networkIPs.push(`[${iface.address}]`);
                }
            }
        }
    }
    if (networkIPs.length > 0) {
        networkIPs.forEach((ip, index) => {
            const networkUrl = `http://${ip}:${port}`;
            const networkText = index === 0 ? `🌐 网络访问: ${networkUrl}` : `           ${networkUrl}`;
            const networkPadding = Math.max(0, Math.floor((terminalWidth - networkText.length) / 2));
            console.log(' '.repeat(networkPadding) + networkText);
        });
    }
    else {
        const networkUrl = host === '0.0.0.0' ? `http://127.0.0.1:${port}` : `http://${host}:${port}`;
        const networkText = `🌐 网络访问: ${networkUrl}`;
        const networkPadding = Math.max(0, Math.floor((terminalWidth - networkText.length) / 2));
        console.log(' '.repeat(networkPadding) + networkText);
    }
    console.log('');
    const tipText = '💡 请在浏览器中打开上述地址访问管理面板';
    const tipPadding = Math.max(0, Math.floor((terminalWidth - tipText.length) / 2));
    console.log(' '.repeat(tipPadding) + tipText);
    console.log('');
    console.log('='.repeat(terminalWidth));
    console.log('');
}
function getPlatformArt() {
    const platform = process.platform;
    switch (platform) {
        case 'win32':
            return `
██╗    ██╗██╗███╗   ██╗██████╗  ██████╗ ██╗    ██╗███████╗
██║    ██║██║████╗  ██║██╔══██╗██╔═══██╗██║    ██║██╔════╝
██║ █╗ ██║██║██╔██╗ ██║██║  ██║██║   ██║██║ █╗ ██║███████╗
██║███╗██║██║██║╚██╗██║██║  ██║██║   ██║██║███╗██║╚════██║
╚███╔███╔╝██║██║ ╚████║██████╔╝╚██████╔╝╚███╔███╔╝███████║
 ╚══╝╚══╝ ╚═╝╚═╝  ╚═══╝╚═════╝  ╚═════╝  ╚══╝╚══╝ ╚══════╝`;
        case 'linux':
            return `
██╗     ██╗███╗   ██╗██╗   ██╗██╗  ██╗
██║     ██║████╗  ██║██║   ██║╚██╗██╔╝
██║     ██║██╔██╗ ██║██║   ██║ ╚███╔╝ 
██║     ██║██║╚██╗██║██║   ██║ ██╔██╗ 
███████╗██║██║ ╚████║╚██████╔╝██╔╝ ██╗
╚══════╝╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚═╝  ╚═╝`;
        case 'darwin':
            return `
███╗   ███╗ █████╗  ██████╗ ██████╗ ███████╗
████╗ ████║██╔══██╗██╔════╝██╔═══██╗██╔════╝
██╔████╔██║███████║██║     ██║   ██║███████╗
██║╚██╔╝██║██╔══██║██║     ██║   ██║╚════██║
██║ ╚═╝ ██║██║  ██║╚██████╗╚██████╔╝███████║
╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝`;
        default:
            return `
██╗   ██╗███╗   ██╗██╗██╗  ██╗
██║   ██║████╗  ██║██║╚██╗██╔╝
██║   ██║██╔██╗ ██║██║ ╚███╔╝ 
██║   ██║██║╚██╗██║██║ ██╔██╗ 
╚██████╔╝██║ ╚████║██║██╔╝ ██╗
 ╚═════╝ ╚═╝  ╚═══╝╚═╝╚═╝  ╚═╝`;
    }
}
function checkCORSConfiguration() {
    const corsOrigin = process.env.CORS_ORIGIN || '*';
    const socketCorsOrigin = process.env.SOCKET_CORS_ORIGIN || '*';
    if (corsOrigin === '*' || socketCorsOrigin === '*') {
        console.log('\n' + '='.repeat(80));
        console.log('🚨 CORS安全风险警告 🚨');
        console.log('='.repeat(80));
        if (corsOrigin === '*') {
            console.log('⚠️  检测到 CORS_ORIGIN 配置为通配符 "*"');
            console.log('   这将允许任何域名访问您的API，存在跨域安全风险！');
        }
        if (socketCorsOrigin === '*') {
            console.log('⚠️  检测到 SOCKET_CORS_ORIGIN 配置为通配符 "*"');
            console.log('   这将允许任何域名连接您的WebSocket，存在安全风险！');
        }
        console.log('\n🔧 若在公网中使用强烈建议修改配置：');
        console.log('   1. 在 .env 文件中将 CORS_ORIGIN 设置为具体的前端地址');
        console.log('   2. 在 .env 文件中将 SOCKET_CORS_ORIGIN 设置为具体的前端地址');
        console.log('   例如: CORS_ORIGIN=http://域名:端口');
        console.log('   例如: SOCKET_CORS_ORIGIN=http://域名:端口');
        console.log('\n💡 生产环境请务必使用具体的域名替换通配符！');
        console.log('='.repeat(80) + '\n');
    }
    else {
        console.log('✅ CORS配置安全检查通过');
    }
}
async function ensureEnvFile() {
    const envPath = path.join(process.cwd(), '.env');
    try {
        await fs.access(envPath);
        logger.info('.env 文件已存在');
    }
    catch {
        logger.info('.env 文件不存在，正在创建...');
        const envContent = `# GSM3 游戏服务器管理系统配置

# 服务器端口配置
# 后端API服务端口
SERVER_PORT=3001

# 前端开发服务端口（仅开发环境使用）
CLIENT_PORT=5173

# 环境配置
NODE_ENV=development

# 日志配置
LOG_LEVEL=info

# CORS配置
# 前端访问地址（开发环境）
CLIENT_URL=http://localhost:5173
# 允许的前端访问地址，生产环境请修改为实际域名
CORS_ORIGIN=*

# Socket.IO配置
SOCKET_CORS_ORIGIN=*

# 数据目录
DATA_DIR=./data

# 日志目录
LOG_DIR=./logs

# PTY配置
PTY_TIMEOUT=1800000
PTY_MAX_SESSIONS=0

# 游戏服务器配置
GAME_MAX_INSTANCES=0
GAME_DATA_DIR=./data/games

# 系统监控配置
SYSTEM_MONITOR_INTERVAL=3000
SYSTEM_STATS_HISTORY_SIZE=1200

# 告警配置
ALERT_CPU_WARNING=70
ALERT_CPU_CRITICAL=90
ALERT_MEMORY_WARNING=80
ALERT_MEMORY_CRITICAL=95
ALERT_DISK_WARNING=85
ALERT_DISK_CRITICAL=95

# Java配置（用于Minecraft服务器）
JAVA_HOME=
JAVA_OPTS=-Xmx2G -Xms1G

# 备份配置
BACKUP_ENABLED=true
BACKUP_INTERVAL=86400000
BACKUP_RETENTION=7

# 网络配置
REQUEST_TIMEOUT=0

# 说明：
# 1. 修改 SERVER_PORT 可以更改后端服务端口
# 2. 生产环境部署时，请将 CORS_ORIGIN 和 SOCKET_CORS_ORIGIN 设置为实际的前端访问地址
# 3. 请务必修改 SESSION_SECRET 和 JWT_SECRET 为随机字符串
# 4. 根据服务器配置调整 JAVA_OPTS 中的内存设置
`;
        await fs.writeFile(envPath, envContent, 'utf8');
        logger.info(`.env 文件已创建: ${envPath}`);
        dotenv.config({ path: envPath });
    }
}
async function startServer() {
    try {
        await ensureEnvFile();
        if (os.platform() === 'linux') {
            const steamHome = '/home/steam';
            try {
                await fs.access(steamHome);
                const dirsToCreate = [
                    path.join(steamHome, '.local'),
                    path.join(steamHome, '.config')
                ];
                for (const dir of dirsToCreate) {
                    await fs.mkdir(dir, { recursive: true });
                    await fs.chmod(dir, 0o777);
                }
                logger.info(`已在 ${steamHome} 下创建 .local 和 .config 目录并设置 777 权限`);
            }
            catch {
                logger.info('/home/steam 目录不存在，跳过 Steam 目录初始化');
            }
        }
        printAsciiArt();
        const uploadsDir = path.join(process.cwd(), 'uploads');
        try {
            await fs.access(uploadsDir);
        }
        catch {
            await fs.mkdir(uploadsDir, { recursive: true });
            logger.info(`创建uploads目录: ${uploadsDir}`);
        }
        const terminalSessionsPath = path.join(process.cwd(), 'data', 'terminal-sessions.json');
        try {
            await fs.unlink(terminalSessionsPath);
            logger.info('已删除之前的终端会话文件');
        }
        catch (error) {
            if (error.code !== 'ENOENT') {
                logger.warn(`删除终端会话文件时出错: ${error.message}`);
            }
        }
        configManager = new ConfigManager(logger);
        authManager = new AuthManager(configManager, logger);
        terminalManager = new TerminalManager(io, logger, configManager);
        gameManager = new GameManager(io, logger);
        systemManager = new SystemManager(io, logger);
        instanceManager = new InstanceManager(terminalManager, logger);
        steamcmdManager = new SteamCMDManager(logger, configManager);
        pluginManager = new PluginManager(logger);
        fileWatchManager = new FileWatchManager(logger);
        const dataDir = path.join(process.cwd(), 'data');
        try {
            await fs.access(dataDir);
        }
        catch {
            await fs.mkdir(dataDir, { recursive: true });
            logger.info(`创建data目录: ${dataDir}`);
        }
        schedulerManager = new SchedulerManager(dataDir, logger);
        await configManager.initialize();
        await authManager.initialize();
        try {
            await ptyManager.ensureInstalled();
            logger.info('PTY 已就绪');
        }
        catch (error) {
            logger.warn(`PTY 下载失败，终端功能可能不可用: ${error.message || error}`);
        }
        await terminalManager.initialize();
        await instanceManager.initialize();
        await pluginManager.loadPlugins();
        setAuthManager(authManager);
        setPluginManager(pluginManager);
        terminalManager.setSocketIO(io);
        fileWatchManager.setSocketIO(io);
        consoleLogBuffer.setSocketIO(io);
        schedulerManager.setGameManager(gameManager);
        schedulerManager.setInstanceManager(instanceManager);
        schedulerManager.setTerminalManager(terminalManager);
        try {
            await zipToolsManager.ensureInstalled();
            logger.info('Zip-Tools 已就绪');
        }
        catch (error) {
            logger.warn(`Zip-Tools 下载失败，ZIP 相关功能可能不可用: ${error.message || error}`);
        }
        try {
            await zipToolsManager.ensure7zInstalled();
            logger.info('7z 已就绪');
        }
        catch (error) {
            logger.warn(`7z 下载失败，7z 相关功能可能不可用: ${error.message || error}`);
        }
        app.use('/api/auth', setupAuthRoutes(authManager));
        app.use('/api/terminal', setupTerminalRoutes(terminalManager));
        app.use('/api/games', setupGameRoutes(gameManager));
        app.use('/api/system', setupSystemRoutes(systemManager));
        app.use('/api/files', filesRouter);
        app.use('/api/instances', setupInstanceRoutes(instanceManager));
        app.use('/api/scheduled-tasks', setupScheduledTaskRoutes(schedulerManager));
        app.use('/api/config', setupConfigRoutes(configManager));
        app.use('/api/settings', setupSettingsRoutes(configManager));
        app.use('/api/backup', backupRoutes);
        setSteamCMDManager(steamcmdManager, logger);
        app.use('/api/steamcmd', steamcmdRouter);
        setGameDeploymentManagers(terminalManager, instanceManager, steamcmdManager, configManager);
        app.use('/api/game-deployment', gameDeploymentRouter);
        setMinecraftDependencies(io, instanceManager);
        app.use('/api/minecraft', minecraftRouter);
        const { setMoreGamesDependencies } = await import('./routes/moreGames.js');
        setMoreGamesDependencies(io);
        app.use('/api/more-games', moreGamesRouter);
        app.use('/api/weather', weatherRouter);
        app.use('/api/plugins', pluginsRouter);
        setPluginApiDependencies(instanceManager, systemManager, terminalManager, gameManager);
        app.use('/api/plugin-api', pluginApiRouter);
        setSponsorDependencies(configManager);
        app.use('/api/sponsor', sponsorRouter);
        const { setOnlineDeployDependencies } = await import('./routes/onlineDeploy.js');
        setOnlineDeployDependencies(io, configManager);
        app.use('/api/online-deploy', onlineDeployRouter);
        const { setInstanceManager: setGameConfigInstanceManager } = await import('./routes/gameconfig.js');
        setGameConfigInstanceManager(instanceManager);
        app.use('/api/gameconfig', gameConfigRouter);
        app.use('/api/rcon', rconRouter);
        setEnvironmentSocketIO(io);
        setEnvironmentConfigManager(configManager);
        app.use('/api/environment', environmentRouter);
        global.fileWatchManager = fileWatchManager;
        app.use('/api/developer', setupDeveloperRoutes(configManager));
        app.use('/api/wallpaper', wallpaperRouter);
        app.use('/api/network', networkRouter);
        app.use('/api/cloud-build', cloudBuildRouter);
        setFileDeployDependencies(io, configManager, instanceManager);
        app.use('/api/file-deploy', fileDeployRouter);
        const { setSecurityConfigManager } = await import('./routes/security.js');
        setSecurityConfigManager(configManager);
        const securityRouter = (await import('./routes/security.js')).default;
        app.use('/api/security', securityRouter);
        app.get('*', (req, res) => {
            if (req.path.startsWith('/api/')) {
                res.status(404).json({
                    error: '接口不存在',
                    path: req.originalUrl
                });
            }
            else {
                res.sendFile(path.join(__dirname, '../public/index.html'));
            }
        });
        io.use(async (socket, next) => {
            const token = socket.handshake.auth.token;
            if (!token) {
                logger.warn(`Socket连接被拒绝: ${socket.id} - 缺少token`);
                return next(new Error('Authentication error: No token provided'));
            }
            const decoded = authManager.verifyToken(token);
            if (!decoded) {
                logger.warn(`Socket连接被拒绝: ${socket.id} - 无效token`);
                return next(new Error('Authentication error: Invalid token'));
            }
            socket.data.user = {
                userId: decoded.userId,
                username: decoded.username,
                role: decoded.role
            };
            logger.info(`Socket认证成功: ${socket.id} - 用户: ${decoded.username}`);
            next();
        });
        io.on('connection', (socket) => {
            logger.info(`客户端连接: ${socket.id} - 用户: ${socket.data.user?.username}`);
            const runDisconnectCleanupStep = (label, action) => {
                try {
                    action();
                }
                catch (error) {
                    logger.error(`客户端断开清理失败(${label}):`, error);
                }
            };
            socket.on('create-pty', async (data) => {
                const mappedData = {
                    ...data,
                    workingDirectory: data.cwd || data.workingDirectory
                };
                delete mappedData.cwd;
                await terminalManager.createPty(socket, mappedData);
            });
            socket.on('terminal-input', (data) => {
                terminalManager.handleInput(socket, data);
            });
            socket.on('terminal-resize', (data) => {
                terminalManager.resizeTerminal(socket, data);
            });
            socket.on('close-pty', (data) => {
                terminalManager.closePty(socket, data);
            });
            socket.on('reconnect-session', (data) => {
                const success = terminalManager.reconnectSession(socket, data.sessionId);
                if (success) {
                    socket.emit('session-reconnected', { sessionId: data.sessionId });
                }
                else {
                    socket.emit('session-reconnect-failed', { sessionId: data.sessionId });
                }
            });
            socket.on('game-start', (data) => {
                gameManager.startGame(socket, data);
            });
            socket.on('game-stop', (data) => {
                gameManager.stopGame(socket, data);
            });
            socket.on('game-command', (data) => {
                gameManager.sendCommand(socket, data.gameId, data.command);
            });
            socket.on('subscribe-system-stats', () => {
                socket.join('system-stats');
                logger.info(`客户端 ${socket.id} 开始订阅系统状态`);
            });
            socket.on('unsubscribe-system-stats', () => {
                socket.leave('system-stats');
                logger.info(`客户端 ${socket.id} 取消订阅系统状态`);
                systemManager.handleClientDisconnect();
            });
            socket.on('subscribe-system-ports', () => {
                socket.join('system-ports');
                logger.info(`客户端 ${socket.id} 开始订阅端口信息`);
            });
            socket.on('unsubscribe-system-ports', () => {
                socket.leave('system-ports');
                logger.info(`客户端 ${socket.id} 取消订阅端口信息`);
                systemManager.handleClientDisconnect();
            });
            socket.on('subscribe-system-processes', () => {
                socket.join('system-processes');
                logger.info(`客户端 ${socket.id} 开始订阅进程信息`);
            });
            socket.on('unsubscribe-system-processes', () => {
                socket.leave('system-processes');
                logger.info(`客户端 ${socket.id} 取消订阅进程信息`);
                systemManager.handleClientDisconnect();
            });
            socket.on('subscribe-terminal-processes', () => {
                socket.join('terminal-processes');
                logger.info(`客户端 ${socket.id} 开始订阅终端活跃进程信息`);
                terminalManager.sendActiveProcessesToClient(socket);
            });
            socket.on('unsubscribe-terminal-processes', () => {
                socket.leave('terminal-processes');
                logger.info(`客户端 ${socket.id} 取消订阅终端活跃进程信息`);
                terminalManager.handleClientDisconnect();
            });
            socket.on('subscribe-console-logs', () => {
                socket.join('console-logs');
                logger.info(`客户端 ${socket.id} 开始订阅面板日志`);
                const recentLogs = consoleLogBuffer.getRecentLogs(100);
                socket.emit('console-logs-history', { lines: recentLogs });
            });
            socket.on('unsubscribe-console-logs', () => {
                socket.leave('console-logs');
                logger.info(`客户端 ${socket.id} 取消订阅面板日志`);
            });
            socket.on('watch-file', async (data) => {
                try {
                    const success = await fileWatchManager.watchFile(socket, data.filePath);
                    socket.emit('watch-file-response', {
                        filePath: data.filePath,
                        success,
                        message: success ? '开始监视文件' : '监视文件失败'
                    });
                }
                catch (error) {
                    logger.error('监视文件失败:', error);
                    socket.emit('watch-file-response', {
                        filePath: data.filePath,
                        success: false,
                        message: error.message || '监视文件失败'
                    });
                }
            });
            socket.on('unwatch-file', (data) => {
                try {
                    fileWatchManager.unwatchFile(socket, data.filePath);
                    socket.emit('unwatch-file-response', {
                        filePath: data.filePath,
                        success: true,
                        message: '停止监视文件'
                    });
                }
                catch (error) {
                    logger.error('取消监视文件失败:', error);
                    socket.emit('unwatch-file-response', {
                        filePath: data.filePath,
                        success: false,
                        message: error.message || '取消监视文件失败'
                    });
                }
            });
            socket.on('disconnecting', (reason) => {
                const joinedRooms = Array.from(socket.rooms).filter(room => room !== socket.id);
                logger.info(`客户端准备断开连接: ${socket.id}, 原因: ${reason}, 房间: ${joinedRooms.join(', ') || '无'}`);
            });
            socket.on('disconnect', (reason) => {
                logger.info(`客户端断开连接: ${socket.id}, 原因: ${reason}`);
                runDisconnectCleanupStep('terminalManager.handleDisconnect', () => {
                    terminalManager.handleDisconnect(socket);
                });
                runDisconnectCleanupStep('leave system-stats', () => {
                    socket.leave('system-stats');
                });
                runDisconnectCleanupStep('leave system-ports', () => {
                    socket.leave('system-ports');
                });
                runDisconnectCleanupStep('leave system-processes', () => {
                    socket.leave('system-processes');
                });
                runDisconnectCleanupStep('leave terminal-processes', () => {
                    socket.leave('terminal-processes');
                });
                runDisconnectCleanupStep('leave console-logs', () => {
                    socket.leave('console-logs');
                });
                runDisconnectCleanupStep('systemManager.handleClientDisconnect', () => {
                    systemManager.handleClientDisconnect();
                });
                runDisconnectCleanupStep('terminalManager.handleClientDisconnect', () => {
                    terminalManager.handleClientDisconnect();
                });
                runDisconnectCleanupStep('fileWatchManager.unwatchAllFilesForSocket', () => {
                    fileWatchManager.unwatchAllFilesForSocket(socket);
                });
            });
            socket.on('error', (error) => {
                logger.error(`Socket错误 ${socket.id}:`, error);
            });
        });
        const PORT = parseInt(process.env.SERVER_PORT || process.env.PORT || '3001', 10);
        const HOST = process.env.HOST || '::';
        server.listen(PORT, HOST, () => {
            logger.info(`GSM3服务器启动成功!`);
            logger.info(`地址: http://${HOST}:${PORT}`);
            logger.info(`环境: ${process.env.NODE_ENV || 'development'}`);
            logger.info(`进程ID: ${process.pid}`);
            checkCORSConfiguration();
            displayConnectionInfo(HOST, PORT);
        });
    }
    catch (error) {
        logger.error('服务器启动失败:', error);
        process.exit(1);
    }
}
startServer();
export { app, server, io, logger };
