Spaces:
Paused
Paused
| 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 | |
| }; |