@feng3d/cts 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,378 @@
1
+ /**
2
+ * @module control-handler
3
+ * @description 控制通道处理器模块,负责处理客户端通过 WebSocket 控制通道发送的各类控制消息。
4
+ * 包括认证、端口注册/注销、心跳以及断开连接等消息的处理逻辑。
5
+ */
6
+ import { WebSocket } from 'ws';
7
+ import { MessageType, createMessage, logger, } from '@feng3d/chuantou-shared';
8
+ /**
9
+ * 控制通道处理器
10
+ *
11
+ * 处理客户端通过 WebSocket 控制通道发送的各类控制消息,包括:
12
+ * - 客户端认证(AUTH)
13
+ * - 端口注册(REGISTER)与注销(UNREGISTER)
14
+ * - 心跳保活(HEARTBEAT)
15
+ * - 连接断开的清理工作
16
+ */
17
+ export class ControlHandler {
18
+ /**
19
+ * 创建控制通道处理器实例
20
+ *
21
+ * @param sessionManager - 会话管理器,用于管理客户端会话
22
+ * @param config - 服务器配置,包含认证令牌等信息
23
+ * @param proxyHandler - 统一代理处理器,用于启停代理服务器
24
+ */
25
+ constructor(sessionManager, config, proxyHandler) {
26
+ this.sessionManager = sessionManager;
27
+ this.config = config;
28
+ this.proxyHandler = proxyHandler;
29
+ }
30
+ /**
31
+ * 处理新的 WebSocket 控制通道连接
32
+ *
33
+ * 为新连接创建会话,设置消息处理、关闭处理和错误处理回调,
34
+ * 并启动 30 秒认证超时计时器。
35
+ *
36
+ * @param socket - 新建立的 WebSocket 连接
37
+ */
38
+ handleConnection(socket) {
39
+ const clientId = this.sessionManager.createSession(socket);
40
+ logger.log(`新的控制连接来自客户端: ${clientId}`);
41
+ // 设置消息处理器
42
+ socket.on('message', (data) => {
43
+ this.handleMessage(clientId, socket, data).catch((error) => {
44
+ logger.error(`处理来自 ${clientId} 的消息时出错:`, error);
45
+ this.sendError(socket, `内部错误: ${error.message}`);
46
+ });
47
+ });
48
+ // 设置关闭处理器
49
+ socket.on('close', () => {
50
+ logger.log(`控制连接已关闭: ${clientId}`);
51
+ this.handleDisconnect(clientId);
52
+ });
53
+ // 设置错误处理器
54
+ socket.on('error', (error) => {
55
+ logger.error(`客户端 ${clientId} 的 Socket 错误:`, error);
56
+ });
57
+ // 设置认证超时
58
+ const authTimeout = setTimeout(() => {
59
+ const clientInfo = this.sessionManager.getClientInfo(clientId);
60
+ if (clientInfo && !clientInfo.authenticated) {
61
+ logger.log(`客户端 ${clientId} 认证超时`);
62
+ socket.close();
63
+ }
64
+ }, 30000); // 30秒认证超时
65
+ // 存储超时引用,以便在认证成功后清除
66
+ socket._authTimeout = authTimeout;
67
+ }
68
+ /**
69
+ * 处理收到的控制消息
70
+ *
71
+ * 解析 JSON 消息并根据消息类型分发到对应的处理方法。
72
+ * 支持的消息类型包括:AUTH、REGISTER、UNREGISTER、HEARTBEAT。
73
+ *
74
+ * @param clientId - 发送消息的客户端 ID
75
+ * @param socket - 客户端的 WebSocket 连接
76
+ * @param data - 收到的原始消息数据
77
+ */
78
+ async handleMessage(clientId, socket, data) {
79
+ try {
80
+ const message = JSON.parse(data.toString());
81
+ const msgType = message.type;
82
+ logger.log(`收到来自 ${clientId} 的消息: ${msgType}`);
83
+ switch (msgType) {
84
+ case MessageType.AUTH:
85
+ await this.handleAuth(clientId, socket, message);
86
+ break;
87
+ case MessageType.REGISTER:
88
+ await this.handleRegister(clientId, socket, message);
89
+ break;
90
+ case MessageType.UNREGISTER:
91
+ await this.handleUnregister(clientId, socket, message);
92
+ break;
93
+ case MessageType.HEARTBEAT:
94
+ await this.handleHeartbeat(clientId, socket, message);
95
+ break;
96
+ case 'http_response':
97
+ case 'http_response_headers':
98
+ case 'http_response_body':
99
+ // 普通HTTP响应或流式响应头/体
100
+ this.handleClientResponse(message.connectionId, message);
101
+ break;
102
+ case 'http_response_data':
103
+ // 流式响应数据块
104
+ this.handleClientStreamData(message.connectionId, Buffer.from(message.data, 'base64'));
105
+ break;
106
+ case 'http_response_end':
107
+ // 流式响应结束
108
+ this.handleClientStreamEnd(message.connectionId);
109
+ break;
110
+ case 'connection_data':
111
+ // 客户端发送的格式: { type: 'connection_data', connectionId, data }
112
+ this.handleClientData(message.connectionId, Buffer.from(message.data, 'base64'));
113
+ break;
114
+ case MessageType.CONNECTION_CLOSE:
115
+ this.handleClientClose(message.payload.connectionId);
116
+ break;
117
+ default:
118
+ logger.warn(`未知的消息类型: ${msgType}`);
119
+ this.sendError(socket, `未知的消息类型: ${msgType}`);
120
+ }
121
+ }
122
+ catch (error) {
123
+ logger.error(`解析来自 ${clientId} 的消息时出错:`, error);
124
+ this.sendError(socket, '无效的消息格式');
125
+ }
126
+ }
127
+ /**
128
+ * 处理认证消息
129
+ *
130
+ * 验证客户端提供的令牌是否在配置的有效令牌列表中。
131
+ * 认证成功后清除认证超时计时器;认证失败则关闭连接。
132
+ *
133
+ * @param clientId - 客户端唯一标识 ID
134
+ * @param socket - 客户端的 WebSocket 连接
135
+ * @param message - 收到的认证消息
136
+ */
137
+ async handleAuth(clientId, socket, message) {
138
+ const { token } = message.payload;
139
+ if (!token) {
140
+ this.sendMessage(socket, createMessage(MessageType.AUTH_RESP, {
141
+ success: false,
142
+ error: '令牌不能为空',
143
+ }, message.id));
144
+ socket.close();
145
+ return;
146
+ }
147
+ if (!this.config.authTokens.includes(token)) {
148
+ this.sendMessage(socket, createMessage(MessageType.AUTH_RESP, {
149
+ success: false,
150
+ error: '无效的令牌',
151
+ }, message.id));
152
+ socket.close();
153
+ return;
154
+ }
155
+ const authenticated = this.sessionManager.authenticateClient(clientId);
156
+ if (authenticated) {
157
+ // 清除认证超时
158
+ const authTimeout = socket._authTimeout;
159
+ if (authTimeout) {
160
+ clearTimeout(authTimeout);
161
+ delete socket._authTimeout;
162
+ }
163
+ this.sendMessage(socket, createMessage(MessageType.AUTH_RESP, {
164
+ success: true,
165
+ }, message.id));
166
+ logger.log(`客户端 ${clientId} 认证成功`);
167
+ }
168
+ else {
169
+ this.sendMessage(socket, createMessage(MessageType.AUTH_RESP, {
170
+ success: false,
171
+ error: '认证失败',
172
+ }, message.id));
173
+ socket.close();
174
+ }
175
+ }
176
+ /**
177
+ * 处理端口注册消息
178
+ *
179
+ * 验证客户端认证状态和端口范围(1024-65535),检查端口是否已被占用,
180
+ * 然后注册端口并启动代理服务器(同时支持 HTTP 和 WebSocket)。
181
+ * 若启动失败则自动回滚端口注册。
182
+ *
183
+ * @param clientId - 客户端唯一标识 ID
184
+ * @param socket - 客户端的 WebSocket 连接
185
+ * @param message - 收到的端口注册消息
186
+ */
187
+ async handleRegister(clientId, socket, message) {
188
+ const clientInfo = this.sessionManager.getClientInfo(clientId);
189
+ if (!clientInfo || !clientInfo.authenticated) {
190
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
191
+ success: false,
192
+ error: '未认证',
193
+ }, message.id));
194
+ return;
195
+ }
196
+ const { remotePort, localPort, localHost } = message.payload;
197
+ // 验证端口
198
+ if (remotePort < 1024 || remotePort > 65535) {
199
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
200
+ success: false,
201
+ error: '端口超出范围 (1024-65535)',
202
+ }, message.id));
203
+ return;
204
+ }
205
+ // 检查端口是否已被注册
206
+ const existingClientId = this.sessionManager.getClientByPort(remotePort);
207
+ if (existingClientId) {
208
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
209
+ success: false,
210
+ error: '端口已被注册',
211
+ }, message.id));
212
+ return;
213
+ }
214
+ // 注册端口
215
+ const registered = this.sessionManager.registerPort(clientId, remotePort);
216
+ if (!registered) {
217
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
218
+ success: false,
219
+ error: '端口注册失败',
220
+ }, message.id));
221
+ return;
222
+ }
223
+ // 启动代理服务器(同时支持 HTTP 和 WebSocket)
224
+ try {
225
+ await this.proxyHandler.startProxy(remotePort, clientId);
226
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
227
+ success: true,
228
+ remotePort,
229
+ remoteUrl: `http://${this.config.host}:${remotePort}`,
230
+ }, message.id));
231
+ logger.log(`客户端 ${clientId} 注册了代理: 端口 ${remotePort} -> ${localHost || 'localhost'}:${localPort}`);
232
+ }
233
+ catch (error) {
234
+ // 启动代理失败,回滚端口注册
235
+ this.sessionManager.unregisterPort(clientId, remotePort);
236
+ const errorMessage = error instanceof Error ? error.message : String(error);
237
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
238
+ success: false,
239
+ error: `启动代理失败: ${errorMessage}`,
240
+ }, message.id));
241
+ }
242
+ }
243
+ /**
244
+ * 处理端口注销消息
245
+ *
246
+ * 验证客户端认证状态和端口归属,停止代理服务器并注销端口。
247
+ *
248
+ * @param clientId - 客户端唯一标识 ID
249
+ * @param socket - 客户端的 WebSocket 连接
250
+ * @param message - 收到的端口注销消息
251
+ */
252
+ async handleUnregister(clientId, socket, message) {
253
+ const clientInfo = this.sessionManager.getClientInfo(clientId);
254
+ if (!clientInfo || !clientInfo.authenticated) {
255
+ return;
256
+ }
257
+ const { remotePort } = message.payload;
258
+ // 检查端口是否属于该客户端
259
+ if (!clientInfo.registeredPorts.has(remotePort)) {
260
+ this.sendMessage(socket, createMessage(MessageType.REGISTER_RESP, {
261
+ success: false,
262
+ error: '该端口未被此客户端注册',
263
+ }, message.id));
264
+ return;
265
+ }
266
+ // 停止代理
267
+ await this.proxyHandler.stopProxy(remotePort);
268
+ // 注销端口
269
+ const unregistered = this.sessionManager.unregisterPort(clientId, remotePort);
270
+ if (unregistered) {
271
+ logger.log(`客户端 ${clientId} 注销了端口 ${remotePort}`);
272
+ }
273
+ }
274
+ /**
275
+ * 处理心跳消息
276
+ *
277
+ * 更新客户端的最后心跳时间并回复心跳响应。
278
+ *
279
+ * @param clientId - 客户端唯一标识 ID
280
+ * @param socket - 客户端的 WebSocket 连接
281
+ * @param message - 收到的心跳消息
282
+ */
283
+ async handleHeartbeat(clientId, socket, message) {
284
+ this.sessionManager.updateHeartbeat(clientId);
285
+ this.sendMessage(socket, createMessage(MessageType.HEARTBEAT_RESP, {
286
+ timestamp: Date.now(),
287
+ }, message.id));
288
+ }
289
+ /**
290
+ * 处理客户端断开连接
291
+ *
292
+ * 停止该客户端注册的所有代理服务器,并移除其会话。
293
+ *
294
+ * @param clientId - 断开连接的客户端唯一标识 ID
295
+ */
296
+ handleDisconnect(clientId) {
297
+ const clientInfo = this.sessionManager.getClientInfo(clientId);
298
+ if (clientInfo) {
299
+ // 停止所有代理
300
+ for (const port of clientInfo.registeredPorts) {
301
+ this.proxyHandler.stopProxy(port).catch(logger.error);
302
+ }
303
+ }
304
+ this.sessionManager.removeSession(clientId);
305
+ }
306
+ /**
307
+ * 通过 WebSocket 发送消息
308
+ *
309
+ * 将消息对象序列化为 JSON 字符串后发送,仅在连接处于 OPEN 状态时发送。
310
+ *
311
+ * @param socket - 目标 WebSocket 连接
312
+ * @param message - 需要发送的消息对象
313
+ */
314
+ sendMessage(socket, message) {
315
+ if (socket.readyState === WebSocket.OPEN) {
316
+ socket.send(JSON.stringify(message));
317
+ }
318
+ }
319
+ /**
320
+ * 发送错误消息
321
+ *
322
+ * 构造并发送一条 CONNECTION_ERROR 类型的错误消息给客户端。
323
+ *
324
+ * @param socket - 目标 WebSocket 连接
325
+ * @param error - 错误描述信息
326
+ */
327
+ sendError(socket, error) {
328
+ this.sendMessage(socket, createMessage(MessageType.CONNECTION_ERROR, {
329
+ connectionId: '',
330
+ error,
331
+ }));
332
+ }
333
+ /**
334
+ * 处理客户端返回的 HTTP 响应数据
335
+ *
336
+ * @param connectionId - 连接唯一标识 ID
337
+ * @param data - 客户端返回的 HTTP 响应数据
338
+ */
339
+ handleClientResponse(connectionId, data) {
340
+ this.proxyHandler.handleClientResponse(connectionId, data);
341
+ }
342
+ /**
343
+ * 处理来自客户端的 WebSocket 数据
344
+ *
345
+ * @param connectionId - 连接唯一标识 ID
346
+ * @param data - 客户端发送的数据
347
+ */
348
+ handleClientData(connectionId, data) {
349
+ this.proxyHandler.handleClientData(connectionId, data);
350
+ }
351
+ /**
352
+ * 处理来自客户端的连接关闭请求
353
+ *
354
+ * @param connectionId - 需要关闭的连接唯一标识 ID
355
+ * @param code - 可选的关闭状态码
356
+ */
357
+ handleClientClose(connectionId, code) {
358
+ this.proxyHandler.handleClientClose(connectionId, code);
359
+ }
360
+ /**
361
+ * 处理来自客户端的流式响应数据
362
+ *
363
+ * @param connectionId - 连接唯一标识 ID
364
+ * @param data - 客户端发送的流式数据
365
+ */
366
+ handleClientStreamData(connectionId, data) {
367
+ this.proxyHandler.handleClientStreamData(connectionId, data);
368
+ }
369
+ /**
370
+ * 处理来自客户端的流式响应结束通知
371
+ *
372
+ * @param connectionId - 连接唯一标识 ID
373
+ */
374
+ handleClientStreamEnd(connectionId) {
375
+ this.proxyHandler.handleClientStreamEnd(connectionId);
376
+ }
377
+ }
378
+ //# sourceMappingURL=control-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-handler.js","sourceRoot":"","sources":["../../src/handlers/control-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * @module unified-proxy
3
+ * @description 统一代理处理器模块,在指定端口上同时支持 HTTP 和 WebSocket 代理。
4
+ * 将外部 HTTP/WebSocket 请求转发给穿透客户端,实现双向数据转发。
5
+ */
6
+ import { SessionManager } from '../session-manager.js';
7
+ /**
8
+ * 统一代理处理器
9
+ *
10
+ * 管理多个代理服务器实例,每个代理监听一个独立端口,
11
+ * 同时支持 HTTP 请求和 WebSocket 升级请求。
12
+ * 当外部请求到达代理端口时,将请求信息通过控制通道转发给对应的穿透客户端。
13
+ */
14
+ export declare class UnifiedProxyHandler {
15
+ /** 会话管理器实例 */
16
+ private sessionManager;
17
+ /** 代理服务器映射表,键为端口号,值为 HTTP 服务器实例 */
18
+ private proxies;
19
+ /** WebSocket 服务器映射表,用于处理 upgrade 事件 */
20
+ private wsServers;
21
+ /**
22
+ * 待处理响应映射表
23
+ *
24
+ * 存储等待客户端响应的 Promise 回调和超时定时器,键为连接 ID。
25
+ */
26
+ private pendingResponses;
27
+ /**
28
+ * 用户 WebSocket 连接映射表
29
+ *
30
+ * 存储外部用户的 WebSocket 连接,键为连接 ID,值为用户的 WebSocket 实例。
31
+ */
32
+ private userConnections;
33
+ /**
34
+ * 流式 HTTP 响应映射表
35
+ *
36
+ * 存储正在进行的流式响应(如 SSE)的响应对象。
37
+ */
38
+ private streamingResponses;
39
+ /**
40
+ * 创建统一代理处理器实例
41
+ *
42
+ * @param sessionManager - 会话管理器,用于获取客户端连接和管理连接记录
43
+ */
44
+ constructor(sessionManager: SessionManager);
45
+ /**
46
+ * 启动代理服务器
47
+ *
48
+ * 在指定端口创建并启动一个 HTTP 服务器,该端口同时支持 HTTP 请求和 WebSocket 升级。
49
+ * 若该端口已存在代理或端口被占用,将抛出异常。
50
+ *
51
+ * @param port - 代理监听的端口号
52
+ * @param clientId - 绑定的客户端唯一标识 ID
53
+ * @returns 代理服务器启动完成的 Promise
54
+ * @throws 端口已存在代理或端口被占用时抛出错误
55
+ */
56
+ startProxy(port: number, clientId: string): Promise<void>;
57
+ /**
58
+ * 处理外部 HTTP 请求
59
+ *
60
+ * 将外部 HTTP 请求封装为消息发送给穿透客户端,等待客户端处理后返回响应。
61
+ * 支持流式响应(如 SSE)和普通 HTTP 响应。
62
+ *
63
+ * @param clientId - 处理该请求的客户端唯一标识 ID
64
+ * @param req - 收到的 HTTP 请求对象
65
+ * @param res - 用于发送响应的 HTTP 响应对象
66
+ */
67
+ private handleHttpRequest;
68
+ /**
69
+ * 处理 WebSocket 升级请求
70
+ *
71
+ * 将外部 WebSocket 连接桥接到穿透客户端,实现双向实时数据转发。
72
+ *
73
+ * @param clientId - 处理该连接的客户端唯一标识 ID
74
+ * @param req - HTTP 升级请求对象
75
+ * @param socket - 底层 socket 连接
76
+ * @param head - 升级请求的头部 buffer
77
+ */
78
+ private handleWebSocketUpgrade;
79
+ /**
80
+ * 处理 WebSocket 连接
81
+ *
82
+ * 当外部用户连接到代理端口时,记录连接信息,通知穿透客户端有新连接到来,
83
+ * 并设置消息转发、关闭和错误的事件处理。
84
+ *
85
+ * @param clientId - 处理该连接的客户端唯一标识 ID
86
+ * @param connectionId - 连接唯一标识 ID
87
+ * @param userWs - 外部用户的 WebSocket 连接
88
+ * @param req - HTTP 升级请求对象
89
+ */
90
+ private handleWebSocketConnection;
91
+ /**
92
+ * 将用户消息转发到穿透客户端
93
+ *
94
+ * 将外部用户发送的 WebSocket 数据编码为 Base64 后,通过控制通道发送给穿透客户端。
95
+ *
96
+ * @param clientId - 目标客户端唯一标识 ID
97
+ * @param connectionId - 连接唯一标识 ID
98
+ * @param data - 用户发送的原始数据
99
+ */
100
+ private forwardToClient;
101
+ /**
102
+ * 通知穿透客户端连接已关闭
103
+ *
104
+ * 当外部用户的 WebSocket 连接关闭时,向穿透客户端发送连接关闭通知消息。
105
+ *
106
+ * @param clientId - 目标客户端唯一标识 ID
107
+ * @param connectionId - 已关闭的连接唯一标识 ID
108
+ * @param code - WebSocket 关闭状态码
109
+ */
110
+ private notifyClientClose;
111
+ /**
112
+ * 等待客户端响应
113
+ *
114
+ * 创建一个 Promise,等待穿透客户端处理完请求并返回响应数据。
115
+ * 若超过 30 秒未收到响应,将自动超时并拒绝 Promise。
116
+ *
117
+ * @param connectionId - 连接唯一标识 ID
118
+ * @param clientId - 客户端唯一标识 ID
119
+ * @returns 客户端返回的 HTTP 响应数据
120
+ */
121
+ private waitForResponse;
122
+ /**
123
+ * 读取 HTTP 请求体
124
+ *
125
+ * 从 IncomingMessage 流中读取完整的请求体数据。
126
+ *
127
+ * @param req - HTTP 请求对象
128
+ * @returns 包含完整请求体的 Buffer
129
+ */
130
+ private readRequestBody;
131
+ /**
132
+ * 处理穿透客户端返回的响应数据
133
+ *
134
+ * 接收客户端处理完请求后返回的 HTTP 响应数据,清除超时定时器并解析对应的待处理 Promise。
135
+ *
136
+ * @param connectionId - 连接唯一标识 ID
137
+ * @param data - 客户端返回的原始响应消息对象,包含 statusCode, headers, body 等字段
138
+ */
139
+ handleClientResponse(connectionId: string, data: any): void;
140
+ /**
141
+ * 处理来自穿透客户端的数据
142
+ *
143
+ * 将穿透客户端发送的数据转发给对应的外部用户 WebSocket 连接。
144
+ *
145
+ * @param connectionId - 连接唯一标识 ID
146
+ * @param data - 穿透客户端发送的数据
147
+ */
148
+ handleClientData(connectionId: string, data: Buffer): void;
149
+ /**
150
+ * 处理来自穿透客户端的关闭请求
151
+ *
152
+ * 当穿透客户端请求关闭某个连接时,关闭对应的外部用户 WebSocket 连接并清理资源。
153
+ *
154
+ * @param connectionId - 需要关闭的连接唯一标识 ID
155
+ * @param code - 可选的 WebSocket 关闭状态码,默认为 1000(正常关闭)
156
+ */
157
+ handleClientClose(connectionId: string, code?: number): void;
158
+ /**
159
+ * 清理连接资源
160
+ *
161
+ * 从用户连接映射表和会话管理器中移除指定连接的记录。
162
+ *
163
+ * @param connectionId - 需要清理的连接唯一标识 ID
164
+ */
165
+ private cleanupConnection;
166
+ /**
167
+ * 处理来自客户端的流式响应数据
168
+ *
169
+ * 将客户端发送的流式数据(如 SSE 事件)转发给对应的外部 HTTP 连接。
170
+ *
171
+ * @param connectionId - 连接唯一标识 ID
172
+ * @param data - 客户端发送的流式数据
173
+ */
174
+ handleClientStreamData(connectionId: string, data: Buffer): void;
175
+ /**
176
+ * 处理来自客户端的流式响应结束通知
177
+ *
178
+ * 当客户端通知流式响应结束时,关闭外部 HTTP 连接并清理资源。
179
+ *
180
+ * @param connectionId - 连接唯一标识 ID
181
+ */
182
+ handleClientStreamEnd(connectionId: string): void;
183
+ /**
184
+ * 停止指定端口的代理服务器
185
+ *
186
+ * 关闭指定端口上的代理服务器并从映射表中移除。
187
+ *
188
+ * @param port - 需要停止的代理端口号
189
+ * @returns 代理服务器关闭完成的 Promise
190
+ */
191
+ stopProxy(port: number): Promise<void>;
192
+ /**
193
+ * 停止所有代理服务器
194
+ *
195
+ * 并行关闭所有已启动的代理服务器。
196
+ *
197
+ * @returns 所有代理服务器关闭完成的 Promise
198
+ */
199
+ stopAll(): Promise<void>;
200
+ /**
201
+ * 获取所有活跃代理的端口列表
202
+ *
203
+ * @returns 当前正在运行的所有代理端口号数组
204
+ */
205
+ getActivePorts(): number[];
206
+ }
207
+ //# sourceMappingURL=unified-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-proxy.d.ts","sourceRoot":"","sources":["../../src/handlers/unified-proxy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC9B,cAAc;IACd,OAAO,CAAC,cAAc,CAAiB;IACvC,mCAAmC;IACnC,OAAO,CAAC,OAAO,CAA0B;IACzC,uCAAuC;IACvC,OAAO,CAAC,SAAS,CAA+B;IAEhD;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAOT;IAEf;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAqC;IAE5D;;;;OAIG;IACH,OAAO,CAAC,kBAAkB,CAA0C;IAEpE;;;;OAIG;gBACS,cAAc,EAAE,cAAc;IAM1C;;;;;;;;;;OAUG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC/D;;;;;;;;;OASG;YACW,iBAAiB;IAoG/B;;;;;;;;;OASG;YACW,sBAAsB;IAuBpC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB;IAkDjC;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IAWvB;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAWvB;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAavB;;;;;;;OAOG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAe3D;;;;;;;OAOG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAO1D;;;;;;;OAOG;IACH,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ5D;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;;;;OAOG;IACH,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOhE;;;;;;OAMG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IASjD;;;;;;;OAOG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5C;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;OAIG;IACH,cAAc,IAAI,MAAM,EAAE;CAG3B"}