@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.
- package/README.md +150 -0
- package/dist/boot.d.ts +41 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +204 -0
- package/dist/boot.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +377 -0
- package/dist/cli.js.map +1 -0
- package/dist/handlers/control-handler.d.ts +158 -0
- package/dist/handlers/control-handler.d.ts.map +1 -0
- package/dist/handlers/control-handler.js +378 -0
- package/dist/handlers/control-handler.js.map +1 -0
- package/dist/handlers/unified-proxy.d.ts +207 -0
- package/dist/handlers/unified-proxy.d.ts.map +1 -0
- package/dist/handlers/unified-proxy.js +475 -0
- package/dist/handlers/unified-proxy.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +115 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +433 -0
- package/dist/server.js.map +1 -0
- package/dist/session-manager.d.ts +218 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +372 -0
- package/dist/session-manager.js.map +1 -0
- package/package.json +41 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @module cli
|
|
4
|
+
* @description 穿透服务端命令行工具模块。
|
|
5
|
+
* 提供 `feng3d-cts` CLI 命令,支持通过命令行启动、停止和查询转发服务器状态。
|
|
6
|
+
* `start` 以后台守护进程方式运行服务器并注册开机自启动。
|
|
7
|
+
* 使用 PID 文件跟踪运行中的服务器实例,以实现跨进程的状态管理。
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { readFileSync, writeFileSync, mkdirSync, unlinkSync, openSync, closeSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { homedir, platform } from 'os';
|
|
14
|
+
import { request } from 'http';
|
|
15
|
+
import { request as httpsRequest } from 'https';
|
|
16
|
+
import { spawn, execSync } from 'child_process';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
import { start, stop } from './index.js';
|
|
19
|
+
import { registerBoot, unregisterBoot, isBootRegistered } from './boot.js';
|
|
20
|
+
/** PID 文件存放目录路径 */
|
|
21
|
+
const PID_DIR = join(homedir(), '.chuantou');
|
|
22
|
+
/** PID 文件完整路径 */
|
|
23
|
+
const PID_FILE = join(PID_DIR, 'server.pid');
|
|
24
|
+
/** 日志文件路径 */
|
|
25
|
+
const LOG_FILE = join(PID_DIR, 'server.log');
|
|
26
|
+
/**
|
|
27
|
+
* 写入 PID 文件
|
|
28
|
+
*
|
|
29
|
+
* 将服务器进程信息写入 PID 文件,若目录不存在则自动创建。
|
|
30
|
+
*
|
|
31
|
+
* @param info - 需要写入的服务器进程信息
|
|
32
|
+
*/
|
|
33
|
+
function writePidFile(info) {
|
|
34
|
+
mkdirSync(PID_DIR, { recursive: true });
|
|
35
|
+
writeFileSync(PID_FILE, JSON.stringify(info, null, 2));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 读取 PID 文件
|
|
39
|
+
*
|
|
40
|
+
* 从磁盘读取并解析 PID 文件内容,获取运行中服务器的进程信息。
|
|
41
|
+
*
|
|
42
|
+
* @returns 解析后的 {@link PidInfo} 对象;若文件不存在或解析失败则返回 `null`
|
|
43
|
+
*/
|
|
44
|
+
function readPidFile() {
|
|
45
|
+
try {
|
|
46
|
+
const content = readFileSync(PID_FILE, 'utf-8');
|
|
47
|
+
return JSON.parse(content);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 删除 PID 文件
|
|
55
|
+
*
|
|
56
|
+
* 移除磁盘上的 PID 文件。若文件不存在则静默忽略。
|
|
57
|
+
*/
|
|
58
|
+
function removePidFile() {
|
|
59
|
+
try {
|
|
60
|
+
unlinkSync(PID_FILE);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// ignore
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 发送 HTTP GET 请求
|
|
68
|
+
*
|
|
69
|
+
* 向指定地址发送 GET 请求并返回响应内容。支持 HTTP 和 HTTPS。
|
|
70
|
+
* 当 host 为 `0.0.0.0` 时自动替换为 `127.0.0.1`。
|
|
71
|
+
*
|
|
72
|
+
* @param host - 目标主机地址
|
|
73
|
+
* @param port - 目标端口号
|
|
74
|
+
* @param path - 请求路径
|
|
75
|
+
* @param tls - 是否使用 HTTPS
|
|
76
|
+
* @returns 响应体字符串内容
|
|
77
|
+
*/
|
|
78
|
+
function httpGet(host, port, path, tls) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const doRequest = tls ? httpsRequest : request;
|
|
81
|
+
const req = doRequest({ hostname: host === '0.0.0.0' ? '127.0.0.1' : host, port, path, method: 'GET', timeout: 5000 }, (res) => {
|
|
82
|
+
let data = '';
|
|
83
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
84
|
+
res.on('end', () => resolve(data));
|
|
85
|
+
});
|
|
86
|
+
req.on('error', reject);
|
|
87
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
|
|
88
|
+
req.end();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 发送 HTTP POST 请求
|
|
93
|
+
*
|
|
94
|
+
* 向指定地址发送 POST 请求并返回响应内容。支持 HTTP 和 HTTPS。
|
|
95
|
+
* 当 host 为 `0.0.0.0` 时自动替换为 `127.0.0.1`。
|
|
96
|
+
*
|
|
97
|
+
* @param host - 目标主机地址
|
|
98
|
+
* @param port - 目标端口号
|
|
99
|
+
* @param path - 请求路径
|
|
100
|
+
* @param tls - 是否使用 HTTPS
|
|
101
|
+
* @returns 响应体字符串内容
|
|
102
|
+
*/
|
|
103
|
+
function httpPost(host, port, path, tls) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const doRequest = tls ? httpsRequest : request;
|
|
106
|
+
const req = doRequest({ hostname: host === '0.0.0.0' ? '127.0.0.1' : host, port, path, method: 'POST', timeout: 5000 }, (res) => {
|
|
107
|
+
let data = '';
|
|
108
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
109
|
+
res.on('end', () => resolve(data));
|
|
110
|
+
});
|
|
111
|
+
req.on('error', reject);
|
|
112
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
|
|
113
|
+
req.end();
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 等待服务器启动完成
|
|
118
|
+
*
|
|
119
|
+
* 通过轮询 HTTP 状态端点验证后台服务器是否成功启动。
|
|
120
|
+
*
|
|
121
|
+
* @param host - 服务器监听地址
|
|
122
|
+
* @param port - 控制端口
|
|
123
|
+
* @param tls - 是否使用 TLS
|
|
124
|
+
* @param timeoutMs - 最大等待时间(毫秒)
|
|
125
|
+
* @returns 是否成功启动
|
|
126
|
+
*/
|
|
127
|
+
async function waitForStartup(host, port, tls, timeoutMs) {
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
const interval = 500;
|
|
130
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
131
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
132
|
+
try {
|
|
133
|
+
await httpGet(host, port, '/_chuantou/status', tls);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// 未就绪,继续重试
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 在浏览器中打开 URL
|
|
144
|
+
*
|
|
145
|
+
* 根据操作系统使用相应的命令打开默认浏览器。
|
|
146
|
+
*
|
|
147
|
+
* @param url - 需要打开的 URL
|
|
148
|
+
*/
|
|
149
|
+
function openBrowser(url) {
|
|
150
|
+
const os = platform();
|
|
151
|
+
try {
|
|
152
|
+
if (os === 'win32') {
|
|
153
|
+
execSync(`cmd.exe /c start "" "${url}"`, { stdio: 'ignore' });
|
|
154
|
+
}
|
|
155
|
+
else if (os === 'darwin') {
|
|
156
|
+
execSync(`open "${url}"`, { stdio: 'ignore' });
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// Linux
|
|
160
|
+
execSync(`xdg-open "${url}"`, { stdio: 'ignore' });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// 忽略错误,浏览器打开失败不影响服务
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** 服务器选项的 CLI 选项定义,供 start 和 _serve 共用 */
|
|
168
|
+
const serverOptions = [
|
|
169
|
+
['-p, --port <port>', '控制端口', '9000'],
|
|
170
|
+
['-a, --host <address>', '监听地址', '0.0.0.0'],
|
|
171
|
+
['-t, --tokens <tokens>', '认证令牌(逗号分隔)'],
|
|
172
|
+
['--tls-key <path>', 'TLS 私钥文件路径'],
|
|
173
|
+
['--tls-cert <path>', 'TLS 证书文件路径'],
|
|
174
|
+
['--heartbeat-interval <ms>', '心跳间隔(毫秒)', '30000'],
|
|
175
|
+
['--session-timeout <ms>', '会话超时(毫秒)', '60000'],
|
|
176
|
+
];
|
|
177
|
+
const program = new Command();
|
|
178
|
+
program
|
|
179
|
+
.name('feng3d-cts')
|
|
180
|
+
.description(chalk.blue('穿透 - 内网穿透服务端'))
|
|
181
|
+
.version('0.0.5');
|
|
182
|
+
// ====== _serve 命令(隐藏,前台运行,供 start 和开机启动调用)======
|
|
183
|
+
const serveCmd = program.command('_serve', { hidden: true }).description('前台运行服务器(内部命令)');
|
|
184
|
+
for (const opt of serverOptions) {
|
|
185
|
+
if (opt.length === 3) {
|
|
186
|
+
serveCmd.option(opt[0], opt[1], opt[2]);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
serveCmd.option(opt[0], opt[1]);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
serveCmd.action(async (options) => {
|
|
193
|
+
const tls = (options.tlsKey && options.tlsCert)
|
|
194
|
+
? { key: readFileSync(options.tlsKey, 'utf-8'), cert: readFileSync(options.tlsCert, 'utf-8') }
|
|
195
|
+
: undefined;
|
|
196
|
+
const opts = {
|
|
197
|
+
host: options.host,
|
|
198
|
+
controlPort: parseInt(options.port, 10),
|
|
199
|
+
authTokens: options.tokens ? options.tokens.split(',') : [],
|
|
200
|
+
heartbeatInterval: parseInt(options.heartbeatInterval, 10),
|
|
201
|
+
sessionTimeout: parseInt(options.sessionTimeout, 10),
|
|
202
|
+
tls,
|
|
203
|
+
};
|
|
204
|
+
const server = await start(opts);
|
|
205
|
+
writePidFile({
|
|
206
|
+
pid: process.pid,
|
|
207
|
+
host: opts.host,
|
|
208
|
+
controlPort: opts.controlPort,
|
|
209
|
+
tls: tls !== undefined,
|
|
210
|
+
});
|
|
211
|
+
console.log(chalk.green('服务器启动成功'));
|
|
212
|
+
console.log(chalk.gray(` 主机: ${opts.host}`));
|
|
213
|
+
console.log(chalk.gray(` 端口: ${opts.controlPort}`));
|
|
214
|
+
console.log(chalk.gray(` TLS: ${tls ? '已启用' : '已禁用'}`));
|
|
215
|
+
const shutdown = async () => {
|
|
216
|
+
console.log(chalk.yellow('\n正在关闭...'));
|
|
217
|
+
await stop(server);
|
|
218
|
+
removePidFile();
|
|
219
|
+
process.exit(0);
|
|
220
|
+
};
|
|
221
|
+
process.on('SIGINT', shutdown);
|
|
222
|
+
process.on('SIGTERM', shutdown);
|
|
223
|
+
});
|
|
224
|
+
// ====== start 命令(后台守护进程 + 开机启动)======
|
|
225
|
+
const startCmd = program.command('start').description('启动服务器(后台运行并注册开机自启动)');
|
|
226
|
+
for (const opt of serverOptions) {
|
|
227
|
+
if (opt.length === 3) {
|
|
228
|
+
startCmd.option(opt[0], opt[1], opt[2]);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
startCmd.option(opt[0], opt[1]);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
startCmd.option('--no-boot', '不注册开机自启动');
|
|
235
|
+
startCmd.option('-o, --open', '启动后在浏览器中打开状态页面');
|
|
236
|
+
startCmd.action(async (options) => {
|
|
237
|
+
// 1. 检测是否已在运行
|
|
238
|
+
const existing = readPidFile();
|
|
239
|
+
if (existing) {
|
|
240
|
+
try {
|
|
241
|
+
await httpGet(existing.host, existing.controlPort, '/_chuantou/status', existing.tls);
|
|
242
|
+
console.log(chalk.yellow('服务器已在运行中'));
|
|
243
|
+
console.log(chalk.gray(` PID: ${existing.pid}`));
|
|
244
|
+
console.log(chalk.gray(` 端口: ${existing.controlPort}`));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// PID 文件残留,清理后继续
|
|
249
|
+
removePidFile();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// 2. 确保数据目录存在
|
|
253
|
+
mkdirSync(PID_DIR, { recursive: true });
|
|
254
|
+
// 3. 解析路径
|
|
255
|
+
const scriptPath = fileURLToPath(import.meta.url);
|
|
256
|
+
const nodePath = process.execPath;
|
|
257
|
+
// 4. 构建 _serve 参数
|
|
258
|
+
const serveArgs = [];
|
|
259
|
+
serveArgs.push('--port', options.port);
|
|
260
|
+
serveArgs.push('--host', options.host);
|
|
261
|
+
if (options.tokens)
|
|
262
|
+
serveArgs.push('--tokens', options.tokens);
|
|
263
|
+
if (options.tlsKey)
|
|
264
|
+
serveArgs.push('--tls-key', options.tlsKey);
|
|
265
|
+
if (options.tlsCert)
|
|
266
|
+
serveArgs.push('--tls-cert', options.tlsCert);
|
|
267
|
+
serveArgs.push('--heartbeat-interval', options.heartbeatInterval);
|
|
268
|
+
serveArgs.push('--session-timeout', options.sessionTimeout);
|
|
269
|
+
// 5. 打开日志文件
|
|
270
|
+
const logFd = openSync(LOG_FILE, 'a');
|
|
271
|
+
// 6. 启动后台守护进程
|
|
272
|
+
const child = spawn(nodePath, [scriptPath, '_serve', ...serveArgs], {
|
|
273
|
+
detached: true,
|
|
274
|
+
stdio: ['ignore', logFd, logFd],
|
|
275
|
+
});
|
|
276
|
+
child.unref();
|
|
277
|
+
closeSync(logFd);
|
|
278
|
+
// 7. 等待服务器启动
|
|
279
|
+
const controlPort = parseInt(options.port, 10);
|
|
280
|
+
const host = options.host;
|
|
281
|
+
const tls = !!(options.tlsKey && options.tlsCert);
|
|
282
|
+
const started = await waitForStartup(host, controlPort, tls, 10000);
|
|
283
|
+
if (!started) {
|
|
284
|
+
console.log(chalk.red('服务器启动失败,请查看日志文件:'));
|
|
285
|
+
console.log(chalk.gray(` ${LOG_FILE}`));
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
console.log(chalk.green('服务器已在后台启动'));
|
|
289
|
+
console.log(chalk.gray(` PID: ${child.pid}`));
|
|
290
|
+
console.log(chalk.gray(` 主机: ${host}`));
|
|
291
|
+
console.log(chalk.gray(` 端口: ${controlPort}`));
|
|
292
|
+
console.log(chalk.gray(` TLS: ${tls ? '已启用' : '已禁用'}`));
|
|
293
|
+
console.log(chalk.gray(` 日志: ${LOG_FILE}`));
|
|
294
|
+
// 8. 打开浏览器
|
|
295
|
+
if (options.open) {
|
|
296
|
+
const protocol = tls ? 'https' : 'http';
|
|
297
|
+
const url = host === '0.0.0.0'
|
|
298
|
+
? `${protocol}://127.0.0.1:${controlPort}/`
|
|
299
|
+
: `${protocol}://${host}:${controlPort}/`;
|
|
300
|
+
openBrowser(url);
|
|
301
|
+
}
|
|
302
|
+
// 9. 注册开机启动
|
|
303
|
+
if (options.boot !== false) {
|
|
304
|
+
try {
|
|
305
|
+
registerBoot({
|
|
306
|
+
nodePath,
|
|
307
|
+
scriptPath,
|
|
308
|
+
args: serveArgs,
|
|
309
|
+
});
|
|
310
|
+
console.log(chalk.green('已注册开机自启动'));
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
console.log(chalk.yellow(`注册开机自启动失败: ${err instanceof Error ? err.message : err}`));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
// ====== status 命令 ======
|
|
318
|
+
program
|
|
319
|
+
.command('status')
|
|
320
|
+
.description('查询服务器状态')
|
|
321
|
+
.action(async () => {
|
|
322
|
+
const pidInfo = readPidFile();
|
|
323
|
+
if (!pidInfo) {
|
|
324
|
+
console.log(chalk.red('未找到正在运行的服务器(PID 文件不存在)'));
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
const data = await httpGet(pidInfo.host, pidInfo.controlPort, '/_chuantou/status', pidInfo.tls);
|
|
329
|
+
const status = JSON.parse(data);
|
|
330
|
+
console.log(chalk.blue.bold('穿透服务器状态'));
|
|
331
|
+
console.log(chalk.gray(` 运行中: ${status.running ? chalk.green('是') : chalk.red('否')}`));
|
|
332
|
+
console.log(chalk.gray(` 主机: ${status.host}:${status.controlPort}`));
|
|
333
|
+
console.log(chalk.gray(` TLS: ${status.tls ? '已启用' : '已禁用'}`));
|
|
334
|
+
console.log(chalk.gray(` 运行时长: ${Math.floor(status.uptime / 1000)}秒`));
|
|
335
|
+
console.log(chalk.gray(` 客户端: ${status.authenticatedClients}`));
|
|
336
|
+
console.log(chalk.gray(` 端口: ${status.totalPorts}`));
|
|
337
|
+
console.log(chalk.gray(` 连接数: ${status.activeConnections}`));
|
|
338
|
+
console.log(chalk.gray(` 开机自启: ${isBootRegistered() ? chalk.green('已注册') : '未注册'}`));
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
console.log(chalk.red('无法连接到服务器,服务器可能未在运行。'));
|
|
342
|
+
removePidFile();
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
// ====== stop 命令 ======
|
|
347
|
+
program
|
|
348
|
+
.command('stop')
|
|
349
|
+
.description('停止服务器并取消开机自启动')
|
|
350
|
+
.action(async () => {
|
|
351
|
+
const pidInfo = readPidFile();
|
|
352
|
+
if (!pidInfo) {
|
|
353
|
+
console.log(chalk.red('未找到正在运行的服务器(PID 文件不存在)'));
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
await httpPost(pidInfo.host, pidInfo.controlPort, '/_chuantou/stop', pidInfo.tls);
|
|
358
|
+
removePidFile();
|
|
359
|
+
console.log(chalk.green('服务器已停止'));
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
console.log(chalk.red('无法连接到服务器,服务器可能未在运行。'));
|
|
363
|
+
removePidFile();
|
|
364
|
+
}
|
|
365
|
+
// 取消开机启动
|
|
366
|
+
try {
|
|
367
|
+
if (isBootRegistered()) {
|
|
368
|
+
unregisterBoot();
|
|
369
|
+
console.log(chalk.green('已取消开机自启动'));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
console.log(chalk.yellow(`取消开机自启动失败: ${err instanceof Error ? err.message : err}`));
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
program.parse();
|
|
377
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module control-handler
|
|
3
|
+
* @description 控制通道处理器模块,负责处理客户端通过 WebSocket 控制通道发送的各类控制消息。
|
|
4
|
+
* 包括认证、端口注册/注销、心跳以及断开连接等消息的处理逻辑。
|
|
5
|
+
*/
|
|
6
|
+
import { WebSocket } from 'ws';
|
|
7
|
+
import { ServerConfig } from '@feng3d/chuantou-shared';
|
|
8
|
+
import { SessionManager } from '../session-manager.js';
|
|
9
|
+
import { UnifiedProxyHandler } from './unified-proxy.js';
|
|
10
|
+
/**
|
|
11
|
+
* 控制通道处理器
|
|
12
|
+
*
|
|
13
|
+
* 处理客户端通过 WebSocket 控制通道发送的各类控制消息,包括:
|
|
14
|
+
* - 客户端认证(AUTH)
|
|
15
|
+
* - 端口注册(REGISTER)与注销(UNREGISTER)
|
|
16
|
+
* - 心跳保活(HEARTBEAT)
|
|
17
|
+
* - 连接断开的清理工作
|
|
18
|
+
*/
|
|
19
|
+
export declare class ControlHandler {
|
|
20
|
+
/** 会话管理器实例 */
|
|
21
|
+
private sessionManager;
|
|
22
|
+
/** 服务器配置 */
|
|
23
|
+
private config;
|
|
24
|
+
/** 统一代理处理器(同时支持 HTTP 和 WebSocket) */
|
|
25
|
+
private proxyHandler;
|
|
26
|
+
/**
|
|
27
|
+
* 创建控制通道处理器实例
|
|
28
|
+
*
|
|
29
|
+
* @param sessionManager - 会话管理器,用于管理客户端会话
|
|
30
|
+
* @param config - 服务器配置,包含认证令牌等信息
|
|
31
|
+
* @param proxyHandler - 统一代理处理器,用于启停代理服务器
|
|
32
|
+
*/
|
|
33
|
+
constructor(sessionManager: SessionManager, config: ServerConfig, proxyHandler: UnifiedProxyHandler);
|
|
34
|
+
/**
|
|
35
|
+
* 处理新的 WebSocket 控制通道连接
|
|
36
|
+
*
|
|
37
|
+
* 为新连接创建会话,设置消息处理、关闭处理和错误处理回调,
|
|
38
|
+
* 并启动 30 秒认证超时计时器。
|
|
39
|
+
*
|
|
40
|
+
* @param socket - 新建立的 WebSocket 连接
|
|
41
|
+
*/
|
|
42
|
+
handleConnection(socket: WebSocket): void;
|
|
43
|
+
/**
|
|
44
|
+
* 处理收到的控制消息
|
|
45
|
+
*
|
|
46
|
+
* 解析 JSON 消息并根据消息类型分发到对应的处理方法。
|
|
47
|
+
* 支持的消息类型包括:AUTH、REGISTER、UNREGISTER、HEARTBEAT。
|
|
48
|
+
*
|
|
49
|
+
* @param clientId - 发送消息的客户端 ID
|
|
50
|
+
* @param socket - 客户端的 WebSocket 连接
|
|
51
|
+
* @param data - 收到的原始消息数据
|
|
52
|
+
*/
|
|
53
|
+
private handleMessage;
|
|
54
|
+
/**
|
|
55
|
+
* 处理认证消息
|
|
56
|
+
*
|
|
57
|
+
* 验证客户端提供的令牌是否在配置的有效令牌列表中。
|
|
58
|
+
* 认证成功后清除认证超时计时器;认证失败则关闭连接。
|
|
59
|
+
*
|
|
60
|
+
* @param clientId - 客户端唯一标识 ID
|
|
61
|
+
* @param socket - 客户端的 WebSocket 连接
|
|
62
|
+
* @param message - 收到的认证消息
|
|
63
|
+
*/
|
|
64
|
+
private handleAuth;
|
|
65
|
+
/**
|
|
66
|
+
* 处理端口注册消息
|
|
67
|
+
*
|
|
68
|
+
* 验证客户端认证状态和端口范围(1024-65535),检查端口是否已被占用,
|
|
69
|
+
* 然后注册端口并启动代理服务器(同时支持 HTTP 和 WebSocket)。
|
|
70
|
+
* 若启动失败则自动回滚端口注册。
|
|
71
|
+
*
|
|
72
|
+
* @param clientId - 客户端唯一标识 ID
|
|
73
|
+
* @param socket - 客户端的 WebSocket 连接
|
|
74
|
+
* @param message - 收到的端口注册消息
|
|
75
|
+
*/
|
|
76
|
+
private handleRegister;
|
|
77
|
+
/**
|
|
78
|
+
* 处理端口注销消息
|
|
79
|
+
*
|
|
80
|
+
* 验证客户端认证状态和端口归属,停止代理服务器并注销端口。
|
|
81
|
+
*
|
|
82
|
+
* @param clientId - 客户端唯一标识 ID
|
|
83
|
+
* @param socket - 客户端的 WebSocket 连接
|
|
84
|
+
* @param message - 收到的端口注销消息
|
|
85
|
+
*/
|
|
86
|
+
private handleUnregister;
|
|
87
|
+
/**
|
|
88
|
+
* 处理心跳消息
|
|
89
|
+
*
|
|
90
|
+
* 更新客户端的最后心跳时间并回复心跳响应。
|
|
91
|
+
*
|
|
92
|
+
* @param clientId - 客户端唯一标识 ID
|
|
93
|
+
* @param socket - 客户端的 WebSocket 连接
|
|
94
|
+
* @param message - 收到的心跳消息
|
|
95
|
+
*/
|
|
96
|
+
private handleHeartbeat;
|
|
97
|
+
/**
|
|
98
|
+
* 处理客户端断开连接
|
|
99
|
+
*
|
|
100
|
+
* 停止该客户端注册的所有代理服务器,并移除其会话。
|
|
101
|
+
*
|
|
102
|
+
* @param clientId - 断开连接的客户端唯一标识 ID
|
|
103
|
+
*/
|
|
104
|
+
private handleDisconnect;
|
|
105
|
+
/**
|
|
106
|
+
* 通过 WebSocket 发送消息
|
|
107
|
+
*
|
|
108
|
+
* 将消息对象序列化为 JSON 字符串后发送,仅在连接处于 OPEN 状态时发送。
|
|
109
|
+
*
|
|
110
|
+
* @param socket - 目标 WebSocket 连接
|
|
111
|
+
* @param message - 需要发送的消息对象
|
|
112
|
+
*/
|
|
113
|
+
private sendMessage;
|
|
114
|
+
/**
|
|
115
|
+
* 发送错误消息
|
|
116
|
+
*
|
|
117
|
+
* 构造并发送一条 CONNECTION_ERROR 类型的错误消息给客户端。
|
|
118
|
+
*
|
|
119
|
+
* @param socket - 目标 WebSocket 连接
|
|
120
|
+
* @param error - 错误描述信息
|
|
121
|
+
*/
|
|
122
|
+
private sendError;
|
|
123
|
+
/**
|
|
124
|
+
* 处理客户端返回的 HTTP 响应数据
|
|
125
|
+
*
|
|
126
|
+
* @param connectionId - 连接唯一标识 ID
|
|
127
|
+
* @param data - 客户端返回的 HTTP 响应数据
|
|
128
|
+
*/
|
|
129
|
+
handleClientResponse(connectionId: string, data: any): void;
|
|
130
|
+
/**
|
|
131
|
+
* 处理来自客户端的 WebSocket 数据
|
|
132
|
+
*
|
|
133
|
+
* @param connectionId - 连接唯一标识 ID
|
|
134
|
+
* @param data - 客户端发送的数据
|
|
135
|
+
*/
|
|
136
|
+
handleClientData(connectionId: string, data: Buffer): void;
|
|
137
|
+
/**
|
|
138
|
+
* 处理来自客户端的连接关闭请求
|
|
139
|
+
*
|
|
140
|
+
* @param connectionId - 需要关闭的连接唯一标识 ID
|
|
141
|
+
* @param code - 可选的关闭状态码
|
|
142
|
+
*/
|
|
143
|
+
handleClientClose(connectionId: string, code?: number): void;
|
|
144
|
+
/**
|
|
145
|
+
* 处理来自客户端的流式响应数据
|
|
146
|
+
*
|
|
147
|
+
* @param connectionId - 连接唯一标识 ID
|
|
148
|
+
* @param data - 客户端发送的流式数据
|
|
149
|
+
*/
|
|
150
|
+
handleClientStreamData(connectionId: string, data: Buffer): void;
|
|
151
|
+
/**
|
|
152
|
+
* 处理来自客户端的流式响应结束通知
|
|
153
|
+
*
|
|
154
|
+
* @param connectionId - 连接唯一标识 ID
|
|
155
|
+
*/
|
|
156
|
+
handleClientStreamEnd(connectionId: string): void;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=control-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/control-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAOL,YAAY,EAEb,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;;;GAQG;AACH,qBAAa,cAAc;IACzB,cAAc;IACd,OAAO,CAAC,cAAc,CAAiB;IACvC,YAAY;IACZ,OAAO,CAAC,MAAM,CAAe;IAC7B,qCAAqC;IACrC,OAAO,CAAC,YAAY,CAAsB;IAE1C;;;;;;OAMG;gBAED,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,mBAAmB;IAOnC;;;;;;;OAOG;IACH,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAqCzC;;;;;;;;;OASG;YACW,aAAa;IA4D3B;;;;;;;;;OASG;YACW,UAAU;IA2CxB;;;;;;;;;;OAUG;YACW,cAAc;IA+D5B;;;;;;;;OAQG;YACW,gBAAgB;IA2B9B;;;;;;;;OAQG;YACW,eAAe;IAO7B;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAMnB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAOjB;;;;;OAKG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAI3D;;;;;OAKG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAI1D;;;;;OAKG;IACH,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAI5D;;;;;OAKG;IACH,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhE;;;;OAIG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;CAGlD"}
|