@thejrsoft/subway-protocol 1.3.0

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.
Files changed (78) hide show
  1. package/ACK_MESSAGES_IMPLEMENTATION_SUMMARY.md +128 -0
  2. package/ACK_MESSAGE_DESIGN.md +457 -0
  3. package/CHANGELOG.md +58 -0
  4. package/COMMAND_VALIDATION_RULES.md +178 -0
  5. package/DOCUMENTATION_REORGANIZATION_SUMMARY.md +81 -0
  6. package/DOCUMENTATION_STRUCTURE.md +106 -0
  7. package/GATEWAY_MIGRATION_GUIDE.md +130 -0
  8. package/GATEWAY_PROTOCOL_COMPARISON.md +216 -0
  9. package/INTEGRATION_GUIDE.md +190 -0
  10. package/OPTIONAL_FIELDS_WITHOUT_DEFAULTS.md +97 -0
  11. package/PROTOCOL_UTILS_USAGE.md +278 -0
  12. package/README.md +237 -0
  13. package/TYPE_FIXES_SUMMARY.md +210 -0
  14. package/UPDATE_ENUM_VALUES.md +139 -0
  15. package/dist/asyncapi-sync.d.ts +47 -0
  16. package/dist/asyncapi-sync.d.ts.map +1 -0
  17. package/dist/asyncapi-sync.js +85 -0
  18. package/dist/asyncapi-sync.js.map +1 -0
  19. package/dist/command-factory.d.ts +62 -0
  20. package/dist/command-factory.d.ts.map +1 -0
  21. package/dist/command-factory.js +137 -0
  22. package/dist/command-factory.js.map +1 -0
  23. package/dist/command-types.d.ts +27 -0
  24. package/dist/command-types.d.ts.map +1 -0
  25. package/dist/command-types.js +31 -0
  26. package/dist/command-types.js.map +1 -0
  27. package/dist/index.d.ts +403 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +413 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/message-validator.d.ts +102 -0
  32. package/dist/message-validator.d.ts.map +1 -0
  33. package/dist/message-validator.js +640 -0
  34. package/dist/message-validator.js.map +1 -0
  35. package/dist/protocol-utils.d.ts +108 -0
  36. package/dist/protocol-utils.d.ts.map +1 -0
  37. package/dist/protocol-utils.js +293 -0
  38. package/dist/protocol-utils.js.map +1 -0
  39. package/docs/01-protocol/README.md +45 -0
  40. package/docs/01-protocol/design-rationale.md +198 -0
  41. package/docs/01-protocol/message-types.md +669 -0
  42. package/docs/01-protocol/specification.md +1466 -0
  43. package/docs/02-commands/README.md +56 -0
  44. package/docs/02-commands/batch-command.md +435 -0
  45. package/docs/02-commands/complex-command.md +537 -0
  46. package/docs/02-commands/simple-command.md +332 -0
  47. package/docs/02-commands/typed-commands.md +362 -0
  48. package/docs/03-architecture/README.md +66 -0
  49. package/docs/03-architecture/device-protocol.md +430 -0
  50. package/docs/03-architecture/edge-proxy.md +727 -0
  51. package/docs/03-architecture/routing-flow.md +893 -0
  52. package/docs/04-integration/README.md +144 -0
  53. package/docs/04-integration/backend-guide.md +551 -0
  54. package/docs/04-integration/edge-guide.md +684 -0
  55. package/docs/04-integration/gateway-guide.md +180 -0
  56. package/docs/04-integration/migration-guide.md +226 -0
  57. package/docs/05-examples/README.md +141 -0
  58. package/docs/05-examples/progress-update-examples.md +757 -0
  59. package/docs/06-reference/README.md +67 -0
  60. package/docs/06-reference/api.md +572 -0
  61. package/docs/06-reference/faq.md +302 -0
  62. package/docs/06-reference/glossary.md +232 -0
  63. package/examples/backend-upgrade.ts +279 -0
  64. package/examples/edge-multi-device.ts +513 -0
  65. package/examples/gateway-upgrade.ts +150 -0
  66. package/examples/protocol-implementation.ts +715 -0
  67. package/package.json +48 -0
  68. package/scripts/validate-asyncapi.ts +78 -0
  69. package/src/__tests__/protocol.test.ts +297 -0
  70. package/src/asyncapi-sync.ts +84 -0
  71. package/src/command-factory.ts +183 -0
  72. package/src/command-types.ts +72 -0
  73. package/src/edge-proxy.ts +494 -0
  74. package/src/gateway-extensions.ts +278 -0
  75. package/src/index.ts +792 -0
  76. package/src/message-validator.ts +726 -0
  77. package/src/protocol-utils.ts +355 -0
  78. package/tsconfig.json +24 -0
@@ -0,0 +1,128 @@
1
+ # ACK 消息实现总结
2
+
3
+ ## 已完成的更新
4
+
5
+ ### 1. 接口定义补充
6
+
7
+ #### RegisterAckMessage 增强
8
+ ```typescript
9
+ export interface RegisterAckMessage extends BaseMessage {
10
+ type: MessageType.REGISTER_ACK;
11
+ clientId: string; // 确认的客户端ID
12
+ success: boolean; // 注册是否成功
13
+ sessionId?: string; // 成功时分配的会话ID
14
+ error?: { // 失败时的错误信息
15
+ code: string;
16
+ message: string;
17
+ };
18
+ serverInfo?: { // 服务器信息
19
+ version: string;
20
+ capabilities: string[];
21
+ currentLoad?: number; // 当前负载
22
+ maxClients?: number; // 最大客户端数
23
+ };
24
+ }
25
+ ```
26
+
27
+ #### UnregisterMessage 新增
28
+ ```typescript
29
+ export interface UnregisterMessage extends BaseMessage {
30
+ type: MessageType.UNREGISTER;
31
+ clientId: string; // 客户端唯一标识符
32
+ reason?: string; // 注销原因
33
+ }
34
+ ```
35
+
36
+ #### UnregisterAckMessage 新增
37
+ ```typescript
38
+ export interface UnregisterAckMessage extends BaseMessage {
39
+ type: MessageType.UNREGISTER_ACK;
40
+ clientId: string; // 客户端唯一标识符
41
+ success: boolean; // 注销是否成功
42
+ cleanupInfo?: { // 清理信息
43
+ messagesProcessed: number; // 已处理的消息数
44
+ pendingMessages: number; // 待处理的消息数
45
+ connectionDuration: number; // 连接持续时间(秒)
46
+ };
47
+ }
48
+ ```
49
+
50
+ #### HeartbeatMessage 增强
51
+ ```typescript
52
+ export interface HeartbeatMessage extends BaseMessage {
53
+ type: MessageType.HEARTBEAT;
54
+ clientId: string; // 客户端唯一标识符
55
+ sequence: number; // 序列号,用于匹配请求和响应
56
+ clientTime: string; // 客户端时间戳
57
+ }
58
+ ```
59
+
60
+ #### HeartbeatAckMessage 增强
61
+ ```typescript
62
+ export interface HeartbeatAckMessage extends BaseMessage {
63
+ type: MessageType.HEARTBEAT_ACK;
64
+ clientId: string; // 客户端唯一标识符
65
+ sequence: number; // 原始序列号
66
+ clientTime: string; // 原始客户端时间
67
+ serverTime: string; // 服务器时间
68
+ latency?: number; // 服务器处理延迟(毫秒)
69
+ serverStatus?: { // 服务器状态
70
+ healthy: boolean;
71
+ activeConnections: number;
72
+ messageQueueSize: number;
73
+ cpuUsage?: number;
74
+ memoryUsage?: number;
75
+ };
76
+ }
77
+ ```
78
+
79
+ ### 2. 类型守卫函数
80
+
81
+ 新增了所有 ACK 消息的类型守卫函数:
82
+ - `isRegisterAckMessage()`
83
+ - `isUnregisterMessage()`
84
+ - `isUnregisterAckMessage()`
85
+ - `isHeartbeatMessage()`
86
+ - `isHeartbeatAckMessage()`
87
+ - `isErrorMessage()`
88
+
89
+ ### 3. 工厂方法
90
+
91
+ - 更新了 `createHeartbeatMessage()` 以包含必需的 sequence 和 clientTime
92
+ - 新增了 `createUnregisterMessage()` 工厂方法
93
+
94
+ ### 4. 导出类型
95
+
96
+ 更新了 `AnyMessage` 联合类型,包含了所有新增的消息类型。
97
+
98
+ ## 使用场景
99
+
100
+ ### 1. 连接管理
101
+ - **注册流程**:客户端发送 REGISTER,Gateway 返回 REGISTER_ACK 确认状态和会话信息
102
+ - **注销流程**:客户端发送 UNREGISTER,Gateway 清理资源后返回 UNREGISTER_ACK
103
+
104
+ ### 2. 健康监控
105
+ - **心跳检测**:通过 HEARTBEAT/HEARTBEAT_ACK 监控连接健康状态
106
+ - **延迟测量**:通过 sequence 和时间戳计算网络往返时间(RTT)
107
+ - **服务器状态**:HEARTBEAT_ACK 携带服务器负载和健康信息
108
+
109
+ ### 3. 负载均衡
110
+ - **智能路由**:根据 REGISTER_ACK 中的 serverInfo.currentLoad 选择负载最低的服务器
111
+ - **容量管理**:通过 maxClients 了解服务器容量
112
+
113
+ ### 4. 故障恢复
114
+ - **连接监控**:通过心跳 ACK 检测连接失效
115
+ - **优雅重连**:使用 UNREGISTER/UNREGISTER_ACK 确保资源正确清理
116
+
117
+ ## 实现建议
118
+
119
+ 1. **超时处理**:所有等待 ACK 的操作都应设置合理超时(建议 5 秒)
120
+ 2. **序列号管理**:心跳消息使用递增序列号,便于匹配请求和响应
121
+ 3. **错误重试**:注册失败时应实现指数退避重试
122
+ 4. **资源清理**:确保超时或失败时清理待处理的 ACK 请求
123
+
124
+ ## 文档位置
125
+
126
+ - 设计文档:`ACK_MESSAGE_DESIGN.md`
127
+ - 实现总结:`ACK_MESSAGES_IMPLEMENTATION_SUMMARY.md`
128
+ - 协议定义:`src/index.ts`
@@ -0,0 +1,457 @@
1
+ # ACK 消息类型设计方案
2
+
3
+ ## 概述
4
+
5
+ ACK(Acknowledgment)消息用于确认接收方已成功接收并处理了发送方的消息。这对于保证消息可靠性和状态同步非常重要。
6
+
7
+ ## ACK 消息类型定义
8
+
9
+ ### 1. REGISTER_ACK - 注册确认
10
+
11
+ #### 使用场景
12
+ - 客户端发送 REGISTER 消息后,Gateway 返回 REGISTER_ACK 确认注册结果
13
+ - 用于通知客户端是否成功注册,以及分配的会话信息
14
+
15
+ #### 接口定义
16
+ ```typescript
17
+ export interface RegisterAckMessage extends BaseMessage {
18
+ type: MessageType.REGISTER_ACK;
19
+ clientId: string; // 确认的客户端ID
20
+ success: boolean; // 注册是否成功
21
+ sessionId?: string; // 成功时分配的会话ID
22
+ error?: { // 失败时的错误信息
23
+ code: string;
24
+ message: string;
25
+ };
26
+ serverInfo?: { // 服务器信息
27
+ version: string;
28
+ capabilities: string[];
29
+ currentLoad?: number; // 当前负载
30
+ maxClients?: number; // 最大客户端数
31
+ };
32
+ }
33
+ ```
34
+
35
+ #### 交互流程
36
+ ```
37
+ Client Gateway
38
+ | |
39
+ | 1. REGISTER |
40
+ |----------------------->|
41
+ | | 2. 验证客户端信息
42
+ | | 3. 分配资源
43
+ | 4. REGISTER_ACK |
44
+ |<-----------------------|
45
+ | |
46
+ ```
47
+
48
+ ### 2. UNREGISTER_ACK - 注销确认
49
+
50
+ #### 使用场景
51
+ - 客户端主动断开连接前发送 UNREGISTER 消息
52
+ - Gateway 清理资源后返回 UNREGISTER_ACK 确认
53
+
54
+ #### 接口定义
55
+ ```typescript
56
+ export interface UnregisterMessage extends BaseMessage {
57
+ type: MessageType.UNREGISTER;
58
+ clientId: string;
59
+ reason?: string; // 注销原因
60
+ }
61
+
62
+ export interface UnregisterAckMessage extends BaseMessage {
63
+ type: MessageType.UNREGISTER_ACK;
64
+ clientId: string;
65
+ success: boolean;
66
+ cleanupInfo?: { // 清理信息
67
+ messagesProcessed: number; // 已处理的消息数
68
+ pendingMessages: number; // 待处理的消息数
69
+ connectionDuration: number; // 连接持续时间(秒)
70
+ };
71
+ }
72
+ ```
73
+
74
+ #### 交互流程
75
+ ```
76
+ Client Gateway
77
+ | |
78
+ | 1. UNREGISTER |
79
+ |----------------------->|
80
+ | | 2. 停止接收新消息
81
+ | | 3. 处理待处理消息
82
+ | | 4. 清理资源
83
+ | 5. UNREGISTER_ACK |
84
+ |<-----------------------|
85
+ | 6. 关闭连接 |
86
+ |----------------------->|
87
+ ```
88
+
89
+ ### 3. HEARTBEAT_ACK - 心跳确认
90
+
91
+ #### 使用场景
92
+ - 用于精确测量网络延迟
93
+ - 确认双向连接正常
94
+ - 携带服务器状态信息
95
+
96
+ #### 接口定义
97
+ ```typescript
98
+ export interface HeartbeatMessage extends BaseMessage {
99
+ type: MessageType.HEARTBEAT;
100
+ clientId: string;
101
+ sequence: number; // 序列号,用于匹配请求和响应
102
+ clientTime: string; // 客户端时间戳
103
+ }
104
+
105
+ export interface HeartbeatAckMessage extends BaseMessage {
106
+ type: MessageType.HEARTBEAT_ACK;
107
+ clientId: string;
108
+ sequence: number; // 原始序列号
109
+ clientTime: string; // 原始客户端时间
110
+ serverTime: string; // 服务器时间
111
+ latency?: number; // 服务器处理延迟(毫秒)
112
+ serverStatus?: { // 服务器状态
113
+ healthy: boolean;
114
+ activeConnections: number;
115
+ messageQueueSize: number;
116
+ cpuUsage?: number;
117
+ memoryUsage?: number;
118
+ };
119
+ }
120
+ ```
121
+
122
+ #### 交互流程
123
+ ```
124
+ Client Gateway
125
+ | |
126
+ | 1. HEARTBEAT |
127
+ | (seq=123) |
128
+ |----------------------->|
129
+ | | 2. 记录接收时间
130
+ | | 3. 检查系统状态
131
+ | 4. HEARTBEAT_ACK |
132
+ | (seq=123) |
133
+ |<-----------------------|
134
+ | 5. 计算往返延迟 |
135
+ | |
136
+ ```
137
+
138
+ ## 实现示例
139
+
140
+ ### 1. Gateway 端实现
141
+
142
+ ```typescript
143
+ class GatewayAckHandler {
144
+ // 处理注册消息
145
+ async handleRegister(ws: WebSocket, msg: RegisterMessage): Promise<void> {
146
+ try {
147
+ // 验证客户端
148
+ const validation = await this.validateClient(msg);
149
+
150
+ if (validation.success) {
151
+ // 注册成功
152
+ const sessionId = this.generateSessionId();
153
+ this.registerClient(msg.clientId, sessionId, ws);
154
+
155
+ const ackMessage: RegisterAckMessage = {
156
+ type: MessageType.REGISTER_ACK,
157
+ clientId: msg.clientId,
158
+ success: true,
159
+ sessionId,
160
+ serverInfo: {
161
+ version: '1.0',
162
+ capabilities: ['command', 'batch', 'complex'],
163
+ currentLoad: this.getCurrentLoad(),
164
+ maxClients: this.maxClients
165
+ },
166
+ timestamp: new Date().toISOString(),
167
+ version: '1.0'
168
+ };
169
+
170
+ ws.send(JSON.stringify(ackMessage));
171
+ } else {
172
+ // 注册失败
173
+ const ackMessage: RegisterAckMessage = {
174
+ type: MessageType.REGISTER_ACK,
175
+ clientId: msg.clientId,
176
+ success: false,
177
+ error: {
178
+ code: validation.errorCode,
179
+ message: validation.errorMessage
180
+ },
181
+ timestamp: new Date().toISOString(),
182
+ version: '1.0'
183
+ };
184
+
185
+ ws.send(JSON.stringify(ackMessage));
186
+ }
187
+ } catch (error) {
188
+ // 处理异常
189
+ this.sendErrorAck(ws, msg.clientId, error);
190
+ }
191
+ }
192
+
193
+ // 处理心跳消息
194
+ handleHeartbeat(ws: WebSocket, msg: HeartbeatMessage): void {
195
+ const serverTime = new Date().toISOString();
196
+ const receiveTime = Date.now();
197
+
198
+ // 计算服务器处理延迟
199
+ const latency = receiveTime - new Date(msg.timestamp).getTime();
200
+
201
+ const ackMessage: HeartbeatAckMessage = {
202
+ type: MessageType.HEARTBEAT_ACK,
203
+ clientId: msg.clientId,
204
+ sequence: msg.sequence,
205
+ clientTime: msg.clientTime,
206
+ serverTime,
207
+ latency,
208
+ serverStatus: {
209
+ healthy: true,
210
+ activeConnections: this.getActiveConnections(),
211
+ messageQueueSize: this.getQueueSize(),
212
+ cpuUsage: this.getCpuUsage(),
213
+ memoryUsage: this.getMemoryUsage()
214
+ },
215
+ timestamp: serverTime,
216
+ version: '1.0'
217
+ };
218
+
219
+ ws.send(JSON.stringify(ackMessage));
220
+ }
221
+ }
222
+ ```
223
+
224
+ ### 2. 客户端实现
225
+
226
+ ```typescript
227
+ class ClientAckHandler {
228
+ private pendingAcks = new Map<string, PendingAck>();
229
+
230
+ // 发送注册消息并等待 ACK
231
+ async register(): Promise<RegisterAckMessage> {
232
+ const registerMsg: RegisterMessage = {
233
+ type: MessageType.REGISTER,
234
+ clientId: this.clientId,
235
+ clientType: this.clientType,
236
+ clientInfo: {
237
+ version: '1.0.0',
238
+ platform: 'node',
239
+ capabilities: ['command', 'batch']
240
+ },
241
+ timestamp: new Date().toISOString(),
242
+ version: '1.0'
243
+ };
244
+
245
+ // 发送并等待 ACK
246
+ return await this.sendAndWaitForAck(
247
+ registerMsg,
248
+ MessageType.REGISTER_ACK,
249
+ 5000 // 5秒超时
250
+ );
251
+ }
252
+
253
+ // 发送心跳并测量延迟
254
+ async sendHeartbeat(): Promise<number> {
255
+ const sequence = this.nextSequence++;
256
+ const clientTime = new Date().toISOString();
257
+ const sendTime = Date.now();
258
+
259
+ const heartbeatMsg: HeartbeatMessage = {
260
+ type: MessageType.HEARTBEAT,
261
+ clientId: this.clientId,
262
+ sequence,
263
+ clientTime,
264
+ timestamp: clientTime,
265
+ version: '1.0'
266
+ };
267
+
268
+ const ack = await this.sendAndWaitForAck(
269
+ heartbeatMsg,
270
+ MessageType.HEARTBEAT_ACK,
271
+ 3000
272
+ ) as HeartbeatAckMessage;
273
+
274
+ // 计算往返时间
275
+ const rtt = Date.now() - sendTime;
276
+
277
+ // 更新服务器状态
278
+ this.updateServerStatus(ack.serverStatus);
279
+
280
+ return rtt;
281
+ }
282
+
283
+ // 优雅断开连接
284
+ async disconnect(): Promise<void> {
285
+ const unregisterMsg: UnregisterMessage = {
286
+ type: MessageType.UNREGISTER,
287
+ clientId: this.clientId,
288
+ reason: 'Client shutdown',
289
+ timestamp: new Date().toISOString(),
290
+ version: '1.0'
291
+ };
292
+
293
+ try {
294
+ const ack = await this.sendAndWaitForAck(
295
+ unregisterMsg,
296
+ MessageType.UNREGISTER_ACK,
297
+ 5000
298
+ ) as UnregisterAckMessage;
299
+
300
+ console.log('Disconnected gracefully:', ack.cleanupInfo);
301
+ } catch (error) {
302
+ console.error('Disconnect error:', error);
303
+ } finally {
304
+ this.ws.close();
305
+ }
306
+ }
307
+ }
308
+ ```
309
+
310
+ ## 使用场景详解
311
+
312
+ ### 1. 连接建立流程
313
+
314
+ ```typescript
315
+ // 客户端
316
+ async function connectToGateway() {
317
+ const client = new WebSocketClient('ws://gateway:18081');
318
+
319
+ try {
320
+ // 1. 建立 WebSocket 连接
321
+ await client.connect();
322
+
323
+ // 2. 发送注册消息并等待确认
324
+ const registerAck = await client.register();
325
+
326
+ if (!registerAck.success) {
327
+ throw new Error(`Registration failed: ${registerAck.error.message}`);
328
+ }
329
+
330
+ // 3. 保存会话信息
331
+ client.sessionId = registerAck.sessionId;
332
+ console.log(`Connected with session: ${registerAck.sessionId}`);
333
+
334
+ // 4. 启动心跳
335
+ client.startHeartbeat();
336
+
337
+ } catch (error) {
338
+ console.error('Connection failed:', error);
339
+ throw error;
340
+ }
341
+ }
342
+ ```
343
+
344
+ ### 2. 网络质量监控
345
+
346
+ ```typescript
347
+ class NetworkMonitor {
348
+ private rttHistory: number[] = [];
349
+ private readonly maxHistory = 100;
350
+
351
+ async monitorNetwork(client: WebSocketClient): Promise<void> {
352
+ setInterval(async () => {
353
+ try {
354
+ const rtt = await client.sendHeartbeat();
355
+ this.rttHistory.push(rtt);
356
+
357
+ if (this.rttHistory.length > this.maxHistory) {
358
+ this.rttHistory.shift();
359
+ }
360
+
361
+ // 分析网络质量
362
+ const avgRtt = this.calculateAverage(this.rttHistory);
363
+ const jitter = this.calculateJitter(this.rttHistory);
364
+
365
+ if (avgRtt > 1000 || jitter > 200) {
366
+ console.warn('Poor network quality detected', {
367
+ averageRtt: avgRtt,
368
+ jitter: jitter
369
+ });
370
+ }
371
+ } catch (error) {
372
+ console.error('Heartbeat failed:', error);
373
+ // 可能需要重连
374
+ }
375
+ }, 30000); // 30秒一次
376
+ }
377
+ }
378
+ ```
379
+
380
+ ### 3. 负载均衡决策
381
+
382
+ ```typescript
383
+ class LoadBalancer {
384
+ private gateways: GatewayInfo[] = [];
385
+
386
+ // 根据 REGISTER_ACK 中的服务器信息选择最优网关
387
+ selectBestGateway(): GatewayInfo {
388
+ // 收集所有网关的负载信息
389
+ const availableGateways = this.gateways.filter(gw => {
390
+ return gw.lastAck && gw.lastAck.serverInfo;
391
+ });
392
+
393
+ // 选择负载最低的网关
394
+ return availableGateways.reduce((best, current) => {
395
+ const bestLoad = best.lastAck.serverInfo.currentLoad || 0;
396
+ const currentLoad = current.lastAck.serverInfo.currentLoad || 0;
397
+ return currentLoad < bestLoad ? current : best;
398
+ });
399
+ }
400
+ }
401
+ ```
402
+
403
+ ### 4. 故障检测和恢复
404
+
405
+ ```typescript
406
+ class ConnectionManager {
407
+ private missedHeartbeats = 0;
408
+ private readonly maxMissedHeartbeats = 3;
409
+
410
+ async checkConnection(): Promise<void> {
411
+ try {
412
+ await this.client.sendHeartbeat();
413
+ this.missedHeartbeats = 0;
414
+ } catch (error) {
415
+ this.missedHeartbeats++;
416
+
417
+ if (this.missedHeartbeats >= this.maxMissedHeartbeats) {
418
+ console.error('Connection lost, attempting reconnect...');
419
+ await this.reconnect();
420
+ }
421
+ }
422
+ }
423
+
424
+ async reconnect(): Promise<void> {
425
+ // 1. 关闭现有连接
426
+ this.client.close();
427
+
428
+ // 2. 等待一段时间
429
+ await this.delay(5000);
430
+
431
+ // 3. 重新连接
432
+ await this.client.connect();
433
+
434
+ // 4. 重新注册
435
+ const ack = await this.client.register();
436
+ if (ack.success) {
437
+ console.log('Reconnected successfully');
438
+ this.missedHeartbeats = 0;
439
+ }
440
+ }
441
+ }
442
+ ```
443
+
444
+ ## 优势
445
+
446
+ 1. **可靠性保证** - 确保消息被正确接收和处理
447
+ 2. **状态同步** - 客户端和服务器保持状态一致
448
+ 3. **性能监控** - 通过心跳 ACK 监控网络延迟
449
+ 4. **优雅关闭** - 确保资源正确清理
450
+ 5. **错误处理** - 明确的错误反馈机制
451
+
452
+ ## 注意事项
453
+
454
+ 1. **超时处理** - 所有等待 ACK 的操作都应设置合理的超时时间
455
+ 2. **重试机制** - 对于关键操作(如注册),应实现重试逻辑
456
+ 3. **资源清理** - 超时或失败时要清理待处理的 ACK 请求
457
+ 4. **性能影响** - ACK 机制会增加消息往返,需要权衡可靠性和性能
package/CHANGELOG.md ADDED
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ ## [1.0.1] - 2024-01-XX
4
+
5
+ ### Added
6
+ - 为 `CommandMessage` 的 `retryCount` 字段添加默认值 0
7
+ - 为 `createCommandResponseMessage` 添加自动计算 `executionTime` 功能
8
+ - 新增 `commandStartTime` 选项,可自动计算命令执行时间
9
+ - 为 `createProgramResponseMessage` 添加自动计算 `executionTime` 功能
10
+ - 新增 `programStartTime` 选项,可自动计算程序执行时间
11
+ - 为 `createHeartbeatAckMessage` 添加自动计算 `latency` 功能
12
+ - 新增 `heartbeatReceivedTime` 选项,可自动计算处理延迟
13
+
14
+ ### 使用示例
15
+
16
+ ```typescript
17
+ // 1. retryCount 现在有默认值 0
18
+ const command = MessageFactory.createCommandMessage(
19
+ requestRef,
20
+ targetClientId,
21
+ commandObj,
22
+ callbackUrl
23
+ // retryCount 将默认为 0
24
+ );
25
+
26
+ // 2. 自动计算 executionTime
27
+ const startTime = Date.now();
28
+ // ... 执行命令 ...
29
+ const response = MessageFactory.createCommandResponseMessage(
30
+ requestRef,
31
+ CommandStatus.COMPLETED,
32
+ result,
33
+ 'Success',
34
+ { commandStartTime: startTime } // executionTime 将自动计算
35
+ );
36
+
37
+ // 3. 自动计算 latency
38
+ const receivedTime = Date.now();
39
+ // ... 处理心跳 ...
40
+ const ack = MessageFactory.createHeartbeatAckMessage(
41
+ sequence,
42
+ clientId,
43
+ clientTime,
44
+ { heartbeatReceivedTime: receivedTime } // latency 将自动计算
45
+ );
46
+ ```
47
+
48
+ ### Changed
49
+ - 无破坏性更改,所有改动向后兼容
50
+
51
+ ## [1.0.0] - 2024-01-XX
52
+
53
+ ### Initial Release
54
+ - 统一的 WebSocket 协议定义
55
+ - 完整的消息类型系统
56
+ - MessageFactory 工具类
57
+ - MessageValidator 验证器
58
+ - ProtocolUtils 工具类