@feng3d/ctc 0.0.10 → 0.0.12
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.
- package/README.md +17 -32
- package/dist/admin-server.d.ts +65 -12
- package/dist/admin-server.d.ts.map +1 -1
- package/dist/admin-server.js +291 -564
- package/dist/admin-server.js.map +1 -1
- package/dist/cli.d.ts +12 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +931 -311
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -11
- package/dist/config.js.map +1 -1
- package/dist/controller.d.ts +27 -124
- package/dist/controller.d.ts.map +1 -1
- package/dist/controller.js +77 -139
- package/dist/controller.js.map +1 -1
- package/dist/data-channel.d.ts +76 -0
- package/dist/data-channel.d.ts.map +1 -0
- package/dist/data-channel.js +222 -0
- package/dist/data-channel.js.map +1 -0
- package/dist/forward-proxy.d.ts +100 -0
- package/dist/forward-proxy.d.ts.map +1 -0
- package/dist/forward-proxy.js +407 -0
- package/dist/forward-proxy.js.map +1 -0
- package/dist/handlers/unified-handler.d.ts +33 -75
- package/dist/handlers/unified-handler.d.ts.map +1 -1
- package/dist/handlers/unified-handler.js +191 -315
- package/dist/handlers/unified-handler.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +135 -36
- package/dist/index.js.map +1 -1
- package/dist/ipc-handler.d.ts +52 -0
- package/dist/ipc-handler.d.ts.map +1 -0
- package/dist/ipc-handler.js +110 -0
- package/dist/ipc-handler.js.map +1 -0
- package/dist/proxy-manager.d.ts +13 -6
- package/dist/proxy-manager.d.ts.map +1 -1
- package/dist/proxy-manager.js +58 -23
- package/dist/proxy-manager.js.map +1 -1
- package/package.json +9 -5
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module forward-proxy
|
|
3
|
+
*
|
|
4
|
+
* 正向穿透代理模块。
|
|
5
|
+
*
|
|
6
|
+
* 实现从本地端口到远程客户端端口的穿透功能。
|
|
7
|
+
* 用户连接本地端口 → 通过中继服务器数据通道 → 连接到目标客户端的指定端口。
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { createServer as createTcpServer, Socket } from 'net';
|
|
11
|
+
import { MessageType, createMessage, logger, } from '@feng3d/chuantou-shared';
|
|
12
|
+
/**
|
|
13
|
+
* 正向穿透代理类
|
|
14
|
+
*
|
|
15
|
+
* 管理从本地端口到远程客户端的穿透映射。
|
|
16
|
+
* 支持两种角色:
|
|
17
|
+
* - 发起方: 用户连接本地端口,数据转发到目标客户端
|
|
18
|
+
* - 目标方: 接受来自其他客户端的连接,转发到本地服务
|
|
19
|
+
*/
|
|
20
|
+
export class ForwardProxy extends EventEmitter {
|
|
21
|
+
constructor(controller) {
|
|
22
|
+
super();
|
|
23
|
+
this.proxies = new Map();
|
|
24
|
+
this.servers = new Map();
|
|
25
|
+
// 会话信息 (sessionId -> ForwardSession)
|
|
26
|
+
this.sessions = new Map();
|
|
27
|
+
this.controller = controller;
|
|
28
|
+
// 监听控制通道消息
|
|
29
|
+
this.setupMessageHandlers();
|
|
30
|
+
// 监听数据通道消息
|
|
31
|
+
this.setupDataChannelHandlers();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 设置消息处理器
|
|
35
|
+
*/
|
|
36
|
+
setupMessageHandlers() {
|
|
37
|
+
// 监听控制通道消息
|
|
38
|
+
this.controller.on('controlMessage', (message) => {
|
|
39
|
+
switch (message.type) {
|
|
40
|
+
case MessageType.INCOMING_CONNECTION:
|
|
41
|
+
this.handleIncomingConnection(message);
|
|
42
|
+
break;
|
|
43
|
+
case MessageType.CONNECTION_ESTABLISHED:
|
|
44
|
+
this.handleConnectionEstablished(message);
|
|
45
|
+
break;
|
|
46
|
+
case MessageType.CONNECTION_ERROR:
|
|
47
|
+
this.handleConnectionError(message);
|
|
48
|
+
break;
|
|
49
|
+
case MessageType.PROXY_TARGET_PORT:
|
|
50
|
+
this.handleProxyTargetPort(message);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 设置数据通道处理器
|
|
57
|
+
*/
|
|
58
|
+
setupDataChannelHandlers() {
|
|
59
|
+
const dataChannel = this.controller.getDataChannel();
|
|
60
|
+
// 监听来自服务端的数据帧
|
|
61
|
+
dataChannel.on('data', (sessionId, data) => {
|
|
62
|
+
this.handleDataChannelData(sessionId, data);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 处理数据通道数据
|
|
67
|
+
*/
|
|
68
|
+
handleDataChannelData(sessionId, data) {
|
|
69
|
+
const session = this.sessions.get(sessionId);
|
|
70
|
+
if (!session) {
|
|
71
|
+
logger.warn(`收到未知会话 ${sessionId} 的数据`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (session.status !== 'connected') {
|
|
75
|
+
logger.warn(`会话 ${sessionId} 未连接,丢弃数据`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (session.role === 'initiator' && session.targetSocket) {
|
|
79
|
+
// 数据从目标客户端 -> 本地目标端口
|
|
80
|
+
if (session.targetSocket.writable) {
|
|
81
|
+
session.targetSocket.write(data);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (session.role === 'target') {
|
|
85
|
+
// 数据从发起方 -> 本地服务
|
|
86
|
+
const socket = session.targetSocket;
|
|
87
|
+
if (socket && socket.writable) {
|
|
88
|
+
socket.write(data);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 注册客户端(正向穿透模式)
|
|
94
|
+
*/
|
|
95
|
+
async registerAsClient(description) {
|
|
96
|
+
if (!this.controller.isAuthenticated()) {
|
|
97
|
+
throw new Error('请先连接并认证到服务器');
|
|
98
|
+
}
|
|
99
|
+
const message = createMessage(MessageType.CLIENT_REGISTER, {
|
|
100
|
+
clientId: this.controller.getClientId(),
|
|
101
|
+
description,
|
|
102
|
+
});
|
|
103
|
+
const response = await this.controller.sendRequest(message);
|
|
104
|
+
if (!response.payload.success) {
|
|
105
|
+
throw new Error(`注册失败: ${response.payload.error}`);
|
|
106
|
+
}
|
|
107
|
+
logger.log(`客户端注册成功: ${this.controller.getClientId()} (${description || '无描述'})`);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 获取在线客户端列表
|
|
111
|
+
*/
|
|
112
|
+
async getClientList() {
|
|
113
|
+
if (!this.controller.isAuthenticated()) {
|
|
114
|
+
throw new Error('请先连接并认证到服务器');
|
|
115
|
+
}
|
|
116
|
+
const message = createMessage(MessageType.GET_CLIENT_LIST, {});
|
|
117
|
+
const response = await this.controller.sendRequest(message);
|
|
118
|
+
return response.payload;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 添加正向穿透代理
|
|
122
|
+
*/
|
|
123
|
+
async addProxy(entry) {
|
|
124
|
+
const { localPort, targetClientId, targetPort } = entry;
|
|
125
|
+
// 检查端口是否已被使用
|
|
126
|
+
if (this.proxies.has(localPort)) {
|
|
127
|
+
throw new Error(`本地端口 ${localPort} 已被使用`);
|
|
128
|
+
}
|
|
129
|
+
// 检查端口是否可用
|
|
130
|
+
const isAvailable = await this.isPortAvailable(localPort);
|
|
131
|
+
if (!isAvailable) {
|
|
132
|
+
throw new Error(`本地端口 ${localPort} 已被占用`);
|
|
133
|
+
}
|
|
134
|
+
// 创建 TCP 服务器监听本地端口
|
|
135
|
+
const server = createTcpServer();
|
|
136
|
+
server.on('connection', (socket) => {
|
|
137
|
+
this.handleLocalConnection(socket, localPort, targetClientId, targetPort);
|
|
138
|
+
});
|
|
139
|
+
server.on('error', (error) => {
|
|
140
|
+
logger.error(`代理服务器 ${localPort} 错误:`, error);
|
|
141
|
+
});
|
|
142
|
+
// 启动服务器
|
|
143
|
+
await new Promise((resolve, reject) => {
|
|
144
|
+
server.listen(localPort, '127.0.0.1', () => {
|
|
145
|
+
logger.log(`正向代理已启动: 本地 :${localPort} → ${targetClientId}:${targetPort}`);
|
|
146
|
+
resolve();
|
|
147
|
+
});
|
|
148
|
+
server.on('error', reject);
|
|
149
|
+
});
|
|
150
|
+
this.proxies.set(localPort, entry);
|
|
151
|
+
this.servers.set(localPort, server);
|
|
152
|
+
this.emit('proxyAdded', entry);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 移除正向穿透代理
|
|
156
|
+
*/
|
|
157
|
+
async removeProxy(localPort) {
|
|
158
|
+
const entry = this.proxies.get(localPort);
|
|
159
|
+
if (!entry) {
|
|
160
|
+
throw new Error(`本地端口 ${localPort} 没有代理映射`);
|
|
161
|
+
}
|
|
162
|
+
const server = this.servers.get(localPort);
|
|
163
|
+
if (server) {
|
|
164
|
+
await new Promise((resolve) => {
|
|
165
|
+
server.close(() => resolve());
|
|
166
|
+
});
|
|
167
|
+
this.servers.delete(localPort);
|
|
168
|
+
}
|
|
169
|
+
this.proxies.delete(localPort);
|
|
170
|
+
logger.log(`正向代理已移除: 本地 :${localPort}`);
|
|
171
|
+
this.emit('proxyRemoved', localPort);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 移除指定目标的所有代理
|
|
175
|
+
*/
|
|
176
|
+
async removeByTarget(targetClientId) {
|
|
177
|
+
const toRemove = [];
|
|
178
|
+
for (const [localPort, entry] of this.proxies) {
|
|
179
|
+
if (entry.targetClientId === targetClientId) {
|
|
180
|
+
toRemove.push(localPort);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
for (const localPort of toRemove) {
|
|
184
|
+
await this.removeProxy(localPort);
|
|
185
|
+
}
|
|
186
|
+
return toRemove.length;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 获取所有代理
|
|
190
|
+
*/
|
|
191
|
+
getProxies() {
|
|
192
|
+
return Array.from(this.proxies.values());
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 检查端口是否可用
|
|
196
|
+
*/
|
|
197
|
+
async isPortAvailable(port) {
|
|
198
|
+
return new Promise((resolve) => {
|
|
199
|
+
const tester = createTcpServer()
|
|
200
|
+
.once('error', () => resolve(false))
|
|
201
|
+
.once('listening', () => {
|
|
202
|
+
tester.close();
|
|
203
|
+
resolve(true);
|
|
204
|
+
})
|
|
205
|
+
.listen(port, '127.0.0.1');
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* 处理本地连接(发起方)
|
|
210
|
+
*/
|
|
211
|
+
async handleLocalConnection(localSocket, localPort, targetClientId, targetPort) {
|
|
212
|
+
const sessionId = this.generateSessionId();
|
|
213
|
+
logger.log(`本地连接 :${localPort} → 请求连接到 ${targetClientId}:${targetPort} (会话: ${sessionId})`);
|
|
214
|
+
// 创建会话
|
|
215
|
+
const session = {
|
|
216
|
+
sessionId,
|
|
217
|
+
localPort,
|
|
218
|
+
targetPort,
|
|
219
|
+
targetClientId,
|
|
220
|
+
localSocket,
|
|
221
|
+
status: 'pending',
|
|
222
|
+
role: 'initiator',
|
|
223
|
+
};
|
|
224
|
+
this.sessions.set(sessionId, session);
|
|
225
|
+
// 向服务端发送连接请求
|
|
226
|
+
try {
|
|
227
|
+
const message = createMessage(MessageType.CONNECT_REQUEST, {
|
|
228
|
+
fromClientId: this.controller.getClientId(),
|
|
229
|
+
toClientId: targetClientId,
|
|
230
|
+
targetPort,
|
|
231
|
+
sessionId,
|
|
232
|
+
});
|
|
233
|
+
await this.controller.sendRequest(message, 30000);
|
|
234
|
+
logger.log(`连接请求已发送: ${sessionId}`);
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
logger.error(`发送连接请求失败:`, error);
|
|
238
|
+
localSocket.destroy();
|
|
239
|
+
this.sessions.delete(sessionId);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// 处理本地连接关闭
|
|
243
|
+
localSocket.on('close', () => {
|
|
244
|
+
logger.log(`本地连接已关闭: ${sessionId}`);
|
|
245
|
+
this.cleanupSession(sessionId);
|
|
246
|
+
});
|
|
247
|
+
localSocket.on('error', (error) => {
|
|
248
|
+
logger.error(`本地连接错误 (${sessionId}):`, error);
|
|
249
|
+
this.cleanupSession(sessionId);
|
|
250
|
+
});
|
|
251
|
+
// 将本地连接的数据通过数据通道发送
|
|
252
|
+
localSocket.on('data', (data) => {
|
|
253
|
+
if (session.status === 'connected') {
|
|
254
|
+
const dataChannel = this.controller.getDataChannel();
|
|
255
|
+
dataChannel.sendData(sessionId, data);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* 处理入站连接请求(目标方)
|
|
261
|
+
*/
|
|
262
|
+
async handleIncomingConnection(message) {
|
|
263
|
+
const { sessionId, fromClientId, targetPort } = message.payload;
|
|
264
|
+
logger.log(`收到入站连接请求: ${sessionId} 来自 ${fromClientId} → :${targetPort}`);
|
|
265
|
+
// 自动接受连接
|
|
266
|
+
try {
|
|
267
|
+
const acceptMessage = createMessage(MessageType.ACCEPT_CONNECTION, {
|
|
268
|
+
sessionId,
|
|
269
|
+
});
|
|
270
|
+
await this.controller.sendRequest(acceptMessage);
|
|
271
|
+
logger.log(`已接受入站连接: ${sessionId}`);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
logger.error(`接受入站连接失败:`, error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* 处理连接已建立消息(发起方)
|
|
279
|
+
*/
|
|
280
|
+
async handleConnectionEstablished(message) {
|
|
281
|
+
const { sessionId } = message.payload;
|
|
282
|
+
const session = this.sessions.get(sessionId);
|
|
283
|
+
if (!session) {
|
|
284
|
+
logger.warn(`会话 ${sessionId} 不存在`);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (session.role !== 'initiator') {
|
|
288
|
+
return; // 只处理发起方
|
|
289
|
+
}
|
|
290
|
+
logger.log(`连接已建立: ${sessionId}`);
|
|
291
|
+
session.status = 'connected';
|
|
292
|
+
// 开始将本地 socket 数据通过数据通道转发
|
|
293
|
+
if (session.localSocket) {
|
|
294
|
+
// 重新绑定数据处理器(因为之前绑定在 pending 状态时不发送)
|
|
295
|
+
const dataChannel = this.controller.getDataChannel();
|
|
296
|
+
session.localSocket.on('data', (data) => {
|
|
297
|
+
if (session.status === 'connected') {
|
|
298
|
+
dataChannel.sendData(sessionId, data);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 处理代理目标端口请求(目标方)
|
|
305
|
+
*/
|
|
306
|
+
async handleProxyTargetPort(message) {
|
|
307
|
+
const { sessionId, targetPort } = message.payload;
|
|
308
|
+
logger.log(`收到代理目标端口请求: ${sessionId} → :${targetPort}`);
|
|
309
|
+
// 创建到本地目标端口的连接
|
|
310
|
+
const targetSocket = new Socket();
|
|
311
|
+
try {
|
|
312
|
+
await new Promise((resolve, reject) => {
|
|
313
|
+
targetSocket.on('connect', () => resolve());
|
|
314
|
+
targetSocket.on('error', reject);
|
|
315
|
+
targetSocket.connect(targetPort, '127.0.0.1');
|
|
316
|
+
});
|
|
317
|
+
logger.log(`已连接到本地端口 ${targetPort} (会话: ${sessionId})`);
|
|
318
|
+
// 创建会话
|
|
319
|
+
const session = {
|
|
320
|
+
sessionId,
|
|
321
|
+
localPort: targetPort,
|
|
322
|
+
targetPort,
|
|
323
|
+
targetClientId: '',
|
|
324
|
+
targetSocket,
|
|
325
|
+
status: 'connected',
|
|
326
|
+
role: 'target',
|
|
327
|
+
};
|
|
328
|
+
this.sessions.set(sessionId, session);
|
|
329
|
+
// 将目标端口的数据通过数据通道转发
|
|
330
|
+
targetSocket.on('data', (data) => {
|
|
331
|
+
const dataChannel = this.controller.getDataChannel();
|
|
332
|
+
dataChannel.sendData(sessionId, data);
|
|
333
|
+
});
|
|
334
|
+
targetSocket.on('close', () => {
|
|
335
|
+
logger.log(`目标端口连接已关闭: ${sessionId}`);
|
|
336
|
+
this.cleanupSession(sessionId);
|
|
337
|
+
});
|
|
338
|
+
targetSocket.on('error', (error) => {
|
|
339
|
+
logger.error(`目标端口连接错误 (${sessionId}):`, error);
|
|
340
|
+
this.cleanupSession(sessionId);
|
|
341
|
+
});
|
|
342
|
+
// 通知服务端已连接
|
|
343
|
+
const connectedMessage = createMessage(MessageType.TARGET_PORT_CONNECTED, {
|
|
344
|
+
sessionId,
|
|
345
|
+
});
|
|
346
|
+
await this.controller.sendRequest(connectedMessage);
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
logger.error(`连接到本地端口 ${targetPort} 失败:`, error);
|
|
350
|
+
// 发送错误消息
|
|
351
|
+
const errorMsg = createMessage(MessageType.CONNECTION_ERROR, {
|
|
352
|
+
connectionId: sessionId,
|
|
353
|
+
error: `无法连接到本地端口 ${targetPort}`,
|
|
354
|
+
});
|
|
355
|
+
await this.controller.sendRequest(errorMsg);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* 处理连接错误
|
|
360
|
+
*/
|
|
361
|
+
handleConnectionError(message) {
|
|
362
|
+
const { connectionId: sessionId, error } = message.payload;
|
|
363
|
+
logger.error(`连接错误 (${sessionId}): ${error}`);
|
|
364
|
+
this.cleanupSession(sessionId);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* 清理会话
|
|
368
|
+
*/
|
|
369
|
+
cleanupSession(sessionId) {
|
|
370
|
+
const session = this.sessions.get(sessionId);
|
|
371
|
+
if (session) {
|
|
372
|
+
if (session.localSocket && !session.localSocket.destroyed) {
|
|
373
|
+
session.localSocket.destroy();
|
|
374
|
+
}
|
|
375
|
+
if (session.targetSocket && !session.targetSocket.destroyed) {
|
|
376
|
+
session.targetSocket.destroy();
|
|
377
|
+
}
|
|
378
|
+
session.status = 'closed';
|
|
379
|
+
this.sessions.delete(sessionId);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* 生成会话 ID
|
|
384
|
+
*/
|
|
385
|
+
generateSessionId() {
|
|
386
|
+
return `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* 销毁所有代理
|
|
390
|
+
*/
|
|
391
|
+
async destroy() {
|
|
392
|
+
// 关闭所有服务器
|
|
393
|
+
for (const [localPort, server] of this.servers) {
|
|
394
|
+
await new Promise((resolve) => {
|
|
395
|
+
server.close(() => resolve());
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
// 清理所有会话
|
|
399
|
+
for (const sessionId of this.sessions.keys()) {
|
|
400
|
+
this.cleanupSession(sessionId);
|
|
401
|
+
}
|
|
402
|
+
this.proxies.clear();
|
|
403
|
+
this.servers.clear();
|
|
404
|
+
this.removeAllListeners();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
//# sourceMappingURL=forward-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward-proxy.js","sourceRoot":"","sources":["../src/forward-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,107 +3,65 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 统一代理连接处理器模块。
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* 负责处理通过穿透隧道传输的所有协议连接。
|
|
7
|
+
* TCP 类协议(HTTP/WS/TCP)作为原始字节流通过本地 TCP socket 转发,
|
|
8
|
+
* UDP 通过本地 dgram socket 转发。
|
|
9
|
+
* 不做协议解析,HTTP 和 WebSocket 协议由外部客户端和本地服务端到端处理。
|
|
8
10
|
*/
|
|
9
11
|
import { EventEmitter } from 'events';
|
|
10
12
|
import { Controller } from '../controller.js';
|
|
11
13
|
import { ProxyConfig } from '@feng3d/chuantou-shared';
|
|
12
14
|
/**
|
|
13
|
-
*
|
|
15
|
+
* 统一代理连接处理器
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* 工作流程:
|
|
19
|
-
* 1. 监听控制器的 `newConnection` 事件,接收新的连接请求
|
|
20
|
-
* 2. 根据协议类型(http/websocket)建立相应的本地连接
|
|
21
|
-
* 3. 将本地服务发送的数据转发给服务器
|
|
22
|
-
* 4. 将服务器转发的远程客户端数据转发到本地服务
|
|
23
|
-
* 5. 处理连接关闭和错误情况
|
|
24
|
-
*
|
|
25
|
-
* 触发的事件:
|
|
26
|
-
* - `error` - 处理连接时发生错误
|
|
17
|
+
* 所有 TCP 类协议统一处理:收到 NEW_CONNECTION 后打开本地 TCP socket,
|
|
18
|
+
* 通过二进制数据通道双向管道传输原始字节。
|
|
19
|
+
* UDP 使用独立的 dgram socket 和超时管理。
|
|
27
20
|
*/
|
|
28
21
|
export declare class UnifiedHandler extends EventEmitter {
|
|
29
|
-
/** 控制器实例,用于与服务器通信 */
|
|
30
22
|
private controller;
|
|
31
|
-
|
|
23
|
+
private dataChannel;
|
|
32
24
|
private config;
|
|
33
|
-
/**
|
|
34
|
-
private
|
|
35
|
-
/** 本地
|
|
36
|
-
private
|
|
37
|
-
/**
|
|
38
|
-
private
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
* 并设置数据转发监听器。
|
|
44
|
-
*
|
|
45
|
-
* @param controller - 控制器实例,用于与服务器通信
|
|
46
|
-
* @param config - 代理配置对象,包含本地服务地址和端口
|
|
47
|
-
*/
|
|
25
|
+
/** 本地 TCP 连接映射表:connectionId → Socket */
|
|
26
|
+
private localTcpConnections;
|
|
27
|
+
/** 本地 UDP socket 映射表:connectionId → { socket, timer } */
|
|
28
|
+
private localUdpSockets;
|
|
29
|
+
/** 数据缓冲区:在 NEW_CONNECTION 到达前缓冲的数据帧 */
|
|
30
|
+
private pendingDataBuffers;
|
|
31
|
+
/** 已通知关闭的连接集合,防止重复发送 CONNECTION_CLOSE */
|
|
32
|
+
private closedConnections;
|
|
33
|
+
/** 本地 socket 写入缓慢导致的背压连接集合 */
|
|
34
|
+
private backedUpConnections;
|
|
48
35
|
constructor(controller: Controller, config: ProxyConfig);
|
|
49
36
|
/**
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 处理来自服务器的新 HTTP 连接请求。
|
|
55
|
-
*/
|
|
56
|
-
private handleHttpConnection;
|
|
57
|
-
/**
|
|
58
|
-
* 处理来自服务器的新 WebSocket 连接请求。
|
|
59
|
-
*/
|
|
60
|
-
private handleWebSocketConnection;
|
|
61
|
-
/**
|
|
62
|
-
* 将本地数据转发到服务器。
|
|
63
|
-
*/
|
|
64
|
-
private forwardToServer;
|
|
65
|
-
/**
|
|
66
|
-
* 处理从服务器接收到的远程客户端数据。
|
|
67
|
-
*/
|
|
68
|
-
private handleClientData;
|
|
69
|
-
/**
|
|
70
|
-
* 将 HTTP 响应数据发送回服务器。
|
|
71
|
-
*/
|
|
72
|
-
private sendResponse;
|
|
73
|
-
/**
|
|
74
|
-
* 发送流式响应头(用于 SSE)。
|
|
37
|
+
* 处理 TCP 类协议连接(HTTP/WS/TCP 统一处理)
|
|
38
|
+
*
|
|
39
|
+
* 打开本地 TCP socket,通过数据通道双向管道传输原始字节。
|
|
75
40
|
*/
|
|
76
|
-
private
|
|
41
|
+
private handleTcpConnection;
|
|
77
42
|
/**
|
|
78
|
-
*
|
|
43
|
+
* 处理来自服务器的 TCP 数据(通过数据通道)
|
|
79
44
|
*/
|
|
80
|
-
private
|
|
45
|
+
private handleDataFromServer;
|
|
81
46
|
/**
|
|
82
|
-
*
|
|
47
|
+
* 处理 UDP 连接
|
|
83
48
|
*/
|
|
84
|
-
private
|
|
49
|
+
private handleUdpConnection;
|
|
85
50
|
/**
|
|
86
|
-
*
|
|
51
|
+
* 处理来自服务器的 UDP 数据
|
|
87
52
|
*/
|
|
88
|
-
private
|
|
53
|
+
private handleUdpDataFromServer;
|
|
89
54
|
/**
|
|
90
|
-
*
|
|
55
|
+
* 通知服务器连接已关闭
|
|
91
56
|
*/
|
|
92
57
|
private notifyServerClose;
|
|
93
58
|
/**
|
|
94
|
-
*
|
|
59
|
+
* 处理来自服务器的连接关闭通知
|
|
95
60
|
*/
|
|
96
61
|
private handleConnectionClose;
|
|
62
|
+
private cleanupUdpSocket;
|
|
97
63
|
/**
|
|
98
|
-
*
|
|
99
|
-
*/
|
|
100
|
-
private cleanupWsConnection;
|
|
101
|
-
/**
|
|
102
|
-
* 过滤请求头,移除逐跳头部字段。
|
|
103
|
-
*/
|
|
104
|
-
private filterHeaders;
|
|
105
|
-
/**
|
|
106
|
-
* 销毁处理器,释放所有资源。
|
|
64
|
+
* 销毁处理器,释放所有资源
|
|
107
65
|
*/
|
|
108
66
|
destroy(): void;
|
|
109
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unified-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/unified-handler.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"unified-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/unified-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAoF,MAAM,yBAAyB,CAAC;AAKxI;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,MAAM,CAAc;IAE5B,yCAAyC;IACzC,OAAO,CAAC,mBAAmB,CAAkC;IAE7D,yDAAyD;IACzD,OAAO,CAAC,eAAe,CAAwE;IAE/F,uCAAuC;IACvC,OAAO,CAAC,kBAAkB,CAAoC;IAE9D,yCAAyC;IACzC,OAAO,CAAC,iBAAiB,CAA0B;IAEnD,8BAA8B;IAC9B,OAAO,CAAC,mBAAmB,CAA0B;gBAEzC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW;IAiCvD;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAuD3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAsC5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA+B3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,IAAI,IAAI;CAiBhB"}
|