@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,513 @@
1
+ /**
2
+ * Edge 管理多个设备的示例
3
+ * 展示一个 Edge 如何代理和管理多个不同类型的设备
4
+ */
5
+
6
+ import {
7
+ EdgeProxy,
8
+ EdgeProxyUtils,
9
+ ManagedDevice,
10
+ MessageFactory,
11
+ CommandMessage,
12
+ ClientType
13
+ } from '../src';
14
+
15
+ /**
16
+ * 地铁站 Edge 节点
17
+ * 管理一个站点的所有设备
18
+ */
19
+ export class SubwayStationEdge extends EdgeProxy {
20
+ // 设备分组管理
21
+ private deviceGroups = {
22
+ platform: new Set<string>(), // 站台设备
23
+ escalator: new Set<string>(), // 扶梯设备
24
+ ventilation: new Set<string>(), // 通风设备
25
+ lighting: new Set<string>(), // 照明设备
26
+ security: new Set<string>() // 安防设备
27
+ };
28
+
29
+ constructor(stationId: string) {
30
+ super(`edge-${stationId}`);
31
+ }
32
+
33
+ /**
34
+ * 初始化站点所有设备
35
+ */
36
+ async initializeStation() {
37
+ console.log(`Initializing station ${this.edgeId}`);
38
+
39
+ // 添加站台设备
40
+ await this.addPlatformDevices();
41
+
42
+ // 添加扶梯设备
43
+ await this.addEscalatorDevices();
44
+
45
+ // 添加通风设备
46
+ await this.addVentilationDevices();
47
+
48
+ // 添加照明设备
49
+ await this.addLightingDevices();
50
+
51
+ // 添加安防设备
52
+ await this.addSecurityDevices();
53
+
54
+ console.log(`Station initialized with ${this.devices.size} devices`);
55
+ this.reportDeviceStatistics();
56
+ }
57
+
58
+ /**
59
+ * 添加站台设备
60
+ */
61
+ private async addPlatformDevices() {
62
+ const platformDevices = [
63
+ { id: 'psd-01', name: '1号站台屏蔽门-A', type: 'platform_door' },
64
+ { id: 'psd-02', name: '1号站台屏蔽门-B', type: 'platform_door' },
65
+ { id: 'psd-03', name: '2号站台屏蔽门-A', type: 'platform_door' },
66
+ { id: 'psd-04', name: '2号站台屏蔽门-B', type: 'platform_door' },
67
+ { id: 'dis-01', name: '1号站台显示屏', type: 'display' },
68
+ { id: 'dis-02', name: '2号站台显示屏', type: 'display' },
69
+ { id: 'pa-01', name: '站台广播系统', type: 'pa_system' }
70
+ ];
71
+
72
+ for (const dev of platformDevices) {
73
+ const device: ManagedDevice = {
74
+ deviceId: dev.id,
75
+ deviceType: dev.type,
76
+ status: 'online',
77
+ lastSeen: new Date().toISOString(),
78
+ capabilities: this.getDeviceCapabilities(dev.type),
79
+ metadata: {
80
+ name: dev.name,
81
+ group: 'platform',
82
+ location: 'platform_area'
83
+ }
84
+ };
85
+
86
+ this.addDevice(device);
87
+ this.deviceGroups.platform.add(dev.id);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * 添加扶梯设备
93
+ */
94
+ private async addEscalatorDevices() {
95
+ const escalators = [
96
+ { id: 'esc-01', name: 'A出口上行扶梯', direction: 'up', location: 'exit_a' },
97
+ { id: 'esc-02', name: 'A出口下行扶梯', direction: 'down', location: 'exit_a' },
98
+ { id: 'esc-03', name: 'B出口上行扶梯', direction: 'up', location: 'exit_b' },
99
+ { id: 'esc-04', name: 'B出口下行扶梯', direction: 'down', location: 'exit_b' }
100
+ ];
101
+
102
+ for (const esc of escalators) {
103
+ const device: ManagedDevice = {
104
+ deviceId: esc.id,
105
+ deviceType: 'escalator',
106
+ status: 'online',
107
+ lastSeen: new Date().toISOString(),
108
+ capabilities: ['start', 'stop', 'emergency_stop', 'speed_control', 'status_read'],
109
+ metadata: {
110
+ name: esc.name,
111
+ direction: esc.direction,
112
+ location: esc.location,
113
+ group: 'escalator'
114
+ }
115
+ };
116
+
117
+ this.addDevice(device);
118
+ this.deviceGroups.escalator.add(esc.id);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * 添加通风设备
124
+ */
125
+ private async addVentilationDevices() {
126
+ const ventilationDevices = [
127
+ { id: 'fan-01', name: '站台通风机1', power: 50 },
128
+ { id: 'fan-02', name: '站台通风机2', power: 50 },
129
+ { id: 'fan-03', name: '隧道通风机1', power: 100 },
130
+ { id: 'fan-04', name: '隧道通风机2', power: 100 },
131
+ { id: 'ac-01', name: '站厅空调系统', type: 'ac_unit' },
132
+ { id: 'ac-02', name: '设备房空调系统', type: 'ac_unit' }
133
+ ];
134
+
135
+ for (const vent of ventilationDevices) {
136
+ const device: ManagedDevice = {
137
+ deviceId: vent.id,
138
+ deviceType: vent.type || 'ventilation_fan',
139
+ status: 'online',
140
+ lastSeen: new Date().toISOString(),
141
+ capabilities: ['start', 'stop', 'speed_control', 'power_read', 'temperature_read'],
142
+ metadata: {
143
+ name: vent.name,
144
+ power: vent.power,
145
+ group: 'ventilation'
146
+ }
147
+ };
148
+
149
+ this.addDevice(device);
150
+ this.deviceGroups.ventilation.add(vent.id);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * 添加照明设备
156
+ */
157
+ private async addLightingDevices() {
158
+ const lightingZones = [
159
+ { id: 'light-01', name: '站台照明A区', zone: 'platform_a' },
160
+ { id: 'light-02', name: '站台照明B区', zone: 'platform_b' },
161
+ { id: 'light-03', name: '站厅照明', zone: 'hall' },
162
+ { id: 'light-04', name: '通道照明', zone: 'passage' },
163
+ { id: 'light-05', name: '应急照明', zone: 'emergency', type: 'emergency_light' }
164
+ ];
165
+
166
+ for (const light of lightingZones) {
167
+ const device: ManagedDevice = {
168
+ deviceId: light.id,
169
+ deviceType: light.type || 'lighting_zone',
170
+ status: 'online',
171
+ lastSeen: new Date().toISOString(),
172
+ capabilities: ['on', 'off', 'dimming', 'brightness_read', 'power_read'],
173
+ metadata: {
174
+ name: light.name,
175
+ zone: light.zone,
176
+ group: 'lighting'
177
+ }
178
+ };
179
+
180
+ this.addDevice(device);
181
+ this.deviceGroups.lighting.add(light.id);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 添加安防设备
187
+ */
188
+ private async addSecurityDevices() {
189
+ const securityDevices = [
190
+ { id: 'cam-01', name: '站台监控摄像头1', type: 'camera', location: 'platform_1' },
191
+ { id: 'cam-02', name: '站台监控摄像头2', type: 'camera', location: 'platform_2' },
192
+ { id: 'cam-03', name: '站厅监控摄像头', type: 'camera', location: 'hall' },
193
+ { id: 'gate-01', name: '进站闸机组', type: 'gate', count: 6 },
194
+ { id: 'gate-02', name: '出站闸机组', type: 'gate', count: 6 },
195
+ { id: 'alarm-01', name: '火灾报警系统', type: 'fire_alarm' },
196
+ { id: 'alarm-02', name: '紧急呼叫系统', type: 'emergency_call' }
197
+ ];
198
+
199
+ for (const sec of securityDevices) {
200
+ const device: ManagedDevice = {
201
+ deviceId: sec.id,
202
+ deviceType: sec.type,
203
+ status: 'online',
204
+ lastSeen: new Date().toISOString(),
205
+ capabilities: this.getSecurityDeviceCapabilities(sec.type),
206
+ metadata: {
207
+ name: sec.name,
208
+ location: sec.location,
209
+ count: sec.count,
210
+ group: 'security'
211
+ }
212
+ };
213
+
214
+ this.addDevice(device);
215
+ this.deviceGroups.security.add(sec.id);
216
+ }
217
+ }
218
+
219
+ /**
220
+ * 获取设备能力列表
221
+ */
222
+ private getDeviceCapabilities(deviceType: string): string[] {
223
+ const capabilityMap: Record<string, string[]> = {
224
+ platform_door: ['open', 'close', 'emergency_open', 'status_read', 'fault_read'],
225
+ display: ['show_message', 'clear', 'brightness_control', 'status_read'],
226
+ pa_system: ['broadcast', 'stop', 'volume_control', 'zone_select'],
227
+ escalator: ['start', 'stop', 'emergency_stop', 'speed_control', 'status_read'],
228
+ ventilation_fan: ['start', 'stop', 'speed_control', 'power_read'],
229
+ ac_unit: ['start', 'stop', 'temperature_set', 'mode_set', 'status_read'],
230
+ lighting_zone: ['on', 'off', 'dimming', 'brightness_read'],
231
+ emergency_light: ['on', 'off', 'test', 'battery_read']
232
+ };
233
+
234
+ return capabilityMap[deviceType] || ['status_read'];
235
+ }
236
+
237
+ /**
238
+ * 获取安防设备能力
239
+ */
240
+ private getSecurityDeviceCapabilities(deviceType: string): string[] {
241
+ const capabilityMap: Record<string, string[]> = {
242
+ camera: ['stream_start', 'stream_stop', 'snapshot', 'ptz_control', 'status_read'],
243
+ gate: ['open', 'close', 'emergency_open', 'passenger_count', 'status_read'],
244
+ fire_alarm: ['status_read', 'test', 'reset', 'zone_status'],
245
+ emergency_call: ['status_read', 'answer', 'broadcast', 'test']
246
+ };
247
+
248
+ return capabilityMap[deviceType] || ['status_read'];
249
+ }
250
+
251
+ /**
252
+ * 报告设备统计信息
253
+ */
254
+ private reportDeviceStatistics() {
255
+ console.log('\n=== 站点设备统计 ===');
256
+ console.log(`总设备数: ${this.devices.size}`);
257
+
258
+ for (const [group, deviceIds] of Object.entries(this.deviceGroups)) {
259
+ console.log(`${group}: ${deviceIds.size} 台设备`);
260
+ }
261
+
262
+ // 按类型统计
263
+ const typeCount = new Map<string, number>();
264
+ for (const device of this.devices.values()) {
265
+ const count = typeCount.get(device.deviceType) || 0;
266
+ typeCount.set(device.deviceType, count + 1);
267
+ }
268
+
269
+ console.log('\n按设备类型统计:');
270
+ for (const [type, count] of typeCount) {
271
+ console.log(` ${type}: ${count}`);
272
+ }
273
+ }
274
+
275
+ /**
276
+ * 执行设备组命令
277
+ */
278
+ async executeGroupCommand(
279
+ group: keyof typeof this.deviceGroups,
280
+ command: Partial<CommandMessage['command']>
281
+ ) {
282
+ const deviceIds = Array.from(this.deviceGroups[group]);
283
+
284
+ if (deviceIds.length === 0) {
285
+ throw new Error(`No devices in group: ${group}`);
286
+ }
287
+
288
+ console.log(`Executing command on ${group} group (${deviceIds.length} devices)`);
289
+
290
+ // 创建批量命令
291
+ const batchCommand = EdgeProxyUtils.createEdgeBatchCommand(
292
+ `group-${group}-${Date.now()}`,
293
+ this.edgeId,
294
+ deviceIds,
295
+ {
296
+ commandCode: command.commandCode || 'STATUS_READ',
297
+ deviceType: command.deviceType || 'generic',
298
+ operationType: command.operationType || 'read',
299
+ parameters: command.parameters || {}
300
+ },
301
+ {
302
+ failureStrategy: 'continue_on_failure'
303
+ }
304
+ );
305
+
306
+ // 执行命令
307
+ return await this.handleGatewayCommand(batchCommand);
308
+ }
309
+
310
+ /**
311
+ * 紧急响应场景
312
+ */
313
+ async executeEmergencyResponse(scenario: 'fire' | 'evacuation' | 'power_failure') {
314
+ console.log(`Executing emergency response: ${scenario}`);
315
+
316
+ switch (scenario) {
317
+ case 'fire':
318
+ // 火灾响应
319
+ await Promise.all([
320
+ // 打开所有屏蔽门
321
+ this.executeGroupCommand('platform', {
322
+ commandCode: 'EMERGENCY_OPEN',
323
+ operationType: 'write'
324
+ }),
325
+ // 停止所有扶梯
326
+ this.executeGroupCommand('escalator', {
327
+ commandCode: 'EMERGENCY_STOP',
328
+ operationType: 'write'
329
+ }),
330
+ // 启动应急照明
331
+ this.executeDeviceCommand('light-05', {
332
+ commandCode: 'ON',
333
+ operationType: 'write'
334
+ }),
335
+ // 启动排烟模式
336
+ this.executeGroupCommand('ventilation', {
337
+ commandCode: 'SMOKE_EXHAUST_MODE',
338
+ operationType: 'write'
339
+ })
340
+ ]);
341
+ break;
342
+
343
+ case 'evacuation':
344
+ // 疏散响应
345
+ await Promise.all([
346
+ // 广播疏散信息
347
+ this.executeDeviceCommand('pa-01', {
348
+ commandCode: 'BROADCAST',
349
+ operationType: 'write',
350
+ parameters: { message: 'evacuation_announcement' }
351
+ }),
352
+ // 显示疏散指引
353
+ this.executeGroupCommand('platform', {
354
+ commandCode: 'SHOW_MESSAGE',
355
+ operationType: 'write',
356
+ parameters: { message: 'evacuation_guide' }
357
+ }),
358
+ // 打开所有闸机
359
+ this.executeDeviceCommands(['gate-01', 'gate-02'], {
360
+ commandCode: 'EMERGENCY_OPEN',
361
+ operationType: 'write'
362
+ })
363
+ ]);
364
+ break;
365
+
366
+ case 'power_failure':
367
+ // 停电响应
368
+ await Promise.all([
369
+ // 切换到应急电源模式
370
+ this.switchToEmergencyPower(),
371
+ // 关闭非必要设备
372
+ this.shutdownNonEssentialDevices()
373
+ ]);
374
+ break;
375
+ }
376
+ }
377
+
378
+ /**
379
+ * 批量执行设备命令
380
+ */
381
+ private async executeDeviceCommands(
382
+ deviceIds: string[],
383
+ command: Partial<CommandMessage['command']>
384
+ ) {
385
+ const promises = deviceIds.map(deviceId =>
386
+ this.executeDeviceCommand(deviceId, command)
387
+ );
388
+ return await Promise.all(promises);
389
+ }
390
+
391
+ /**
392
+ * 切换到应急电源
393
+ */
394
+ private async switchToEmergencyPower() {
395
+ // 实现应急电源切换逻辑
396
+ console.log('Switching to emergency power mode');
397
+ }
398
+
399
+ /**
400
+ * 关闭非必要设备
401
+ */
402
+ private async shutdownNonEssentialDevices() {
403
+ // 保持应急照明和通风
404
+ const essentialDevices = new Set(['light-05', 'fan-01', 'fan-02']);
405
+
406
+ for (const [deviceId, device] of this.devices) {
407
+ if (!essentialDevices.has(deviceId) &&
408
+ (device.deviceType === 'lighting_zone' || device.deviceType === 'ac_unit')) {
409
+ await this.executeDeviceCommand(deviceId, {
410
+ commandCode: 'OFF',
411
+ operationType: 'write'
412
+ });
413
+ }
414
+ }
415
+ }
416
+
417
+ /**
418
+ * 生成设备状态报告
419
+ */
420
+ generateDeviceReport(): any {
421
+ const report = {
422
+ stationId: this.edgeId,
423
+ timestamp: new Date().toISOString(),
424
+ summary: {
425
+ totalDevices: this.devices.size,
426
+ onlineDevices: 0,
427
+ offlineDevices: 0,
428
+ errorDevices: 0
429
+ },
430
+ groups: {} as Record<string, any>,
431
+ alerts: [] as any[]
432
+ };
433
+
434
+ // 统计设备状态
435
+ for (const device of this.devices.values()) {
436
+ switch (device.status) {
437
+ case 'online':
438
+ report.summary.onlineDevices++;
439
+ break;
440
+ case 'offline':
441
+ report.summary.offlineDevices++;
442
+ break;
443
+ case 'error':
444
+ report.summary.errorDevices++;
445
+ report.alerts.push({
446
+ deviceId: device.deviceId,
447
+ deviceType: device.deviceType,
448
+ message: `Device ${device.deviceId} is in error state`
449
+ });
450
+ break;
451
+ }
452
+ }
453
+
454
+ // 按组统计
455
+ for (const [group, deviceIds] of Object.entries(this.deviceGroups)) {
456
+ const groupDevices = Array.from(deviceIds).map(id => this.devices.get(id));
457
+ report.groups[group] = {
458
+ total: deviceIds.size,
459
+ online: groupDevices.filter(d => d?.status === 'online').length,
460
+ offline: groupDevices.filter(d => d?.status === 'offline').length,
461
+ error: groupDevices.filter(d => d?.status === 'error').length
462
+ };
463
+ }
464
+
465
+ return report;
466
+ }
467
+ }
468
+
469
+ // 使用示例
470
+ async function demonstrateMultiDeviceEdge() {
471
+ // 创建地铁站 Edge
472
+ const stationEdge = new SubwayStationEdge('station-001');
473
+
474
+ // 初始化所有设备
475
+ await stationEdge.initializeStation();
476
+
477
+ // 注册到 Gateway
478
+ await stationEdge.connectToGateway('ws://gateway:3001');
479
+ stationEdge.registerToGateway();
480
+
481
+ // 执行日常操作
482
+ console.log('\n执行早高峰模式...');
483
+ await Promise.all([
484
+ // 增加通风
485
+ stationEdge.executeGroupCommand('ventilation', {
486
+ commandCode: 'SET_SPEED',
487
+ operationType: 'write',
488
+ parameters: { speed: 80 }
489
+ }),
490
+ // 增加照明亮度
491
+ stationEdge.executeGroupCommand('lighting', {
492
+ commandCode: 'SET_BRIGHTNESS',
493
+ operationType: 'write',
494
+ parameters: { brightness: 100 }
495
+ }),
496
+ // 加快扶梯速度
497
+ stationEdge.executeGroupCommand('escalator', {
498
+ commandCode: 'SET_SPEED',
499
+ operationType: 'write',
500
+ parameters: { speed: 'fast' }
501
+ })
502
+ ]);
503
+
504
+ // 模拟紧急情况
505
+ console.log('\n模拟火灾紧急响应...');
506
+ await stationEdge.executeEmergencyResponse('fire');
507
+
508
+ // 生成报告
509
+ const report = stationEdge.generateDeviceReport();
510
+ console.log('\n设备状态报告:', JSON.stringify(report, null, 2));
511
+ }
512
+
513
+ export { SubwayStationEdge, demonstrateMultiDeviceEdge };
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Gateway 升级示例 - 支持新旧协议
3
+ */
4
+
5
+ import {
6
+ RegisterMessage,
7
+ MessageValidator,
8
+ ProtocolConverter,
9
+ isRegisterMessage
10
+ } from '@jrsoft/subway-protocol';
11
+
12
+ // 扩展的客户端信息存储
13
+ interface ExtendedClient {
14
+ ws: any; // WebSocket
15
+ clientId: string;
16
+ clientType: string;
17
+ clientInfo: Record<string, any>;
18
+ protocolVersion: string;
19
+ registeredAt: Date;
20
+ sessionId?: string;
21
+ }
22
+
23
+ export class UpgradedWebSocketHandler {
24
+ private clients = new Map<string, ExtendedClient>();
25
+
26
+ /**
27
+ * 处理注册消息 - 支持新旧格式
28
+ */
29
+ handleRegister(ws: any, rawMessage: any) {
30
+ // 1. 标准化消息格式
31
+ const message = ProtocolConverter.normalizeMessage(rawMessage);
32
+
33
+ if (!message || !isRegisterMessage(message)) {
34
+ this.sendError(ws, 'Invalid register message');
35
+ return;
36
+ }
37
+
38
+ // 2. 验证消息
39
+ if (!MessageValidator.validateRegisterMessage(message)) {
40
+ this.sendError(ws, 'Register message validation failed');
41
+ return;
42
+ }
43
+
44
+ const registerMsg = message as RegisterMessage;
45
+
46
+ // 3. 提取信息(支持简单和完整格式)
47
+ const client: ExtendedClient = {
48
+ ws,
49
+ clientId: registerMsg.clientId,
50
+ clientType: registerMsg.clientType || 'device',
51
+ clientInfo: registerMsg.clientInfo || {},
52
+ protocolVersion: registerMsg.version || '1.0',
53
+ registeredAt: new Date(),
54
+ sessionId: this.generateSessionId()
55
+ };
56
+
57
+ // 4. 存储客户端
58
+ this.clients.set(registerMsg.clientId, client);
59
+
60
+ // 5. 记录协议版本信息
61
+ console.log(`Client registered:`, {
62
+ clientId: client.clientId,
63
+ clientType: client.clientType,
64
+ protocolVersion: client.protocolVersion,
65
+ capabilities: client.clientInfo.capabilities || []
66
+ });
67
+
68
+ // 6. 发送确认(根据协议版本调整响应)
69
+ const ack = this.createRegisterAck(client);
70
+ ws.send(JSON.stringify(ack));
71
+ }
72
+
73
+ /**
74
+ * 创建注册确认消息
75
+ */
76
+ private createRegisterAck(client: ExtendedClient) {
77
+ const isNewProtocol = parseFloat(client.protocolVersion) >= 1.0;
78
+
79
+ const ack: any = {
80
+ type: 'register_ack',
81
+ clientId: client.clientId,
82
+ success: true
83
+ };
84
+
85
+ // 新协议包含更多信息
86
+ if (isNewProtocol) {
87
+ ack.sessionId = client.sessionId;
88
+ ack.timestamp = new Date().toISOString();
89
+ ack.version = '1.0';
90
+ }
91
+
92
+ return ack;
93
+ }
94
+
95
+ /**
96
+ * 获取客户端信息(包括扩展信息)
97
+ */
98
+ getClientInfo(clientId: string): ExtendedClient | undefined {
99
+ return this.clients.get(clientId);
100
+ }
101
+
102
+ /**
103
+ * 根据客户端类型获取所有客户端
104
+ */
105
+ getClientsByType(clientType: string): ExtendedClient[] {
106
+ return Array.from(this.clients.values())
107
+ .filter(client => client.clientType === clientType);
108
+ }
109
+
110
+ /**
111
+ * 发送错误消息
112
+ */
113
+ private sendError(ws: any, message: string) {
114
+ ws.send(JSON.stringify({
115
+ type: 'error',
116
+ message,
117
+ timestamp: new Date().toISOString()
118
+ }));
119
+ }
120
+
121
+ /**
122
+ * 生成会话ID
123
+ */
124
+ private generateSessionId(): string {
125
+ return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
126
+ }
127
+ }
128
+
129
+ // 使用示例
130
+ const handler = new UpgradedWebSocketHandler();
131
+
132
+ // 处理旧格式消息
133
+ handler.handleRegister(mockWs, {
134
+ type: 'register',
135
+ clientId: 'device001'
136
+ });
137
+
138
+ // 处理新格式消息
139
+ handler.handleRegister(mockWs, {
140
+ type: 'register',
141
+ clientId: 'backend-server',
142
+ clientType: 'backend',
143
+ clientInfo: {
144
+ version: '1.0.0',
145
+ platform: 'nodejs',
146
+ capabilities: ['command', 'program']
147
+ },
148
+ timestamp: new Date().toISOString(),
149
+ version: '1.0'
150
+ });