File size: 10,375 Bytes
0d3f8ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
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
};