@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/README.md +195 -0
- package/dist/admin-server.d.ts +90 -0
- package/dist/admin-server.d.ts.map +1 -0
- package/dist/admin-server.js +680 -0
- package/dist/admin-server.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +433 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +62 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +209 -0
- package/dist/config.js.map +1 -0
- package/dist/controller.d.ts +173 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +340 -0
- package/dist/controller.js.map +1 -0
- package/dist/handlers/unified-handler.d.ts +110 -0
- package/dist/handlers/unified-handler.d.ts.map +1 -0
- package/dist/handlers/unified-handler.js +373 -0
- package/dist/handlers/unified-handler.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy-manager.d.ts +75 -0
- package/dist/proxy-manager.d.ts.map +1 -0
- package/dist/proxy-manager.js +124 -0
- package/dist/proxy-manager.js.map +1 -0
- package/package.json +39 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module config
|
|
3
|
+
*
|
|
4
|
+
* 客户端配置管理模块。
|
|
5
|
+
*
|
|
6
|
+
* 负责从配置文件、命令行参数和默认值中加载、合并和验证客户端配置。
|
|
7
|
+
* 配置优先级:命令行参数 > 配置文件 > 默认值。
|
|
8
|
+
* 默认配置文件路径为用户主目录下的 `.chuantou/client.json`。
|
|
9
|
+
*/
|
|
10
|
+
import { promises as fs } from 'fs';
|
|
11
|
+
import * as os from 'os';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { DEFAULT_CONFIG } from '@feng3d/chuantou-shared';
|
|
14
|
+
/**
|
|
15
|
+
* 获取配置目录路径。
|
|
16
|
+
*
|
|
17
|
+
* @returns 用户主目录下的 `.chuantou` 目录绝对路径
|
|
18
|
+
*/
|
|
19
|
+
function getConfigDir() {
|
|
20
|
+
const homeDir = os.homedir();
|
|
21
|
+
return path.join(homeDir, '.chuantou');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 获取客户端配置文件的完整路径。
|
|
25
|
+
*
|
|
26
|
+
* @returns 配置文件 `client.json` 的绝对路径
|
|
27
|
+
*/
|
|
28
|
+
function getClientConfigPath() {
|
|
29
|
+
return path.join(getConfigDir(), 'client.json');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 解析代理配置字符串为代理配置数组。
|
|
33
|
+
*
|
|
34
|
+
* 字符串格式为逗号分隔的代理项,每项格式为 `remotePort:localPort[:localHost]`。
|
|
35
|
+
* 每个端口同时支持 HTTP 和 WebSocket 协议。
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```
|
|
39
|
+
* parseProxies('8080:3000:localhost,8081:3001')
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param proxiesStr - 代理配置字符串,如 `"8080:3000:localhost,8081:3001"`
|
|
43
|
+
* @returns 解析后的代理配置数组
|
|
44
|
+
*/
|
|
45
|
+
function parseProxies(proxiesStr) {
|
|
46
|
+
return proxiesStr.split(',').map((p) => {
|
|
47
|
+
const parts = p.trim().split(':');
|
|
48
|
+
return {
|
|
49
|
+
remotePort: parseInt(parts[0], 10),
|
|
50
|
+
localPort: parseInt(parts[1], 10),
|
|
51
|
+
localHost: parts[2] || 'localhost',
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 解析命令行参数。
|
|
57
|
+
*
|
|
58
|
+
* 支持以下命令行选项:
|
|
59
|
+
* - `--config <path>` - 配置文件路径
|
|
60
|
+
* - `--server <url>` - 服务器地址
|
|
61
|
+
* - `--token <token>` - 认证令牌
|
|
62
|
+
* - `--proxies <proxies>` - 代理配置字符串
|
|
63
|
+
*
|
|
64
|
+
* @returns 解析后的命令行参数对象,未指定的参数值为 `undefined`
|
|
65
|
+
*/
|
|
66
|
+
function parseArgs() {
|
|
67
|
+
const args = process.argv.slice(2);
|
|
68
|
+
const result = {};
|
|
69
|
+
for (let i = 0; i < args.length; i++) {
|
|
70
|
+
const arg = args[i];
|
|
71
|
+
if (arg === '--config' && i + 1 < args.length) {
|
|
72
|
+
result.config = args[++i];
|
|
73
|
+
}
|
|
74
|
+
else if (arg === '--server' && i + 1 < args.length) {
|
|
75
|
+
result.server = args[++i];
|
|
76
|
+
}
|
|
77
|
+
else if (arg === '--token' && i + 1 < args.length) {
|
|
78
|
+
result.token = args[++i];
|
|
79
|
+
}
|
|
80
|
+
else if (arg === '--proxies' && i + 1 < args.length) {
|
|
81
|
+
result.proxies = args[++i];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 从指定路径的 JSON 文件中加载配置。
|
|
88
|
+
*
|
|
89
|
+
* 如果文件不存在或解析失败,返回空对象。
|
|
90
|
+
*
|
|
91
|
+
* @param configPath - 配置文件的绝对路径
|
|
92
|
+
* @returns 部分客户端配置对象,加载失败时返回空对象
|
|
93
|
+
*/
|
|
94
|
+
async function loadFromFile(configPath) {
|
|
95
|
+
try {
|
|
96
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
97
|
+
return JSON.parse(content);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 加载并合并所有来源的配置。
|
|
105
|
+
*
|
|
106
|
+
* 配置合并优先级(从低到高):
|
|
107
|
+
* 1. 内置默认值
|
|
108
|
+
* 2. 配置文件中的值
|
|
109
|
+
* 3. 命令行参数
|
|
110
|
+
*
|
|
111
|
+
* @returns 合并后的完整客户端配置对象
|
|
112
|
+
*/
|
|
113
|
+
async function loadConfig() {
|
|
114
|
+
const args = parseArgs();
|
|
115
|
+
let config = {
|
|
116
|
+
serverUrl: 'ws://localhost:9000',
|
|
117
|
+
token: 'test-token',
|
|
118
|
+
reconnectInterval: DEFAULT_CONFIG.RECONNECT_INTERVAL,
|
|
119
|
+
maxReconnectAttempts: DEFAULT_CONFIG.MAX_RECONNECT_ATTEMPTS,
|
|
120
|
+
proxies: [
|
|
121
|
+
{ remotePort: 8080, localPort: 3000, localHost: 'localhost' },
|
|
122
|
+
],
|
|
123
|
+
};
|
|
124
|
+
// 1. 从配置文件加载
|
|
125
|
+
const configPath = args.config || getClientConfigPath();
|
|
126
|
+
const fileConfig = await loadFromFile(configPath);
|
|
127
|
+
Object.assign(config, fileConfig);
|
|
128
|
+
// 2. 命令行参数覆盖
|
|
129
|
+
if (args.server)
|
|
130
|
+
config.serverUrl = args.server;
|
|
131
|
+
if (args.token)
|
|
132
|
+
config.token = args.token;
|
|
133
|
+
if (args.proxies)
|
|
134
|
+
config.proxies = parseProxies(args.proxies);
|
|
135
|
+
return config;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 客户端配置类。
|
|
139
|
+
*
|
|
140
|
+
* 实现 {@link ClientConfig} 接口,封装了客户端运行所需的全部配置项,
|
|
141
|
+
* 提供配置加载和验证功能。
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* const config = await Config.load();
|
|
146
|
+
* config.validate();
|
|
147
|
+
* console.log(config.serverUrl);
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export class Config {
|
|
151
|
+
/**
|
|
152
|
+
* 创建配置实例。
|
|
153
|
+
*
|
|
154
|
+
* @param data - 客户端配置数据对象
|
|
155
|
+
*/
|
|
156
|
+
constructor(data) {
|
|
157
|
+
this.serverUrl = data.serverUrl;
|
|
158
|
+
this.token = data.token;
|
|
159
|
+
this.reconnectInterval = data.reconnectInterval;
|
|
160
|
+
this.maxReconnectAttempts = data.maxReconnectAttempts;
|
|
161
|
+
this.proxies = data.proxies;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 从配置文件和命令行参数中加载配置并创建实例。
|
|
165
|
+
*
|
|
166
|
+
* 优先使用命令行参数中的值覆盖配置文件中的值。
|
|
167
|
+
*
|
|
168
|
+
* @returns 加载完成的 Config 实例
|
|
169
|
+
*/
|
|
170
|
+
static async load() {
|
|
171
|
+
const config = await loadConfig();
|
|
172
|
+
return new Config(config);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 验证配置的合法性。
|
|
176
|
+
*
|
|
177
|
+
* 检查以下内容:
|
|
178
|
+
* - 服务器地址不为空且以 `ws://` 或 `wss://` 开头
|
|
179
|
+
* - 认证令牌不为空
|
|
180
|
+
* - 至少配置了一个代理
|
|
181
|
+
* - 每个代理的端口号合法
|
|
182
|
+
*
|
|
183
|
+
* @throws {Error} 当配置项不合法时抛出错误,包含具体的错误描述
|
|
184
|
+
*/
|
|
185
|
+
validate() {
|
|
186
|
+
if (!this.serverUrl) {
|
|
187
|
+
throw new Error('服务器地址是必需的 (--server ws://host:port 或 --config 配置文件)');
|
|
188
|
+
}
|
|
189
|
+
if (!this.token) {
|
|
190
|
+
throw new Error('认证令牌是必需的 (--token xxx 或 --config 配置文件)');
|
|
191
|
+
}
|
|
192
|
+
if (!this.serverUrl.startsWith('ws://') && !this.serverUrl.startsWith('wss://')) {
|
|
193
|
+
throw new Error('服务器地址必须以 ws:// 或 wss:// 开头');
|
|
194
|
+
}
|
|
195
|
+
if (this.proxies.length === 0) {
|
|
196
|
+
throw new Error('至少需要一个代理配置 (--proxies 或 --config 配置文件)');
|
|
197
|
+
}
|
|
198
|
+
for (let i = 0; i < this.proxies.length; i++) {
|
|
199
|
+
const proxy = this.proxies[i];
|
|
200
|
+
if (!proxy.remotePort || proxy.remotePort < 1024 || proxy.remotePort > 65535) {
|
|
201
|
+
throw new Error(`proxy[${i}] 的 remotePort 无效: ${proxy.remotePort}`);
|
|
202
|
+
}
|
|
203
|
+
if (!proxy.localPort || proxy.localPort < 1 || proxy.localPort > 65535) {
|
|
204
|
+
throw new Error(`proxy[${i}] 的 localPort 无效: ${proxy.localPort}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAA6B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEpF;;;;GAIG;AACH,SAAS,YAAY;IACnB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,YAAY,CAAC,UAAkB;IACtC,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE;QAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO;YACL,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAClC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACjC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW;SACnC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,MAAM,GAA2E,EAAE,CAAC;IAE1F,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9C,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACrD,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACpD,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,GAAG,KAAK,WAAW,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACtD,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,YAAY,CAAC,UAAkB;IAC5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,UAAU;IACvB,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;IACzB,IAAI,MAAM,GAAiB;QACzB,SAAS,EAAE,qBAAqB;QAChC,KAAK,EAAE,YAAY;QACnB,iBAAiB,EAAE,cAAc,CAAC,kBAAkB;QACpD,oBAAoB,EAAE,cAAc,CAAC,sBAAsB;QAC3D,OAAO,EAAE;YACP,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE;SAC9D;KACF,CAAC;IAEF,aAAa;IACb,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,mBAAmB,EAAE,CAAC;IACxD,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAElC,aAAa;IACb,IAAI,IAAI,CAAC,MAAM;QAAE,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;IAChD,IAAI,IAAI,CAAC,KAAK;QAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAC1C,IAAI,IAAI,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE9D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,MAAM;IAgBjB;;;;OAIG;IACH,YAAY,IAAkB;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAChD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,oBAAoB,CAAC;QACtD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI;QACf,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;OAUG;IACH,QAAQ;QACN,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChF,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,GAAG,IAAI,IAAI,KAAK,CAAC,UAAU,GAAG,KAAK,EAAE,CAAC;gBAC7E,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,sBAAsB,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;YACtE,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK,EAAE,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,qBAAqB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module controller
|
|
3
|
+
*
|
|
4
|
+
* 客户端控制器模块。
|
|
5
|
+
*
|
|
6
|
+
* 管理客户端与穿透服务器之间的 WebSocket 控制连接,
|
|
7
|
+
* 负责身份认证、心跳保活、消息收发、断线重连等核心通信逻辑。
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { Config } from './config.js';
|
|
11
|
+
/**
|
|
12
|
+
* 客户端控制器类,管理与穿透服务器的 WebSocket 控制连接。
|
|
13
|
+
*
|
|
14
|
+
* 继承自 {@link EventEmitter},提供以下事件:
|
|
15
|
+
* - `connected` - 成功连接到服务器时触发
|
|
16
|
+
* - `disconnected` - 与服务器断开连接时触发
|
|
17
|
+
* - `authenticated` - 身份认证成功时触发
|
|
18
|
+
* - `maxReconnectAttemptsReached` - 达到最大重连次数时触发
|
|
19
|
+
* - `newConnection` - 收到新的代理连接请求时触发
|
|
20
|
+
* - `connectionClose` - 收到连接关闭通知时触发
|
|
21
|
+
* - `connectionError` - 收到连接错误通知时触发
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const controller = new Controller(config);
|
|
26
|
+
* controller.on('authenticated', () => logger.log('已认证'));
|
|
27
|
+
* await controller.connect();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class Controller extends EventEmitter {
|
|
31
|
+
/** 客户端配置实例 */
|
|
32
|
+
private config;
|
|
33
|
+
/** 与服务器的 WebSocket 连接实例 */
|
|
34
|
+
private ws;
|
|
35
|
+
/** 是否已连接到服务器 */
|
|
36
|
+
private connected;
|
|
37
|
+
/** 是否已通过身份认证 */
|
|
38
|
+
private authenticated;
|
|
39
|
+
/** 重连定时器 */
|
|
40
|
+
private reconnectTimer;
|
|
41
|
+
/** 心跳定时器 */
|
|
42
|
+
private heartbeatTimer;
|
|
43
|
+
/** 当前重连尝试次数 */
|
|
44
|
+
private reconnectAttempts;
|
|
45
|
+
/** 待响应的请求映射表,键为消息 ID */
|
|
46
|
+
private pendingRequests;
|
|
47
|
+
/**
|
|
48
|
+
* 创建控制器实例。
|
|
49
|
+
*
|
|
50
|
+
* @param config - 客户端配置对象
|
|
51
|
+
*/
|
|
52
|
+
constructor(config: Config);
|
|
53
|
+
/**
|
|
54
|
+
* 连接到穿透服务器。
|
|
55
|
+
*
|
|
56
|
+
* 建立 WebSocket 连接后会自动进行身份认证和启动心跳。
|
|
57
|
+
* 连接断开时会自动安排重连。
|
|
58
|
+
*
|
|
59
|
+
* @returns 连接并认证成功后解析的 Promise
|
|
60
|
+
* @throws {Error} 连接失败或认证失败时抛出错误
|
|
61
|
+
*/
|
|
62
|
+
connect(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* 向服务器发送身份认证请求。
|
|
65
|
+
*
|
|
66
|
+
* 使用配置中的 token 进行认证,认证成功后触发 `authenticated` 事件。
|
|
67
|
+
*
|
|
68
|
+
* @throws {Error} 认证失败时抛出错误,包含服务器返回的错误信息
|
|
69
|
+
*/
|
|
70
|
+
private authenticate;
|
|
71
|
+
/**
|
|
72
|
+
* 启动心跳定时器。
|
|
73
|
+
*
|
|
74
|
+
* 每 30 秒向服务器发送一次心跳消息,仅在已连接且已认证状态下发送。
|
|
75
|
+
*/
|
|
76
|
+
private startHeartbeat;
|
|
77
|
+
/**
|
|
78
|
+
* 停止心跳定时器。
|
|
79
|
+
*
|
|
80
|
+
* 清除心跳定时器并将其设置为 null。
|
|
81
|
+
*/
|
|
82
|
+
private stopHeartbeat;
|
|
83
|
+
/**
|
|
84
|
+
* 安排断线重连。
|
|
85
|
+
*
|
|
86
|
+
* 使用指数退避策略计算重连延迟时间。如果已达到最大重连次数,
|
|
87
|
+
* 则触发 `maxReconnectAttemptsReached` 事件并停止重连。
|
|
88
|
+
*/
|
|
89
|
+
private scheduleReconnect;
|
|
90
|
+
/**
|
|
91
|
+
* 计算重连延迟时间(指数退避算法)。
|
|
92
|
+
*
|
|
93
|
+
* 基于重连间隔和当前重连次数计算延迟,最大不超过 60 秒,
|
|
94
|
+
* 并添加 0~1 秒的随机抖动以避免多客户端同时重连造成服务器压力。
|
|
95
|
+
*
|
|
96
|
+
* @returns 重连延迟时间(毫秒)
|
|
97
|
+
*/
|
|
98
|
+
private calculateReconnectDelay;
|
|
99
|
+
/**
|
|
100
|
+
* 处理从服务器接收到的消息。
|
|
101
|
+
*
|
|
102
|
+
* 根据消息类型进行分发:
|
|
103
|
+
* - 响应类消息(AUTH_RESP、REGISTER_RESP、HEARTBEAT_RESP)交由 {@link handleResponse} 处理
|
|
104
|
+
* - 新连接、连接关闭、连接错误等消息通过事件触发通知上层
|
|
105
|
+
*
|
|
106
|
+
* @param data - 接收到的原始消息数据
|
|
107
|
+
*/
|
|
108
|
+
private handleMessage;
|
|
109
|
+
/**
|
|
110
|
+
* 处理响应类消息。
|
|
111
|
+
*
|
|
112
|
+
* 根据消息 ID 查找对应的待处理请求,清除超时定时器并解析 Promise。
|
|
113
|
+
*
|
|
114
|
+
* @param message - 服务器返回的响应消息对象
|
|
115
|
+
*/
|
|
116
|
+
private handleResponse;
|
|
117
|
+
/**
|
|
118
|
+
* 发送请求消息并等待服务器响应。
|
|
119
|
+
*
|
|
120
|
+
* 将消息发送到服务器,并在指定超时时间内等待对应的响应消息。
|
|
121
|
+
* 如果超时未收到响应,Promise 将被拒绝。
|
|
122
|
+
*
|
|
123
|
+
* @typeParam T - 期望的响应消息类型
|
|
124
|
+
* @param message - 要发送的请求消息对象,必须包含 `id` 字段
|
|
125
|
+
* @param timeout - 请求超时时间(毫秒),默认为 30000
|
|
126
|
+
* @returns 服务器响应消息的 Promise
|
|
127
|
+
* @throws {Error} 请求超时时抛出 "Request timeout" 错误
|
|
128
|
+
*/
|
|
129
|
+
sendRequest<T>(message: any, timeout?: number): Promise<T>;
|
|
130
|
+
/**
|
|
131
|
+
* 向服务器发送消息。
|
|
132
|
+
*
|
|
133
|
+
* 将消息对象序列化为 JSON 并通过 WebSocket 发送。
|
|
134
|
+
* 仅在 WebSocket 连接处于 OPEN 状态时才能发送。
|
|
135
|
+
*
|
|
136
|
+
* @param message - 要发送的消息对象
|
|
137
|
+
* @returns 发送成功返回 `true`,未连接时返回 `false`
|
|
138
|
+
*/
|
|
139
|
+
sendMessage(message: any): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* 检查是否已连接到服务器。
|
|
142
|
+
*
|
|
143
|
+
* @returns 已连接返回 `true`,否则返回 `false`
|
|
144
|
+
*/
|
|
145
|
+
isConnected(): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* 检查是否已通过身份认证。
|
|
148
|
+
*
|
|
149
|
+
* @returns 已认证返回 `true`,否则返回 `false`
|
|
150
|
+
*/
|
|
151
|
+
isAuthenticated(): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* 获取当前重连尝试次数。
|
|
154
|
+
*
|
|
155
|
+
* @returns 当前重连次数
|
|
156
|
+
*/
|
|
157
|
+
getReconnectAttempts(): number;
|
|
158
|
+
/**
|
|
159
|
+
* 断开与服务器的连接。
|
|
160
|
+
*
|
|
161
|
+
* 清除重连定时器、停止心跳、关闭 WebSocket 连接,
|
|
162
|
+
* 并重置连接和认证状态。
|
|
163
|
+
*/
|
|
164
|
+
disconnect(): void;
|
|
165
|
+
/**
|
|
166
|
+
* 销毁控制器实例,释放所有资源。
|
|
167
|
+
*
|
|
168
|
+
* 断开连接、清除所有待处理请求的超时定时器、
|
|
169
|
+
* 清空待处理请求映射表并移除所有事件监听器。
|
|
170
|
+
*/
|
|
171
|
+
destroy(): void;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AActC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,cAAc;IACd,OAAO,CAAC,MAAM,CAAS;IAEvB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,CAA0B;IAEpC,gBAAgB;IAChB,OAAO,CAAC,SAAS,CAAkB;IAEnC,gBAAgB;IAChB,OAAO,CAAC,aAAa,CAAkB;IAEvC,YAAY;IACZ,OAAO,CAAC,cAAc,CAA+B;IAErD,YAAY;IACZ,OAAO,CAAC,cAAc,CAA+B;IAErD,eAAe;IACf,OAAO,CAAC,iBAAiB,CAAa;IAEtC,wBAAwB;IACxB,OAAO,CAAC,eAAe,CAIR;IAEf;;;;OAIG;gBACS,MAAM,EAAE,MAAM;IAK1B;;;;;;;;OAQG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA4C9B;;;;;;OAMG;YACW,YAAY;IAiB1B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAWtB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAkCrB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAStB;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAE,MAAc,GAAG,OAAO,CAAC,CAAC,CAAC;IAYjE;;;;;;;;OAQG;IACH,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IASlC;;;;OAIG;IACH,WAAW,IAAI,OAAO;IAItB;;;;OAIG;IACH,eAAe,IAAI,OAAO;IAI1B;;;;OAIG;IACH,oBAAoB,IAAI,MAAM;IAI9B;;;;;OAKG;IACH,UAAU,IAAI,IAAI;IAclB;;;;;OAKG;IACH,OAAO,IAAI,IAAI;CAQhB"}
|