| | import { spawn } from 'child_process'; |
| | import { fileURLToPath } from 'url'; |
| | import { dirname, join } from 'path'; |
| | import fs from 'fs'; |
| | import os from 'os'; |
| | import dotenv from 'dotenv'; |
| | import chalk from 'chalk'; |
| |
|
| | |
| | const __filename = fileURLToPath(import.meta.url); |
| | const __dirname = dirname(__filename); |
| |
|
| | |
| | dotenv.config({ path: join(dirname(__dirname), '.env') }); |
| |
|
| | |
| | const logger = { |
| | info: (message) => console.log(chalk.blue(`[ProxyServer] ${message}`)), |
| | error: (message) => console.error(chalk.red(`[ProxyServer] ${message}`)), |
| | warning: (message) => console.warn(chalk.yellow(`[ProxyServer] ${message}`)), |
| | success: (message) => console.log(chalk.green(`[ProxyServer] ${message}`)), |
| | }; |
| |
|
| | class ProxyServer { |
| | constructor() { |
| | this.proxyProcess = null; |
| | this.platform = process.env.PROXY_SERVER_PLATFORM || 'auto'; |
| | this.port = process.env.PROXY_SERVER_PORT || 10655; |
| | this.logPath = process.env.PROXY_SERVER_LOG_PATH || './proxy_server.log'; |
| | this.enabled = process.env.ENABLE_PROXY_SERVER === 'true'; |
| | this.proxyAuthToken = process.env.PROXY_AUTH_TOKEN || 'default_token'; |
| | this.logStream = null; |
| | } |
| |
|
| | |
| | detectPlatform() { |
| | if (this.platform !== 'auto') { |
| | return this.platform; |
| | } |
| |
|
| | const platform = os.platform(); |
| | const arch = os.arch(); |
| |
|
| | if (platform === 'win32') { |
| | return 'windows'; |
| | } else if (platform === 'linux') { |
| | if (arch === 'arm64') { |
| | return 'android'; |
| | } else { |
| | return 'linux'; |
| | } |
| | } else if (platform === 'android') { |
| | return 'android'; |
| | } else { |
| | logger.warning(`未知平台: ${platform}, ${arch}, 默认使用linux版本`); |
| | return 'linux'; |
| | } |
| | } |
| |
|
| | |
| | getProxyServerPath() { |
| | const platform = this.detectPlatform(); |
| | const proxyDir = join(__dirname, 'proxy'); |
| |
|
| | switch (platform) { |
| | case 'windows': |
| | return join(proxyDir, 'chrome_proxy_server_windows_amd64.exe'); |
| | case 'linux': |
| | return join(proxyDir, 'chrome_proxy_server_linux_amd64'); |
| | case 'android': |
| | return join(proxyDir, 'chrome_proxy_server_android_arm64'); |
| | default: |
| | logger.error(`不支持的平台: ${platform}`); |
| | return null; |
| | } |
| | } |
| |
|
| | |
| | async start() { |
| | if (!this.enabled) { |
| | logger.info('代理服务器未启用,跳过启动'); |
| | return; |
| | } |
| |
|
| | if (this.proxyProcess) { |
| | logger.warning('代理服务器已经在运行中'); |
| | return; |
| | } |
| |
|
| | const proxyServerPath = this.getProxyServerPath(); |
| | if (!proxyServerPath) { |
| | logger.error('无法获取代理服务器路径'); |
| | return; |
| | } |
| |
|
| | try { |
| | |
| | if (this.detectPlatform() !== 'windows') { |
| | try { |
| | fs.chmodSync(proxyServerPath, 0o755); |
| | } catch (err) { |
| | logger.warning(`无法设置执行权限: ${err.message}`); |
| | } |
| | } |
| |
|
| | |
| | this.logStream = fs.createWriteStream(this.logPath, { flags: 'a' }); |
| | |
| | |
| | |
| | this.proxyProcess = spawn(proxyServerPath, [ |
| | '--port', this.port.toString(), |
| | '--token', this.proxyAuthToken |
| | ], { |
| | stdio: ['ignore', 'pipe', 'pipe'], |
| | detached: false |
| | }); |
| |
|
| | |
| | if (this.proxyProcess.stdout) { |
| | this.proxyProcess.stdout.pipe(this.logStream); |
| | } |
| | |
| | if (this.proxyProcess.stderr) { |
| | this.proxyProcess.stderr.pipe(this.logStream); |
| | } |
| |
|
| | |
| | this.proxyProcess.on('error', (err) => { |
| | logger.error(`代理服务器启动失败: ${err.message}`); |
| | this.proxyProcess = null; |
| | if (this.logStream) { |
| | this.logStream.end(); |
| | this.logStream = null; |
| | } |
| | }); |
| |
|
| | this.proxyProcess.on('exit', (code, signal) => { |
| | logger.info(`代理服务器已退出,退出码: ${code}, 信号: ${signal}`); |
| | this.proxyProcess = null; |
| | if (this.logStream) { |
| | this.logStream.end(); |
| | this.logStream = null; |
| | } |
| | }); |
| |
|
| | |
| | await new Promise(resolve => setTimeout(resolve, 1000)); |
| | |
| | if (this.proxyProcess && this.proxyProcess.exitCode === null) { |
| | logger.success(`代理服务器已启动,端口: ${this.port}, 日志文件: ${this.logPath}`); |
| | return true; |
| | } else { |
| | logger.error('代理服务器启动失败'); |
| | if (this.logStream) { |
| | this.logStream.end(); |
| | this.logStream = null; |
| | } |
| | return false; |
| | } |
| | } catch (error) { |
| | logger.error(`启动代理服务器时出错: ${error.message}`); |
| | if (this.logStream) { |
| | this.logStream.end(); |
| | this.logStream = null; |
| | } |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | stop() { |
| | if (!this.proxyProcess) { |
| | |
| | return; |
| | } |
| |
|
| | try { |
| | |
| | if (this.detectPlatform() === 'windows' && this.proxyProcess.pid) { |
| | spawn('taskkill', ['/pid', this.proxyProcess.pid, '/f', '/t']); |
| | } else { |
| | |
| | this.proxyProcess.kill('SIGTERM'); |
| | } |
| |
|
| | logger.success('代理服务器已停止'); |
| | } catch (error) { |
| | logger.error(`停止代理服务器时出错: ${error.message}`); |
| | } finally { |
| | this.proxyProcess = null; |
| | if (this.logStream) { |
| | this.logStream.end(); |
| | this.logStream = null; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | const proxyServer = new ProxyServer(); |
| |
|
| | |
| | export { proxyServer }; |