@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,684 @@
1
+ # Edge 集成指南
2
+
3
+ 本文档说明如何实现和集成 Edge 节点,作为设备的代理服务。
4
+
5
+ ## 概述
6
+
7
+ Edge 节点是位于 Gateway 和设备之间的代理层,负责:
8
+ - 管理设备的 WebSocket 连接
9
+ - 转发 Gateway 和设备之间的消息
10
+ - 维护设备状态和连接信息
11
+ - 处理设备的注册和心跳
12
+
13
+ ## 架构设计
14
+
15
+ ```
16
+ Gateway (18081)
17
+
18
+ Edge (Dynamic Port)
19
+
20
+ Devices (Multiple Connections)
21
+ ```
22
+
23
+ ## 实现步骤
24
+
25
+ ### 1. Edge 服务器实现
26
+
27
+ ```typescript
28
+ import WebSocket from 'ws';
29
+ import { v4 as uuidv4 } from 'uuid';
30
+ import { EventEmitter } from 'events';
31
+
32
+ interface DeviceConnection {
33
+ id: string;
34
+ ws: WebSocket;
35
+ info: any;
36
+ lastHeartbeat: number;
37
+ }
38
+
39
+ export class EdgeServer extends EventEmitter {
40
+ private gatewayClient: WebSocket | null = null;
41
+ private deviceServer: WebSocket.Server;
42
+ private devices: Map<string, DeviceConnection> = new Map();
43
+ private edgeId: string;
44
+ private gatewayUrl: string;
45
+
46
+ constructor(edgeId: string, gatewayUrl: string, devicePort: number) {
47
+ super();
48
+ this.edgeId = edgeId;
49
+ this.gatewayUrl = gatewayUrl;
50
+
51
+ // 创建设备服务器
52
+ this.deviceServer = new WebSocket.Server({ port: devicePort });
53
+ this.setupDeviceServer();
54
+
55
+ // 连接到 Gateway
56
+ this.connectToGateway();
57
+
58
+ // 启动心跳检查
59
+ this.startHeartbeatCheck();
60
+ }
61
+
62
+ private connectToGateway(): void {
63
+ console.log(`Connecting to Gateway at ${this.gatewayUrl}`);
64
+
65
+ this.gatewayClient = new WebSocket(this.gatewayUrl);
66
+
67
+ this.gatewayClient.on('open', () => {
68
+ console.log('Connected to Gateway');
69
+ this.registerWithGateway();
70
+ });
71
+
72
+ this.gatewayClient.on('message', (data: WebSocket.Data) => {
73
+ this.handleGatewayMessage(data.toString());
74
+ });
75
+
76
+ this.gatewayClient.on('close', () => {
77
+ console.log('Disconnected from Gateway, reconnecting...');
78
+ setTimeout(() => this.connectToGateway(), 5000);
79
+ });
80
+
81
+ this.gatewayClient.on('error', (error) => {
82
+ console.error('Gateway connection error:', error);
83
+ });
84
+ }
85
+
86
+ private registerWithGateway(): void {
87
+ const registerMessage = {
88
+ type: 'register',
89
+ clientId: this.edgeId,
90
+ clientType: 'EDGE',
91
+ clientInfo: {
92
+ name: 'Edge Node',
93
+ version: '1.0.0',
94
+ capabilities: ['device-proxy', 'batch-command'],
95
+ metadata: {
96
+ maxDevices: 100,
97
+ location: 'tunnel-exit-1'
98
+ }
99
+ },
100
+ timestamp: new Date().toISOString(),
101
+ version: '1.0'
102
+ };
103
+
104
+ this.sendToGateway(registerMessage);
105
+
106
+ // 启动心跳
107
+ this.startGatewayHeartbeat();
108
+ }
109
+
110
+ private setupDeviceServer(): void {
111
+ this.deviceServer.on('connection', (ws: WebSocket, req) => {
112
+ console.log('New device connection');
113
+
114
+ // 临时存储连接,等待注册
115
+ const tempId = uuidv4();
116
+ let registered = false;
117
+
118
+ ws.on('message', (data: WebSocket.Data) => {
119
+ const message = JSON.parse(data.toString());
120
+
121
+ if (message.type === 'register' && !registered) {
122
+ // 处理设备注册
123
+ this.handleDeviceRegistration(ws, message);
124
+ registered = true;
125
+ } else if (registered) {
126
+ // 处理其他消息
127
+ this.handleDeviceMessage(message);
128
+ }
129
+ });
130
+
131
+ ws.on('close', () => {
132
+ // 查找并移除设备
133
+ for (const [id, device] of this.devices) {
134
+ if (device.ws === ws) {
135
+ console.log(`Device ${id} disconnected`);
136
+ this.devices.delete(id);
137
+ this.notifyGatewayDeviceStatus(id, 'offline');
138
+ break;
139
+ }
140
+ }
141
+ });
142
+
143
+ ws.on('error', (error) => {
144
+ console.error('Device connection error:', error);
145
+ });
146
+ });
147
+ }
148
+
149
+ private handleDeviceRegistration(ws: WebSocket, message: any): void {
150
+ const deviceId = message.clientId;
151
+
152
+ // 检查是否已存在
153
+ if (this.devices.has(deviceId)) {
154
+ console.log(`Device ${deviceId} already registered, closing old connection`);
155
+ this.devices.get(deviceId)!.ws.close();
156
+ }
157
+
158
+ // 存储设备连接
159
+ this.devices.set(deviceId, {
160
+ id: deviceId,
161
+ ws: ws,
162
+ info: message.clientInfo,
163
+ lastHeartbeat: Date.now()
164
+ });
165
+
166
+ console.log(`Device ${deviceId} registered`);
167
+
168
+ // 通知 Gateway 设备上线
169
+ this.notifyGatewayDeviceStatus(deviceId, 'online');
170
+
171
+ // 回复注册成功
172
+ ws.send(JSON.stringify({
173
+ type: 'register_response',
174
+ success: true,
175
+ timestamp: new Date().toISOString(),
176
+ version: '1.0'
177
+ }));
178
+ }
179
+ }
180
+ ```
181
+
182
+ ### 2. 消息路由实现
183
+
184
+ ```typescript
185
+ class MessageRouter {
186
+
187
+ // Gateway 消息处理
188
+ private handleGatewayMessage(data: string): void {
189
+ try {
190
+ const message = JSON.parse(data);
191
+
192
+ switch (message.type) {
193
+ case 'command':
194
+ this.routeCommandToDevice(message);
195
+ break;
196
+
197
+ case 'program':
198
+ this.routeProgramToDevice(message);
199
+ break;
200
+
201
+ case 'heartbeat':
202
+ // Gateway 心跳响应
203
+ break;
204
+
205
+ default:
206
+ console.log(`Unknown message type from Gateway: ${message.type}`);
207
+ }
208
+ } catch (error) {
209
+ console.error('Error handling Gateway message:', error);
210
+ }
211
+ }
212
+
213
+ // 路由命令到设备
214
+ private routeCommandToDevice(message: any): void {
215
+ // targetClientId 直接就是设备ID
216
+ const deviceId = message.targetClientId;
217
+
218
+ // 查找设备
219
+ const device = this.devices.get(deviceId);
220
+ if (!device) {
221
+ this.sendErrorToGateway(message.requestRef, 'DEVICE_NOT_FOUND',
222
+ `Device ${deviceId} not connected`);
223
+ return;
224
+ }
225
+
226
+ // 修改 targetClientId 为设备ID
227
+ message.targetClientId = deviceId;
228
+
229
+ // 转发到设备
230
+ device.ws.send(JSON.stringify(message));
231
+ console.log(`Forwarded command to device ${deviceId}`);
232
+ }
233
+
234
+ // 设备消息处理
235
+ private handleDeviceMessage(message: any): void {
236
+ switch (message.type) {
237
+ case 'command_response':
238
+ case 'progress_update':
239
+ case 'program_response':
240
+ // 转发响应到 Gateway
241
+ this.sendToGateway(message);
242
+ break;
243
+
244
+ case 'heartbeat':
245
+ // 更新设备心跳时间
246
+ const device = this.devices.get(message.clientId);
247
+ if (device) {
248
+ device.lastHeartbeat = Date.now();
249
+ }
250
+ break;
251
+
252
+ case 'error':
253
+ // 转发错误到 Gateway
254
+ this.sendToGateway(message);
255
+ break;
256
+
257
+ default:
258
+ console.log(`Unknown message type from device: ${message.type}`);
259
+ }
260
+ }
261
+
262
+ // 发送消息到 Gateway
263
+ private sendToGateway(message: any): void {
264
+ if (this.gatewayClient && this.gatewayClient.readyState === WebSocket.OPEN) {
265
+ this.gatewayClient.send(JSON.stringify(message));
266
+ } else {
267
+ console.error('Gateway connection not available');
268
+ // 可以考虑缓存消息,等待重连
269
+ }
270
+ }
271
+
272
+ // 发送错误到 Gateway
273
+ private sendErrorToGateway(requestRef: string, code: string, message: string): void {
274
+ const errorMessage = {
275
+ type: 'error',
276
+ requestRef,
277
+ code,
278
+ message,
279
+ timestamp: new Date().toISOString(),
280
+ version: '1.0'
281
+ };
282
+
283
+ this.sendToGateway(errorMessage);
284
+ }
285
+ }
286
+ ```
287
+
288
+ ### 3. 设备状态管理
289
+
290
+ ```typescript
291
+ class DeviceManager {
292
+ private devices: Map<string, DeviceConnection> = new Map();
293
+ private deviceStatus: Map<string, DeviceStatus> = new Map();
294
+
295
+ interface DeviceStatus {
296
+ online: boolean;
297
+ lastSeen: Date;
298
+ metrics: {
299
+ commandsReceived: number;
300
+ commandsSucceeded: number;
301
+ commandsFailed: number;
302
+ averageResponseTime: number;
303
+ };
304
+ }
305
+
306
+ // 通知 Gateway 设备状态变化
307
+ private notifyGatewayDeviceStatus(deviceId: string, status: 'online' | 'offline'): void {
308
+ const statusMessage = {
309
+ type: 'device_status',
310
+ edgeId: this.edgeId,
311
+ deviceId,
312
+ status,
313
+ timestamp: new Date().toISOString(),
314
+ version: '1.0'
315
+ };
316
+
317
+ this.sendToGateway(statusMessage);
318
+ }
319
+
320
+ // 获取所有设备状态
321
+ getDeviceStatuses(): DeviceStatus[] {
322
+ const statuses = [];
323
+
324
+ for (const [id, device] of this.devices) {
325
+ const status = this.deviceStatus.get(id) || this.createDefaultStatus();
326
+ statuses.push({
327
+ deviceId: id,
328
+ ...status,
329
+ info: device.info
330
+ });
331
+ }
332
+
333
+ return statuses;
334
+ }
335
+
336
+ // 更新设备指标
337
+ updateDeviceMetrics(deviceId: string, success: boolean, responseTime: number): void {
338
+ const status = this.deviceStatus.get(deviceId) || this.createDefaultStatus();
339
+
340
+ status.metrics.commandsReceived++;
341
+ if (success) {
342
+ status.metrics.commandsSucceeded++;
343
+ } else {
344
+ status.metrics.commandsFailed++;
345
+ }
346
+
347
+ // 计算平均响应时间
348
+ const total = status.metrics.commandsSucceeded;
349
+ status.metrics.averageResponseTime =
350
+ (status.metrics.averageResponseTime * (total - 1) + responseTime) / total;
351
+
352
+ this.deviceStatus.set(deviceId, status);
353
+ }
354
+ }
355
+ ```
356
+
357
+ ### 4. 心跳和健康检查
358
+
359
+ ```typescript
360
+ class HealthChecker {
361
+ private heartbeatInterval = 30000; // 30秒
362
+ private heartbeatTimeout = 90000; // 90秒
363
+
364
+ // Gateway 心跳
365
+ private startGatewayHeartbeat(): void {
366
+ setInterval(() => {
367
+ if (this.gatewayClient && this.gatewayClient.readyState === WebSocket.OPEN) {
368
+ const heartbeat = {
369
+ type: 'heartbeat',
370
+ clientId: this.edgeId,
371
+ timestamp: new Date().toISOString(),
372
+ version: '1.0'
373
+ };
374
+
375
+ this.gatewayClient.send(JSON.stringify(heartbeat));
376
+ }
377
+ }, this.heartbeatInterval);
378
+ }
379
+
380
+ // 设备心跳检查
381
+ private startHeartbeatCheck(): void {
382
+ setInterval(() => {
383
+ const now = Date.now();
384
+
385
+ for (const [id, device] of this.devices) {
386
+ if (now - device.lastHeartbeat > this.heartbeatTimeout) {
387
+ console.log(`Device ${id} heartbeat timeout, removing`);
388
+ device.ws.close();
389
+ this.devices.delete(id);
390
+ this.notifyGatewayDeviceStatus(id, 'offline');
391
+ }
392
+ }
393
+ }, this.heartbeatInterval);
394
+ }
395
+
396
+ // 健康检查端点
397
+ getHealthStatus(): HealthStatus {
398
+ return {
399
+ status: 'healthy',
400
+ edgeId: this.edgeId,
401
+ gatewayConnected: this.gatewayClient?.readyState === WebSocket.OPEN,
402
+ deviceCount: this.devices.size,
403
+ uptime: process.uptime(),
404
+ memory: process.memoryUsage(),
405
+ timestamp: new Date().toISOString()
406
+ };
407
+ }
408
+ }
409
+ ```
410
+
411
+ ### 5. 批量命令处理
412
+
413
+ ```typescript
414
+ class BatchCommandHandler {
415
+
416
+ // 处理批量命令
417
+ async handleBatchCommand(message: any): Promise<void> {
418
+ const { command } = message;
419
+ // targetClientId 直接就是设备ID
420
+ const targetDeviceId = message.targetClientId;
421
+
422
+ // 批量命令直接转发给设备
423
+ const device = this.devices.get(targetDeviceId);
424
+ if (!device) {
425
+ this.sendErrorToGateway(message.requestRef, 'DEVICE_NOT_FOUND',
426
+ `Device ${targetDeviceId} not connected`);
427
+ return;
428
+ }
429
+
430
+ // 设备会处理批量逻辑并发送进度更新
431
+ device.ws.send(JSON.stringify(message));
432
+
433
+ console.log(`Forwarded batch command to device ${targetDeviceId}`);
434
+ }
435
+
436
+ // 聚合批量命令的进度更新
437
+ private aggregateBatchProgress(updates: ProgressUpdate[]): any {
438
+ const total = updates.length;
439
+ const successful = updates.filter(u => u.status === 'COMPLETED').length;
440
+ const failed = updates.filter(u => u.status === 'FAILED').length;
441
+ const inProgress = updates.filter(u => u.status === 'IN_PROGRESS').length;
442
+
443
+ return {
444
+ total,
445
+ successful,
446
+ failed,
447
+ inProgress,
448
+ progress: (successful + failed) / total * 100
449
+ };
450
+ }
451
+ }
452
+ ```
453
+
454
+ ### 6. 配置和启动
455
+
456
+ ```typescript
457
+ // config.ts
458
+ export interface EdgeConfig {
459
+ edgeId: string;
460
+ gatewayUrl: string;
461
+ devicePort: number;
462
+ maxDevices: number;
463
+ heartbeatInterval: number;
464
+ logLevel: 'debug' | 'info' | 'warn' | 'error';
465
+ }
466
+
467
+ // index.ts
468
+ import { EdgeServer } from './edge-server';
469
+ import { EdgeConfig } from './config';
470
+
471
+ const config: EdgeConfig = {
472
+ edgeId: process.env.EDGE_ID || 'edge-001',
473
+ gatewayUrl: process.env.GATEWAY_URL || 'ws://localhost:18081',
474
+ devicePort: parseInt(process.env.DEVICE_PORT || '18090'),
475
+ maxDevices: 100,
476
+ heartbeatInterval: 30000,
477
+ logLevel: 'info'
478
+ };
479
+
480
+ // 启动 Edge 服务
481
+ const edge = new EdgeServer(config.edgeId, config.gatewayUrl, config.devicePort);
482
+
483
+ // 健康检查 HTTP 端点
484
+ import express from 'express';
485
+ const app = express();
486
+
487
+ app.get('/health', (req, res) => {
488
+ res.json(edge.getHealthStatus());
489
+ });
490
+
491
+ app.get('/devices', (req, res) => {
492
+ res.json(edge.getDeviceStatuses());
493
+ });
494
+
495
+ app.listen(18091, () => {
496
+ console.log('Edge HTTP server listening on port 18091');
497
+ });
498
+
499
+ // 优雅关闭
500
+ process.on('SIGTERM', () => {
501
+ console.log('Shutting down Edge server...');
502
+ edge.shutdown();
503
+ process.exit(0);
504
+ });
505
+ ```
506
+
507
+ ## 部署建议
508
+
509
+ ### 1. Docker 部署
510
+
511
+ ```dockerfile
512
+ FROM node:18-alpine
513
+
514
+ WORKDIR /app
515
+
516
+ COPY package*.json ./
517
+ RUN npm ci --only=production
518
+
519
+ COPY . .
520
+
521
+ EXPOSE 18090 18091
522
+
523
+ CMD ["node", "dist/index.js"]
524
+ ```
525
+
526
+ ### 2. 环境变量
527
+
528
+ ```bash
529
+ # .env
530
+ EDGE_ID=edge-001
531
+ GATEWAY_URL=ws://gateway:18081
532
+ DEVICE_PORT=18090
533
+ LOG_LEVEL=info
534
+ NODE_ENV=production
535
+ ```
536
+
537
+ ### 3. 监控和日志
538
+
539
+ ```typescript
540
+ import winston from 'winston';
541
+
542
+ const logger = winston.createLogger({
543
+ level: config.logLevel,
544
+ format: winston.format.combine(
545
+ winston.format.timestamp(),
546
+ winston.format.json()
547
+ ),
548
+ transports: [
549
+ new winston.transports.File({ filename: 'edge.log' }),
550
+ new winston.transports.Console()
551
+ ]
552
+ });
553
+
554
+ // 使用结构化日志
555
+ logger.info('Device connected', {
556
+ deviceId: device.id,
557
+ edgeId: this.edgeId,
558
+ timestamp: new Date().toISOString()
559
+ });
560
+ ```
561
+
562
+ ## 高可用设计
563
+
564
+ ### 1. 自动重连
565
+
566
+ ```typescript
567
+ class ReconnectManager {
568
+ private reconnectDelay = 5000;
569
+ private maxReconnectDelay = 60000;
570
+ private reconnectAttempts = 0;
571
+
572
+ async reconnectToGateway(): Promise<void> {
573
+ const delay = Math.min(
574
+ this.reconnectDelay * Math.pow(2, this.reconnectAttempts),
575
+ this.maxReconnectDelay
576
+ );
577
+
578
+ this.reconnectAttempts++;
579
+
580
+ await new Promise(resolve => setTimeout(resolve, delay));
581
+
582
+ try {
583
+ await this.connectToGateway();
584
+ this.reconnectAttempts = 0;
585
+ } catch (error) {
586
+ console.error('Reconnection failed:', error);
587
+ this.reconnectToGateway();
588
+ }
589
+ }
590
+ }
591
+ ```
592
+
593
+ ### 2. 消息缓存
594
+
595
+ ```typescript
596
+ class MessageBuffer {
597
+ private buffer: any[] = [];
598
+ private maxSize = 1000;
599
+
600
+ add(message: any): void {
601
+ if (this.buffer.length >= this.maxSize) {
602
+ this.buffer.shift(); // 移除最旧的消息
603
+ }
604
+ this.buffer.push(message);
605
+ }
606
+
607
+ flush(): any[] {
608
+ const messages = [...this.buffer];
609
+ this.buffer = [];
610
+ return messages;
611
+ }
612
+ }
613
+ ```
614
+
615
+ ## 性能优化
616
+
617
+ ### 1. 连接池
618
+
619
+ ```typescript
620
+ class ConnectionPool {
621
+ private pool: WebSocket[] = [];
622
+ private maxConnections = 5;
623
+
624
+ async getConnection(): Promise<WebSocket> {
625
+ // 实现连接池逻辑
626
+ }
627
+ }
628
+ ```
629
+
630
+ ### 2. 消息批处理
631
+
632
+ ```typescript
633
+ class MessageBatcher {
634
+ private batch: any[] = [];
635
+ private batchSize = 100;
636
+ private batchInterval = 100; // ms
637
+
638
+ add(message: any): void {
639
+ this.batch.push(message);
640
+
641
+ if (this.batch.length >= this.batchSize) {
642
+ this.flush();
643
+ }
644
+ }
645
+
646
+ private flush(): void {
647
+ if (this.batch.length > 0) {
648
+ this.sendBatch(this.batch);
649
+ this.batch = [];
650
+ }
651
+ }
652
+ }
653
+ ```
654
+
655
+ ## 故障排查
656
+
657
+ ### 常见问题
658
+
659
+ 1. **设备连接不上**
660
+ - 检查防火墙设置
661
+ - 验证设备端口是否正确
662
+ - 查看 Edge 日志
663
+
664
+ 2. **消息转发失败**
665
+ - 确认设备已注册
666
+ - 检查消息格式
667
+ - 验证 Gateway 连接状态
668
+
669
+ 3. **性能问题**
670
+ - 监控设备数量
671
+ - 检查消息队列长度
672
+ - 优化消息处理逻辑
673
+
674
+ ## 总结
675
+
676
+ Edge 节点实现的关键点:
677
+
678
+ 1. **双向代理** - 正确处理 Gateway 和设备之间的消息转发
679
+ 2. **连接管理** - 可靠的连接维护和自动重连
680
+ 3. **状态跟踪** - 准确的设备状态管理
681
+ 4. **性能优化** - 批处理、连接池等优化手段
682
+ 5. **高可用性** - 容错、缓存、重试机制
683
+
684
+ 遵循这些指南,可以构建一个稳定、高效的 Edge 代理服务。