const { spawn } = require('child_process'); const path = require('path'); const fs = require('fs'); const os = require('os'); const logger = require('./logger'); let mainProxyProcess = null; let othersProxyProcess = null; let mainProxyLogStream = null; let othersProxyLogStream = null; /** * 获取当前系统平台 * @returns {string} 平台标识 */ function detectPlatform() { const platform = os.platform(); const arch = os.arch(); if (platform === 'win32' && arch === 'x64') { return 'windows_x64'; } else if (platform === 'linux' && arch === 'x64') { return 'linux_x64'; } else if ((platform === 'android' || platform === 'linux') && (arch === 'arm64' || arch === 'aarch64')) { return 'android_arm64'; } // 默认返回linux版本 logger.warn(`未识别的平台: ${platform} ${arch},将使用linux_x64代理`); return 'linux_x64'; } /** * 获取代理服务器可执行文件路径 * @param {string} platform 平台类型 * @param {string} proxyType 代理类型 ('main' 或 'others') * @returns {string} 可执行文件路径 */ function getProxyExecutablePath(platform, proxyType = 'main') { let proxyDir; if (proxyType === 'others') { proxyDir = path.join(process.cwd(), 'src', 'proxy', 'others'); } else { proxyDir = path.join(process.cwd(), 'src', 'proxy'); } // 根据平台选择可执行文件 switch (platform) { case 'windows_x64': return path.join(proxyDir, 'cursor_proxy_server_windows_amd64.exe'); case 'linux_x64': return path.join(proxyDir, 'cursor_proxy_server_linux_amd64'); case 'android_arm64': return path.join(proxyDir, 'cursor_proxy_server_android_arm64'); default: logger.warn(`未知平台: ${platform},将使用linux_x64代理`); return path.join(proxyDir, 'cursor_proxy_server_linux_amd64'); } } /** * 创建并打开代理服务器日志文件 * @param {string} platform 平台类型 * @param {string} proxyType 代理类型 ('main' 或 'others') * @returns {fs.WriteStream} 日志文件写入流 */ function createProxyLogFile(platform, proxyType = 'main') { try { // 确保logs目录存在 const logsDir = path.join(process.cwd(), 'logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir, { recursive: true }); } // 创建日志文件名,包含日期和平台信息 const now = new Date(); const dateStr = now.toISOString().split('T')[0]; const logFileName = `proxy_server_${proxyType}_${platform}_${dateStr}.log`; const logFilePath = path.join(logsDir, logFileName); // 创建日志文件流 const logStream = fs.createWriteStream(logFilePath, { flags: 'a' }); // 写入日志文件头 const headerLine = `\n\n========== ${proxyType}代理服务器日志 - ${platform} - ${now.toISOString()} ==========\n\n`; logStream.write(headerLine); logger.info(`${proxyType}代理服务器详细日志将记录到: ${logFilePath}`); return logStream; } catch (error) { logger.error(`创建${proxyType}代理服务器日志文件失败: ${error.message}`); return null; } } /** * 写入日志到代理服务器日志文件 * @param {fs.WriteStream} logStream 日志文件流 * @param {string} message 日志消息 * @param {string} type 日志类型 (stdout 或 stderr) */ function writeToProxyLog(logStream, message, type = 'stdout') { if (!logStream) return; try { const timestamp = new Date().toISOString(); const logLine = `[${timestamp}] [${type}] ${message}\n`; logStream.write(logLine); } catch (error) { logger.error(`写入代理服务器日志失败: ${error.message}`); } } /** * 启动单个代理服务器 * @param {string} platform 平台类型 * @param {string} proxyType 代理类型 ('main' 或 'others') * @param {number} port 代理服务器端口 * @returns {object} 包含进程和日志流的对象 */ function startSingleProxyServer(platform, proxyType, port) { try { // 获取可执行文件路径 const execPath = getProxyExecutablePath(platform, proxyType); // 检查文件是否存在 if (!fs.existsSync(execPath)) { logger.error(`${proxyType}代理服务器可执行文件不存在: ${execPath}`); return { process: null, logStream: null }; } // 在Linux/Android上,设置可执行权限 if (platform !== 'windows_x64') { try { fs.chmodSync(execPath, '755'); } catch (err) { logger.warn(`无法设置${proxyType}代理服务器可执行权限: ${err.message}`); } } // 创建代理服务器日志文件 const logStream = createProxyLogFile(platform, proxyType); // 启动代理服务器进程 logger.info(`正在启动${platform}平台的${proxyType}代理服务器: ${execPath},端口: ${port}`); // 添加端口参数 const args = port ? [`--port=${port}`] : []; const proxyProcess = spawn(execPath, args, { detached: false, stdio: ['ignore', 'pipe', 'pipe'] }); // 记录代理服务器的详细日志到文件 proxyProcess.stdout.on('data', (data) => { const output = data.toString().trim(); writeToProxyLog(logStream, output, 'stdout'); }); proxyProcess.stderr.on('data', (data) => { const errorOutput = data.toString().trim(); writeToProxyLog(logStream, errorOutput, 'stderr'); // 只在启动失败时记录错误信息到控制台 if (!proxyProcess.startSuccessful && errorOutput.includes('error')) { logger.error(`${proxyType}代理服务器启动错误: ${errorOutput.split('\n')[0]}`); } }); proxyProcess.on('error', (err) => { logger.error(`${proxyType}代理服务器启动失败: ${err.message}`); writeToProxyLog(logStream, `启动失败: ${err.message}`, 'error'); return { process: null, logStream: null }; }); proxyProcess.on('close', (code) => { // 只有在非正常退出时记录到控制台 if (code !== 0) { logger.warn(`${proxyType}代理服务器已退出,代码: ${code}`); } writeToProxyLog(logStream, `进程已退出,退出代码: ${code}`, 'info'); // 关闭日志文件 if (logStream) { logStream.end(); } }); // 等待一段时间确保启动成功 setTimeout(() => { if (proxyProcess && proxyProcess.exitCode === null) { proxyProcess.startSuccessful = true; logger.info(`${proxyType}代理服务器已成功启动`); writeToProxyLog(logStream, `${proxyType}代理服务器已成功启动`, 'info'); } else { logger.error(`${proxyType}代理服务器启动失败或异常退出`); writeToProxyLog(logStream, `${proxyType}代理服务器启动失败或异常退出`, 'error'); } }, 1000); return { process: proxyProcess, logStream }; } catch (error) { logger.error(`启动${proxyType}代理服务器出错: ${error.message}`); return { process: null, logStream: null }; } } /** * 启动代理服务器 * @returns {boolean} 是否成功启动 */ function startProxyServer() { try { // 检查是否启用代理 const useTlsProxy = process.env.USE_TLS_PROXY === 'true'; if (!useTlsProxy) { logger.warn('TLS代理服务器未启用,跳过启动'); return true; } // 检查是否启用辅助代理服务器 const useOthersProxy = process.env.USE_OTHERS_PROXY === 'true'; // 确定要使用的平台 let platform = process.env.PROXY_PLATFORM || 'auto'; if (platform === 'auto') { platform = detectPlatform(); } // 启动主代理服务器(默认使用8080端口) const mainProxy = startSingleProxyServer(platform, 'main', 8080); mainProxyProcess = mainProxy.process; mainProxyLogStream = mainProxy.logStream; // 根据配置决定是否启动辅助代理服务器 if (useOthersProxy) { logger.info('辅助代理服务器已启用,正在启动...'); // 启动others代理服务器(端口 10654) const othersProxy = startSingleProxyServer(platform, 'others', 10654); othersProxyProcess = othersProxy.process; othersProxyLogStream = othersProxy.logStream; // 如果辅助代理启动失败,记录警告 if (!othersProxyProcess) { logger.warn('辅助代理服务器启动失败'); } else { logger.info('辅助代理服务器启动成功'); } } else { logger.warn('辅助代理服务器未启用,跳过启动'); } // 如果主代理启动失败,记录警告 if (!mainProxyProcess) { logger.warn('主代理服务器启动失败'); return false; } return true; } catch (error) { logger.error(`启动代理服务器出错: ${error.message}`); return false; } } /** * 停止代理服务器 */ function stopProxyServer() { const stopSingleProxy = (proxyProcess, logStream, proxyType) => { if (proxyProcess) { logger.info(`正在停止${proxyType}代理服务器...`); writeToProxyLog(logStream, `正在停止${proxyType}代理服务器`, 'info'); // 在Windows上,使用taskkill强制终止 if (os.platform() === 'win32') { try { spawn('taskkill', ['/pid', proxyProcess.pid, '/f', '/t']); } catch (err) { logger.error(`使用taskkill终止${proxyType}代理进程失败: ${err.message}`); writeToProxyLog(logStream, `使用taskkill终止${proxyType}代理进程失败: ${err.message}`, 'error'); } } else { // 在Linux/Mac上直接kill proxyProcess.kill('SIGTERM'); } // 允许一些时间写入最后的日志 setTimeout(() => { // 关闭日志文件 if (logStream) { logStream.end(); } }, 500); } }; // 停止主代理服务器 stopSingleProxy(mainProxyProcess, mainProxyLogStream, 'main'); mainProxyProcess = null; mainProxyLogStream = null; // 停止others代理服务器 stopSingleProxy(othersProxyProcess, othersProxyLogStream, 'others'); othersProxyProcess = null; othersProxyLogStream = null; } // 导出模块 module.exports = { startProxyServer, stopProxyServer };