@feng3d/ctc 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/dist/cli.js ADDED
@@ -0,0 +1,433 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @module cli
4
+ * @description 穿透客户端命令行工具模块。
5
+ * 提供 `feng3d-ctc` CLI 命令,支持启动、停止和查询客户端状态。
6
+ * 单实例模式:只允许一个客户端实例运行,多次 start 会向已运行进程添加端口映射。
7
+ */
8
+ import { Command } from 'commander';
9
+ import chalk from 'chalk';
10
+ import { readFileSync, writeFileSync, mkdirSync, unlinkSync, openSync, closeSync } from 'fs';
11
+ import { join } from 'path';
12
+ import { homedir, platform } from 'os';
13
+ import { spawn, execSync } from 'child_process';
14
+ import { fileURLToPath } from 'url';
15
+ import { WebSocket } from 'ws';
16
+ import { MessageType, createMessage } from '@feng3d/chuantou-shared';
17
+ /** 客户端实例数据目录 */
18
+ const DATA_DIR = join(homedir(), '.chuantou');
19
+ /** PID 文件路径 */
20
+ const PID_FILE = join(DATA_DIR, 'client.pid');
21
+ /** 添加代理请求目录 */
22
+ const REQUEST_DIR = join(DATA_DIR, 'proxy-requests');
23
+ /**
24
+ * 写入 PID 文件
25
+ */
26
+ function writePidFile(info) {
27
+ mkdirSync(DATA_DIR, { recursive: true });
28
+ writeFileSync(PID_FILE, JSON.stringify(info, null, 2));
29
+ }
30
+ /**
31
+ * 读取 PID 文件
32
+ */
33
+ function readPidFile() {
34
+ try {
35
+ const content = readFileSync(PID_FILE, 'utf-8');
36
+ return JSON.parse(content);
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ /**
43
+ * 删除 PID 文件
44
+ */
45
+ function removePidFile() {
46
+ try {
47
+ unlinkSync(PID_FILE);
48
+ }
49
+ catch {
50
+ // ignore
51
+ }
52
+ }
53
+ /**
54
+ * 检查客户端是否正在运行
55
+ */
56
+ function isClientRunning() {
57
+ const info = readPidFile();
58
+ if (!info)
59
+ return false;
60
+ try {
61
+ process.kill(info.pid, 0);
62
+ return true;
63
+ }
64
+ catch {
65
+ // 进程不存在,清理 PID 文件
66
+ removePidFile();
67
+ return false;
68
+ }
69
+ }
70
+ /**
71
+ * 在浏览器中打开 URL
72
+ */
73
+ function openBrowser(url) {
74
+ const os = platform();
75
+ try {
76
+ if (os === 'win32') {
77
+ execSync(`cmd.exe /c start "" "${url}"`, { stdio: 'ignore' });
78
+ }
79
+ else if (os === 'darwin') {
80
+ execSync(`open "${url}"`, { stdio: 'ignore' });
81
+ }
82
+ else {
83
+ // Linux
84
+ execSync(`xdg-open "${url}"`, { stdio: 'ignore' });
85
+ }
86
+ }
87
+ catch {
88
+ // 忽略错误,浏览器打开失败不影响服务
89
+ }
90
+ }
91
+ /** 通用服务器选项 */
92
+ const serverOptions = [
93
+ ['-s, --server <url>', '服务器地址 (如 ws://localhost:9000)', 'ws://localhost:9000'],
94
+ ['-t, --token <token>', '认证令牌'],
95
+ ['-p, --proxies <proxies>', '代理配置 (格式: remotePort:localPort:localHost,...)'],
96
+ ['--reconnect-interval <ms>', '重连间隔(毫秒)', '5000'],
97
+ ['--max-reconnect <number>', '最大重连次数', '10'],
98
+ ];
99
+ const program = new Command();
100
+ program
101
+ .name('feng3d-ctc')
102
+ .description(chalk.blue('穿透 - 内网穿透客户端'))
103
+ .version('0.0.5');
104
+ // ====== start 命令 ======
105
+ const startCmd = program.command('start').description('启动客户端(后台运行)');
106
+ for (const opt of serverOptions) {
107
+ if (opt.length === 3) {
108
+ startCmd.option(opt[0], opt[1], opt[2]);
109
+ }
110
+ else {
111
+ startCmd.option(opt[0], opt[1]);
112
+ }
113
+ }
114
+ startCmd.option('--no-daemon', '前台运行(不作为后台守护进程)');
115
+ startCmd.option('-o, --open', '启动后在浏览器中打开管理页面');
116
+ startCmd.action(async (options) => {
117
+ const serverUrl = options.server;
118
+ const token = options.token;
119
+ const proxiesStr = options.proxies;
120
+ const shouldOpenBrowser = options.open;
121
+ // 解析代理配置
122
+ const proxies = [];
123
+ if (proxiesStr) {
124
+ for (const p of proxiesStr.split(',')) {
125
+ const parts = p.trim().split(':');
126
+ proxies.push({
127
+ remotePort: parseInt(parts[0], 10),
128
+ localPort: parseInt(parts[1], 10),
129
+ localHost: parts[2] || 'localhost',
130
+ });
131
+ }
132
+ }
133
+ // 检查客户端是否已运行
134
+ if (isClientRunning()) {
135
+ const info = readPidFile();
136
+ // 检查服务器地址是否一致
137
+ if (info.serverUrl !== serverUrl) {
138
+ console.log(chalk.yellow('客户端正在运行,但连接到不同的服务器'));
139
+ console.log(chalk.gray(` 当前: ${info.serverUrl}`));
140
+ console.log(chalk.gray(` 新请求: ${serverUrl}`));
141
+ console.log(chalk.yellow('请先停止当前客户端,或使用相同的服务器地址'));
142
+ process.exit(1);
143
+ }
144
+ // 客户端已运行,添加代理映射
145
+ console.log(chalk.green('客户端正在运行,添加新的代理映射...'));
146
+ for (const proxy of proxies) {
147
+ await addProxyToRunningClient(info.serverUrl, token, proxy);
148
+ }
149
+ return;
150
+ }
151
+ // 构建 _serve 参数
152
+ const serveArgs = [];
153
+ serveArgs.push('--server', serverUrl);
154
+ if (token)
155
+ serveArgs.push('--token', token);
156
+ if (proxiesStr)
157
+ serveArgs.push('--proxies', proxiesStr);
158
+ serveArgs.push('--reconnect-interval', options.reconnectInterval);
159
+ serveArgs.push('--max-reconnect', options.maxReconnect);
160
+ // 是否后台运行
161
+ const daemon = options.daemon !== false;
162
+ if (daemon) {
163
+ // 后台守护进程模式
164
+ const scriptPath = fileURLToPath(import.meta.url);
165
+ const nodePath = process.execPath;
166
+ const logPath = join(DATA_DIR, 'client.log');
167
+ // 打开日志文件
168
+ const logFd = openSync(logPath, 'a');
169
+ // 启动后台守护进程
170
+ const child = spawn(nodePath, [scriptPath, '_serve', ...serveArgs], {
171
+ detached: true,
172
+ stdio: ['ignore', logFd, logFd],
173
+ });
174
+ child.unref();
175
+ closeSync(logFd);
176
+ // 等待一小段时间让进程启动
177
+ await new Promise((r) => setTimeout(r, 500));
178
+ // 验证进程是否启动成功
179
+ const pid = child.pid;
180
+ if (pid === undefined) {
181
+ console.log(chalk.red('客户端启动失败,请查看日志文件:'));
182
+ console.log(chalk.gray(` ${logPath}`));
183
+ process.exit(1);
184
+ }
185
+ try {
186
+ process.kill(pid, 0);
187
+ }
188
+ catch {
189
+ console.log(chalk.red('客户端启动失败,请查看日志文件:'));
190
+ console.log(chalk.gray(` ${logPath}`));
191
+ process.exit(1);
192
+ }
193
+ // 写入 PID 文件
194
+ writePidFile({
195
+ serverUrl,
196
+ pid,
197
+ startedAt: Date.now(),
198
+ });
199
+ console.log(chalk.green('客户端已在后台启动'));
200
+ console.log(chalk.gray(` PID: ${pid}`));
201
+ console.log(chalk.gray(` 服务器: ${serverUrl}`));
202
+ console.log(chalk.gray(` 日志: ${logPath}`));
203
+ if (proxies.length > 0) {
204
+ console.log(chalk.gray(` 代理映射:`));
205
+ for (const proxy of proxies) {
206
+ console.log(chalk.gray(` :${proxy.remotePort} -> ${proxy.localHost || 'localhost'}:${proxy.localPort}`));
207
+ }
208
+ }
209
+ // 打开浏览器
210
+ if (shouldOpenBrowser) {
211
+ setTimeout(() => {
212
+ openBrowser('http://127.0.0.1:9001/');
213
+ }, 2000);
214
+ }
215
+ }
216
+ else {
217
+ // 前台运行模式
218
+ await runServe(serverUrl, token, proxiesStr, options.reconnectInterval, options.maxReconnect, shouldOpenBrowser);
219
+ }
220
+ });
221
+ // ====== _serve 命令(隐藏,前台运行)======
222
+ const serveCmd = program.command('_serve', { hidden: true }).description('前台运行客户端(内部命令)');
223
+ for (const opt of serverOptions) {
224
+ if (opt.length === 3) {
225
+ serveCmd.option(opt[0], opt[1], opt[2]);
226
+ }
227
+ else {
228
+ serveCmd.option(opt[0], opt[1]);
229
+ }
230
+ }
231
+ serveCmd.action(async (options) => {
232
+ await runServe(options.server, options.token, options.proxies, options.reconnectInterval, options.maxReconnect);
233
+ });
234
+ // ====== stop 命令 ======
235
+ program
236
+ .command('stop')
237
+ .description('停止客户端')
238
+ .action(async () => {
239
+ const info = readPidFile();
240
+ if (!info) {
241
+ console.log(chalk.yellow('客户端未在运行'));
242
+ return;
243
+ }
244
+ try {
245
+ process.kill(info.pid, 'SIGTERM');
246
+ }
247
+ catch (err) {
248
+ console.log(chalk.yellow(`停止客户端失败: ${err instanceof Error ? err.message : err}`));
249
+ }
250
+ removePidFile();
251
+ console.log(chalk.green('客户端已停止'));
252
+ });
253
+ // ====== status 命令 ======
254
+ program
255
+ .command('status')
256
+ .description('查询客户端状态')
257
+ .action(async () => {
258
+ const info = readPidFile();
259
+ if (!info) {
260
+ console.log(chalk.yellow('客户端未在运行'));
261
+ return;
262
+ }
263
+ const uptime = Math.floor((Date.now() - info.startedAt) / 1000);
264
+ const minutes = Math.floor(uptime / 60);
265
+ const seconds = uptime % 60;
266
+ console.log(chalk.blue.bold('穿透客户端状态'));
267
+ console.log(chalk.gray(` 运行中: 是`));
268
+ console.log(chalk.gray(` 服务器: ${info.serverUrl}`));
269
+ console.log(chalk.gray(` PID: ${info.pid}`));
270
+ console.log(chalk.gray(` 运行时长: ${minutes}分${seconds}秒`));
271
+ // 尝试获取代理列表状态
272
+ try {
273
+ const proxies = await getProxiesFromRunningClient(info.serverUrl);
274
+ if (proxies.length > 0) {
275
+ console.log(chalk.gray(` 代理数量: ${proxies.length}`));
276
+ }
277
+ }
278
+ catch {
279
+ // 无法获取代理列表,可能客户端还未完全启动
280
+ }
281
+ });
282
+ // ====== list 命令(列出代理)======
283
+ program
284
+ .command('list')
285
+ .description('列出当前代理映射')
286
+ .action(async () => {
287
+ const info = readPidFile();
288
+ if (!info) {
289
+ console.log(chalk.yellow('客户端未在运行'));
290
+ return;
291
+ }
292
+ try {
293
+ const proxies = await getProxiesFromRunningClient(info.serverUrl);
294
+ if (proxies.length === 0) {
295
+ console.log(chalk.yellow('没有代理映射'));
296
+ return;
297
+ }
298
+ console.log(chalk.blue.bold('当前代理映射:'));
299
+ console.log();
300
+ for (const proxy of proxies) {
301
+ console.log(chalk.gray(` :${proxy.remotePort} -> ${proxy.localHost || 'localhost'}:${proxy.localPort}`));
302
+ }
303
+ }
304
+ catch (err) {
305
+ console.log(chalk.yellow(`获取代理列表失败: ${err instanceof Error ? err.message : err}`));
306
+ }
307
+ });
308
+ /**
309
+ * 向正在运行的客户端添加代理映射
310
+ */
311
+ async function addProxyToRunningClient(serverUrl, token, proxy) {
312
+ return new Promise((resolve, reject) => {
313
+ const ws = new WebSocket(serverUrl);
314
+ const timeout = setTimeout(() => {
315
+ ws.close();
316
+ reject(new Error('连接超时'));
317
+ }, 5000);
318
+ ws.on('open', async () => {
319
+ clearTimeout(timeout);
320
+ // 发送认证
321
+ const authMsg = createMessage(MessageType.AUTH, {
322
+ token: token || '',
323
+ });
324
+ ws.send(JSON.stringify(authMsg));
325
+ // 等待认证响应
326
+ ws.once('message', (data) => {
327
+ try {
328
+ const response = JSON.parse(data.toString());
329
+ if (response.type !== MessageType.AUTH_RESP || !response.payload.success) {
330
+ ws.close();
331
+ reject(new Error(`认证失败: ${response.payload.error || '未知错误'}`));
332
+ return;
333
+ }
334
+ // 认证成功,发送注册代理请求
335
+ const registerMsg = createMessage(MessageType.REGISTER, {
336
+ remotePort: proxy.remotePort,
337
+ localPort: proxy.localPort,
338
+ localHost: proxy.localHost,
339
+ });
340
+ ws.send(JSON.stringify(registerMsg));
341
+ // 等待注册响应
342
+ ws.once('message', (data) => {
343
+ try {
344
+ const response = JSON.parse(data.toString());
345
+ if (response.type !== MessageType.REGISTER_RESP) {
346
+ ws.close();
347
+ reject(new Error('意外的响应类型'));
348
+ return;
349
+ }
350
+ if (response.payload.success) {
351
+ console.log(chalk.green(`代理已添加: :${proxy.remotePort} -> ${proxy.localHost || 'localhost'}:${proxy.localPort}`));
352
+ ws.close();
353
+ resolve();
354
+ }
355
+ else {
356
+ ws.close();
357
+ reject(new Error(`注册代理失败: ${response.payload.error || '未知错误'}`));
358
+ }
359
+ }
360
+ catch (err) {
361
+ ws.close();
362
+ reject(err);
363
+ }
364
+ });
365
+ }
366
+ catch (err) {
367
+ ws.close();
368
+ reject(err);
369
+ }
370
+ });
371
+ });
372
+ ws.on('error', (err) => {
373
+ clearTimeout(timeout);
374
+ reject(new Error(`连接失败: ${err.message}`));
375
+ });
376
+ });
377
+ }
378
+ /**
379
+ * 从正在运行的客户端获取代理列表
380
+ */
381
+ async function getProxiesFromRunningClient(serverUrl) {
382
+ return new Promise((resolve, reject) => {
383
+ const ws = new WebSocket(serverUrl);
384
+ const timeout = setTimeout(() => {
385
+ ws.close();
386
+ resolve([]);
387
+ }, 3000);
388
+ ws.on('open', async () => {
389
+ // 发送获取代理列表请求(使用心跳消息保持连接)
390
+ const heartbeatMsg = createMessage(MessageType.HEARTBEAT, {
391
+ timestamp: Date.now(),
392
+ });
393
+ ws.send(JSON.stringify(heartbeatMsg));
394
+ // 这里简化处理,实际上应该有一个专门的 GET_PROXIES 消息类型
395
+ // 目前返回空数组
396
+ clearTimeout(timeout);
397
+ ws.close();
398
+ resolve([]);
399
+ });
400
+ ws.on('error', () => {
401
+ clearTimeout(timeout);
402
+ resolve([]);
403
+ });
404
+ });
405
+ }
406
+ /**
407
+ * 运行客户端(前台模式)
408
+ */
409
+ async function runServe(serverUrl, token, proxies, reconnectInterval, maxReconnect, shouldOpenBrowser) {
410
+ // 设置 process.argv 供 Config.load 读取
411
+ process.argv = [
412
+ process.argv[0],
413
+ process.argv[1],
414
+ '--server', serverUrl,
415
+ '--reconnect-interval', reconnectInterval,
416
+ '--max-reconnect', maxReconnect,
417
+ ];
418
+ if (token)
419
+ process.argv.push('--token', token);
420
+ if (proxies)
421
+ process.argv.push('--proxies', proxies);
422
+ // 动态导入 index 模块运行
423
+ const { run } = await import('./index.js');
424
+ // 如果需要打开浏览器,延迟打开
425
+ if (shouldOpenBrowser) {
426
+ setTimeout(() => {
427
+ openBrowser('http://127.0.0.1:9001/');
428
+ }, 3000);
429
+ }
430
+ await run();
431
+ }
432
+ program.parse();
433
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @module config
3
+ *
4
+ * 客户端配置管理模块。
5
+ *
6
+ * 负责从配置文件、命令行参数和默认值中加载、合并和验证客户端配置。
7
+ * 配置优先级:命令行参数 > 配置文件 > 默认值。
8
+ * 默认配置文件路径为用户主目录下的 `.chuantou/client.json`。
9
+ */
10
+ import { ClientConfig, ProxyConfig } from '@feng3d/chuantou-shared';
11
+ /**
12
+ * 客户端配置类。
13
+ *
14
+ * 实现 {@link ClientConfig} 接口,封装了客户端运行所需的全部配置项,
15
+ * 提供配置加载和验证功能。
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const config = await Config.load();
20
+ * config.validate();
21
+ * console.log(config.serverUrl);
22
+ * ```
23
+ */
24
+ export declare class Config implements ClientConfig {
25
+ /** 服务器 WebSocket 连接地址,如 `ws://localhost:9000` */
26
+ serverUrl: string;
27
+ /** 客户端认证令牌,用于与服务器进行身份验证 */
28
+ token: string;
29
+ /** 断线重连间隔时间(毫秒) */
30
+ reconnectInterval: number;
31
+ /** 最大重连尝试次数,超过后停止重连 */
32
+ maxReconnectAttempts: number;
33
+ /** 代理隧道配置列表 */
34
+ proxies: ProxyConfig[];
35
+ /**
36
+ * 创建配置实例。
37
+ *
38
+ * @param data - 客户端配置数据对象
39
+ */
40
+ constructor(data: ClientConfig);
41
+ /**
42
+ * 从配置文件和命令行参数中加载配置并创建实例。
43
+ *
44
+ * 优先使用命令行参数中的值覆盖配置文件中的值。
45
+ *
46
+ * @returns 加载完成的 Config 实例
47
+ */
48
+ static load(): Promise<Config>;
49
+ /**
50
+ * 验证配置的合法性。
51
+ *
52
+ * 检查以下内容:
53
+ * - 服务器地址不为空且以 `ws://` 或 `wss://` 开头
54
+ * - 认证令牌不为空
55
+ * - 至少配置了一个代理
56
+ * - 每个代理的端口号合法
57
+ *
58
+ * @throws {Error} 当配置项不合法时抛出错误,包含具体的错误描述
59
+ */
60
+ validate(): void;
61
+ }
62
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAkB,MAAM,yBAAyB,CAAC;AAiIpF;;;;;;;;;;;;GAYG;AACH,qBAAa,MAAO,YAAW,YAAY;IACzC,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAElB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IAEd,mBAAmB;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAE1B,uBAAuB;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAE7B,eAAe;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;IAEvB;;;;OAIG;gBACS,IAAI,EAAE,YAAY;IAQ9B;;;;;;OAMG;WACU,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAKpC;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,IAAI;CAuBjB"}