Spaces:
Sleeping
Sleeping
Upload 16 files
Browse files- src/ProxyServer.js +168 -168
- src/lightweight-client.js +37 -19
src/ProxyServer.js
CHANGED
@@ -1,169 +1,169 @@
|
|
1 |
-
import { spawn } from 'child_process';
|
2 |
-
import { fileURLToPath } from 'url';
|
3 |
-
import { dirname, join } from 'path';
|
4 |
-
import fs from 'fs';
|
5 |
-
import os from 'os';
|
6 |
-
import dotenv from 'dotenv';
|
7 |
-
import chalk from 'chalk';
|
8 |
-
|
9 |
-
// 获取当前文件的目录路径
|
10 |
-
const __filename = fileURLToPath(import.meta.url);
|
11 |
-
const __dirname = dirname(__filename);
|
12 |
-
|
13 |
-
// 加载环境变量
|
14 |
-
dotenv.config({ path: join(dirname(__dirname), '.env') });
|
15 |
-
|
16 |
-
// 日志配置
|
17 |
-
const logger = {
|
18 |
-
info: (message) => console.log(chalk.blue(`[ProxyServer] ${message}`)),
|
19 |
-
error: (message) => console.error(chalk.red(`[ProxyServer] ${message}`)),
|
20 |
-
warning: (message) => console.warn(chalk.yellow(`[ProxyServer] ${message}`)),
|
21 |
-
success: (message) => console.log(chalk.green(`[ProxyServer] ${message}`)),
|
22 |
-
};
|
23 |
-
|
24 |
-
class ProxyServer {
|
25 |
-
constructor() {
|
26 |
-
this.proxyProcess = null;
|
27 |
-
this.platform = process.env.PROXY_SERVER_PLATFORM || 'auto';
|
28 |
-
this.port = process.env.PROXY_SERVER_PORT || 10655;
|
29 |
-
this.enabled = process.env.ENABLE_PROXY_SERVER === 'true';
|
30 |
-
this.proxyAuthToken = process.env.PROXY_AUTH_TOKEN || 'default_token';
|
31 |
-
}
|
32 |
-
|
33 |
-
// 获取当前系统平台
|
34 |
-
detectPlatform() {
|
35 |
-
if (this.platform !== 'auto') {
|
36 |
-
return this.platform;
|
37 |
-
}
|
38 |
-
|
39 |
-
const platform = os.platform();
|
40 |
-
const arch = os.arch();
|
41 |
-
|
42 |
-
if (platform === 'win32') {
|
43 |
-
return 'windows';
|
44 |
-
} else if (platform === 'linux') {
|
45 |
-
if (arch === 'arm64') {
|
46 |
-
return 'android';
|
47 |
-
} else {
|
48 |
-
return 'linux';
|
49 |
-
}
|
50 |
-
} else if (platform === 'android') {
|
51 |
-
return 'android';
|
52 |
-
} else {
|
53 |
-
logger.warning(`未知平台: ${platform}, ${arch}, 默认使用linux版本`);
|
54 |
-
return 'linux';
|
55 |
-
}
|
56 |
-
}
|
57 |
-
|
58 |
-
// 获取代理服务器可执行文件路径
|
59 |
-
getProxyServerPath() {
|
60 |
-
const platform = this.detectPlatform();
|
61 |
-
const proxyDir = join(__dirname, 'proxy');
|
62 |
-
|
63 |
-
switch (platform) {
|
64 |
-
case 'windows':
|
65 |
-
return join(proxyDir, 'chrome_proxy_server_windows_amd64.exe');
|
66 |
-
case 'linux':
|
67 |
-
return join(proxyDir, 'chrome_proxy_server_linux_amd64');
|
68 |
-
case 'android':
|
69 |
-
return join(proxyDir, 'chrome_proxy_server_android_arm64');
|
70 |
-
default:
|
71 |
-
logger.error(`不支持的平台: ${platform}`);
|
72 |
-
return null;
|
73 |
-
}
|
74 |
-
}
|
75 |
-
|
76 |
-
// 启动代理服务器
|
77 |
-
async start() {
|
78 |
-
if (!this.enabled) {
|
79 |
-
logger.info('代理服务器未启用,跳过启动');
|
80 |
-
return;
|
81 |
-
}
|
82 |
-
|
83 |
-
if (this.proxyProcess) {
|
84 |
-
logger.warning('代理服务器已经在运行中');
|
85 |
-
return;
|
86 |
-
}
|
87 |
-
|
88 |
-
const proxyServerPath = this.getProxyServerPath();
|
89 |
-
if (!proxyServerPath) {
|
90 |
-
logger.error('无法获取代理服务器路径');
|
91 |
-
return;
|
92 |
-
}
|
93 |
-
|
94 |
-
try {
|
95 |
-
// 启动代理服务器进程
|
96 |
-
this.proxyProcess = spawn(proxyServerPath, [
|
97 |
-
'--port', this.port.toString(),
|
98 |
-
'--token', this.proxyAuthToken
|
99 |
-
], {
|
100 |
-
stdio: ['ignore', 'pipe', 'pipe'], // 使用pipe而不是直接传递流
|
101 |
-
detached: false
|
102 |
-
});
|
103 |
-
|
104 |
-
// 将进程的输出重定向到主进程
|
105 |
-
if (this.proxyProcess.stdout) {
|
106 |
-
this.proxyProcess.stdout.pipe(process.stdout);
|
107 |
-
}
|
108 |
-
|
109 |
-
if (this.proxyProcess.stderr) {
|
110 |
-
this.proxyProcess.stderr.pipe(process.stderr);
|
111 |
-
}
|
112 |
-
|
113 |
-
// 设置进程事件处理
|
114 |
-
this.proxyProcess.on('error', (err) => {
|
115 |
-
logger.error(`代理服务器启动失败: ${err.message}`);
|
116 |
-
this.proxyProcess = null;
|
117 |
-
});
|
118 |
-
|
119 |
-
this.proxyProcess.on('exit', (code, signal) => {
|
120 |
-
logger.info(`代理服务器已退出,退出码: ${code}, 信号: ${signal}`);
|
121 |
-
this.proxyProcess = null;
|
122 |
-
});
|
123 |
-
|
124 |
-
// 等待一段时间,确保服务器启动
|
125 |
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
126 |
-
|
127 |
-
if (this.proxyProcess && this.proxyProcess.exitCode === null) {
|
128 |
-
logger.success(`代理服务器已启动,端口: ${this.port}`);
|
129 |
-
return true;
|
130 |
-
} else {
|
131 |
-
logger.error('代理服务器启动失败');
|
132 |
-
return false;
|
133 |
-
}
|
134 |
-
} catch (error) {
|
135 |
-
logger.error(`启动代理服务器时出错: ${error.message}`);
|
136 |
-
return false;
|
137 |
-
}
|
138 |
-
}
|
139 |
-
|
140 |
-
// 停止代理服务器
|
141 |
-
stop() {
|
142 |
-
if (!this.proxyProcess) {
|
143 |
-
//logger.info('代理服务器已关闭');
|
144 |
-
return;
|
145 |
-
}
|
146 |
-
|
147 |
-
try {
|
148 |
-
// 在Windows上使用taskkill确保子进程也被终止
|
149 |
-
if (this.detectPlatform() === 'windows' && this.proxyProcess.pid) {
|
150 |
-
spawn('taskkill', ['/pid', this.proxyProcess.pid, '/f', '/t']);
|
151 |
-
} else {
|
152 |
-
// 在Linux/Android上使用kill信号
|
153 |
-
this.proxyProcess.kill('SIGTERM');
|
154 |
-
}
|
155 |
-
|
156 |
-
logger.success('代理服务器已停止');
|
157 |
-
} catch (error) {
|
158 |
-
logger.error(`停止代理服务器时出错: ${error.message}`);
|
159 |
-
} finally {
|
160 |
-
this.proxyProcess = null;
|
161 |
-
}
|
162 |
-
}
|
163 |
-
}
|
164 |
-
|
165 |
-
// 创建单例
|
166 |
-
const proxyServer = new ProxyServer();
|
167 |
-
|
168 |
-
// 导出
|
169 |
export { proxyServer };
|
|
|
1 |
+
import { spawn } from 'child_process';
|
2 |
+
import { fileURLToPath } from 'url';
|
3 |
+
import { dirname, join } from 'path';
|
4 |
+
import fs from 'fs';
|
5 |
+
import os from 'os';
|
6 |
+
import dotenv from 'dotenv';
|
7 |
+
import chalk from 'chalk';
|
8 |
+
|
9 |
+
// 获取当前文件的目录路径
|
10 |
+
const __filename = fileURLToPath(import.meta.url);
|
11 |
+
const __dirname = dirname(__filename);
|
12 |
+
|
13 |
+
// 加载环境变量
|
14 |
+
dotenv.config({ path: join(dirname(__dirname), '.env') });
|
15 |
+
|
16 |
+
// 日志配置
|
17 |
+
const logger = {
|
18 |
+
info: (message) => console.log(chalk.blue(`[ProxyServer] ${message}`)),
|
19 |
+
error: (message) => console.error(chalk.red(`[ProxyServer] ${message}`)),
|
20 |
+
warning: (message) => console.warn(chalk.yellow(`[ProxyServer] ${message}`)),
|
21 |
+
success: (message) => console.log(chalk.green(`[ProxyServer] ${message}`)),
|
22 |
+
};
|
23 |
+
|
24 |
+
class ProxyServer {
|
25 |
+
constructor() {
|
26 |
+
this.proxyProcess = null;
|
27 |
+
this.platform = process.env.PROXY_SERVER_PLATFORM || 'auto';
|
28 |
+
this.port = process.env.PROXY_SERVER_PORT || 10655;
|
29 |
+
this.enabled = process.env.ENABLE_PROXY_SERVER === 'true';
|
30 |
+
this.proxyAuthToken = process.env.PROXY_AUTH_TOKEN || 'default_token';
|
31 |
+
}
|
32 |
+
|
33 |
+
// 获取当前系统平台
|
34 |
+
detectPlatform() {
|
35 |
+
if (this.platform !== 'auto') {
|
36 |
+
return this.platform;
|
37 |
+
}
|
38 |
+
|
39 |
+
const platform = os.platform();
|
40 |
+
const arch = os.arch();
|
41 |
+
|
42 |
+
if (platform === 'win32') {
|
43 |
+
return 'windows';
|
44 |
+
} else if (platform === 'linux') {
|
45 |
+
if (arch === 'arm64') {
|
46 |
+
return 'android';
|
47 |
+
} else {
|
48 |
+
return 'linux';
|
49 |
+
}
|
50 |
+
} else if (platform === 'android') {
|
51 |
+
return 'android';
|
52 |
+
} else {
|
53 |
+
logger.warning(`未知平台: ${platform}, ${arch}, 默认使用linux版本`);
|
54 |
+
return 'linux';
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
// 获取代理服务器可执行文件路径
|
59 |
+
getProxyServerPath() {
|
60 |
+
const platform = this.detectPlatform();
|
61 |
+
const proxyDir = join(__dirname, 'proxy');
|
62 |
+
|
63 |
+
switch (platform) {
|
64 |
+
case 'windows':
|
65 |
+
return join(proxyDir, 'chrome_proxy_server_windows_amd64.exe');
|
66 |
+
case 'linux':
|
67 |
+
return join(proxyDir, 'chrome_proxy_server_linux_amd64');
|
68 |
+
case 'android':
|
69 |
+
return join(proxyDir, 'chrome_proxy_server_android_arm64');
|
70 |
+
default:
|
71 |
+
logger.error(`不支持的平台: ${platform}`);
|
72 |
+
return null;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
// 启动代理服务器
|
77 |
+
async start() {
|
78 |
+
if (!this.enabled) {
|
79 |
+
logger.info('代理服务器未启用,跳过启动');
|
80 |
+
return;
|
81 |
+
}
|
82 |
+
|
83 |
+
if (this.proxyProcess) {
|
84 |
+
logger.warning('代理服务器已经在运行中');
|
85 |
+
return;
|
86 |
+
}
|
87 |
+
|
88 |
+
const proxyServerPath = this.getProxyServerPath();
|
89 |
+
if (!proxyServerPath) {
|
90 |
+
logger.error('无法获取代理服务器路径');
|
91 |
+
return;
|
92 |
+
}
|
93 |
+
|
94 |
+
try {
|
95 |
+
// 启动代理服务器进程
|
96 |
+
this.proxyProcess = spawn(proxyServerPath, [
|
97 |
+
'--port', this.port.toString(),
|
98 |
+
'--token', this.proxyAuthToken
|
99 |
+
], {
|
100 |
+
stdio: ['ignore', 'pipe', 'pipe'], // 使用pipe而不是直接传递流
|
101 |
+
detached: false
|
102 |
+
});
|
103 |
+
|
104 |
+
// 将进程的输出重定向到主进程
|
105 |
+
if (this.proxyProcess.stdout) {
|
106 |
+
this.proxyProcess.stdout.pipe(process.stdout);
|
107 |
+
}
|
108 |
+
|
109 |
+
if (this.proxyProcess.stderr) {
|
110 |
+
this.proxyProcess.stderr.pipe(process.stderr);
|
111 |
+
}
|
112 |
+
|
113 |
+
// 设置进程事件处理
|
114 |
+
this.proxyProcess.on('error', (err) => {
|
115 |
+
logger.error(`代理服务器启动失败: ${err.message}`);
|
116 |
+
this.proxyProcess = null;
|
117 |
+
});
|
118 |
+
|
119 |
+
this.proxyProcess.on('exit', (code, signal) => {
|
120 |
+
logger.info(`代理服务器已退出,退出码: ${code}, 信号: ${signal}`);
|
121 |
+
this.proxyProcess = null;
|
122 |
+
});
|
123 |
+
|
124 |
+
// 等待一段时间,确保服务器启动
|
125 |
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
126 |
+
|
127 |
+
if (this.proxyProcess && this.proxyProcess.exitCode === null) {
|
128 |
+
logger.success(`代理服务器已启动,端口: ${this.port}`);
|
129 |
+
return true;
|
130 |
+
} else {
|
131 |
+
logger.error('代理服务器启动失败');
|
132 |
+
return false;
|
133 |
+
}
|
134 |
+
} catch (error) {
|
135 |
+
logger.error(`启动代理服务器时出错: ${error.message}`);
|
136 |
+
return false;
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
// 停止代理服务器
|
141 |
+
stop() {
|
142 |
+
if (!this.proxyProcess) {
|
143 |
+
//logger.info('代理服务器已关闭');
|
144 |
+
return;
|
145 |
+
}
|
146 |
+
|
147 |
+
try {
|
148 |
+
// 在Windows上使用taskkill确保子进程也被终止
|
149 |
+
if (this.detectPlatform() === 'windows' && this.proxyProcess.pid) {
|
150 |
+
spawn('taskkill', ['/pid', this.proxyProcess.pid, '/f', '/t']);
|
151 |
+
} else {
|
152 |
+
// 在Linux/Android上使用kill信号
|
153 |
+
this.proxyProcess.kill('SIGTERM');
|
154 |
+
}
|
155 |
+
|
156 |
+
logger.success('代理服务器已停止');
|
157 |
+
} catch (error) {
|
158 |
+
logger.error(`停止代理服务器时出错: ${error.message}`);
|
159 |
+
} finally {
|
160 |
+
this.proxyProcess = null;
|
161 |
+
}
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
// 创建单例
|
166 |
+
const proxyServer = new ProxyServer();
|
167 |
+
|
168 |
+
// 导出
|
169 |
export { proxyServer };
|
src/lightweight-client.js
CHANGED
@@ -14,6 +14,8 @@ import {
|
|
14 |
import { proxyPool } from './ProxyPool.js';
|
15 |
import { proxyServer } from './ProxyServer.js';
|
16 |
import { cookieManager } from './CookieManager.js';
|
|
|
|
|
17 |
|
18 |
// 获取当前文件的目录路径
|
19 |
const __filename = fileURLToPath(import.meta.url);
|
@@ -380,34 +382,50 @@ async function fetchNotionResponse(chunkQueue, notionRequestBody, headers, notio
|
|
380 |
// 创建fetch选项
|
381 |
const fetchOptions = {
|
382 |
method: 'POST',
|
383 |
-
headers:
|
384 |
-
...headers,
|
385 |
-
'user-agent': window.navigator.userAgent,
|
386 |
-
'Cookie': notionCookie
|
387 |
-
},
|
388 |
body: JSON.stringify(notionRequestBody),
|
|
|
389 |
};
|
390 |
|
391 |
-
//
|
392 |
if (USE_NATIVE_PROXY_POOL && ENABLE_PROXY_SERVER && !PROXY_URL) {
|
393 |
-
proxy = proxyPool.getProxy();
|
394 |
-
if (proxy
|
395 |
-
|
396 |
-
logger.info(
|
397 |
-
}
|
398 |
-
|
399 |
-
logger.warning(`没有可用代理`);
|
400 |
}
|
401 |
} else if(USE_NATIVE_PROXY_POOL&&!PROXY_URL&&!ENABLE_PROXY_SERVER) {
|
402 |
-
const
|
403 |
-
|
404 |
-
|
405 |
-
|
|
|
|
|
|
|
406 |
}else if(PROXY_URL){
|
407 |
-
|
408 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
409 |
logger.info(`使用代理: ${PROXY_URL}`);
|
410 |
}
|
|
|
|
|
|
|
|
|
|
|
411 |
let response = null;
|
412 |
// 发送请求
|
413 |
if (ENABLE_PROXY_SERVER && USE_NATIVE_PROXY_POOL){
|
|
|
14 |
import { proxyPool } from './ProxyPool.js';
|
15 |
import { proxyServer } from './ProxyServer.js';
|
16 |
import { cookieManager } from './CookieManager.js';
|
17 |
+
import { HttpsProxyAgent } from 'https-proxy-agent';
|
18 |
+
import dns from 'dns';
|
19 |
|
20 |
// 获取当前文件的目录路径
|
21 |
const __filename = fileURLToPath(import.meta.url);
|
|
|
382 |
// 创建fetch选项
|
383 |
const fetchOptions = {
|
384 |
method: 'POST',
|
385 |
+
headers: headers,
|
|
|
|
|
|
|
|
|
386 |
body: JSON.stringify(notionRequestBody),
|
387 |
+
timeout: 120000 // 120s
|
388 |
};
|
389 |
|
390 |
+
// 根据条件添加代理
|
391 |
if (USE_NATIVE_PROXY_POOL && ENABLE_PROXY_SERVER && !PROXY_URL) {
|
392 |
+
const proxy = await proxyPool.getProxy();
|
393 |
+
if (proxy) {
|
394 |
+
fetchOptions.agent = new HttpsProxyAgent(proxy.url);
|
395 |
+
logger.info(`使用原生代理池: ${proxy.url} (来自 ${proxy.source})`);
|
396 |
+
} else {
|
397 |
+
logger.warning("原生代理池已启用但没有可用的代理,将不使用代理");
|
|
|
398 |
}
|
399 |
} else if(USE_NATIVE_PROXY_POOL&&!PROXY_URL&&!ENABLE_PROXY_SERVER) {
|
400 |
+
const proxy = await proxyPool.getProxy();
|
401 |
+
if (proxy) {
|
402 |
+
fetchOptions.agent = new HttpsProxyAgent(proxy.url);
|
403 |
+
logger.info(`使用原生代理池: ${proxy.url} (来自 ${proxy.source})`);
|
404 |
+
} else {
|
405 |
+
logger.warning("原生代理池已启用但没有可用的代理,将不使用代理");
|
406 |
+
}
|
407 |
}else if(PROXY_URL){
|
408 |
+
// IPv6 优先
|
409 |
+
const customLookup = (hostname, options, callback) => {
|
410 |
+
dns.lookup(hostname, { family: 6 }, (err, address, family) => {
|
411 |
+
if (err) {
|
412 |
+
// 如果 IPv6 查询失败,则回退到 IPv4
|
413 |
+
dns.lookup(hostname, { family: 4 }, (err, address, family) => {
|
414 |
+
callback(err, address, family);
|
415 |
+
});
|
416 |
+
} else {
|
417 |
+
callback(err, address, family);
|
418 |
+
}
|
419 |
+
});
|
420 |
+
};
|
421 |
+
fetchOptions.agent = new HttpsProxyAgent(PROXY_URL, { lookup: customLookup });
|
422 |
logger.info(`使用代理: ${PROXY_URL}`);
|
423 |
}
|
424 |
+
else if (ENABLE_PROXY_SERVER && !USE_NATIVE_PROXY_POOL && !PROXY_URL){
|
425 |
+
const proxy = await proxyPool.getProxy();
|
426 |
+
fetchOptions.agent = new HttpsProxyAgent(proxy.url);
|
427 |
+
logger.info(`使用代理: ${proxy.url} (来自 ${proxy.source})`);
|
428 |
+
}
|
429 |
let response = null;
|
430 |
// 发送请求
|
431 |
if (ENABLE_PROXY_SERVER && USE_NATIVE_PROXY_POOL){
|