@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,332 @@
1
+ # Simple 命令执行流程详解
2
+
3
+ ## 概述
4
+
5
+ Simple 类型命令是 JRSoft Subway 协议中最基本的命令类型,遵循"一次请求,一次响应"的模式。
6
+
7
+ ## 执行流程
8
+
9
+ ### 标准执行流程
10
+
11
+ 所有设备都通过 Edge 接入系统,Gateway 负责路由到正确的 Edge:
12
+
13
+ ```
14
+ ┌─────────┐ ┌─────────┐ ┌──────┐ ┌────────┐
15
+ │ Backend │ │ Gateway │ │ Edge │ │ Device │
16
+ └────┬────┘ └────┬────┘ └───┬──┘ └────┬───┘
17
+ │ │ │ │
18
+ │ 1. command │ │ │
19
+ │ (edge01:td01)│ │ │
20
+ ├─────────────►│ │ │
21
+ │ │ │ │
22
+ │ │ 2. route to │ │
23
+ │ │ edge01 │ │
24
+ │ ├─────────────►│ │
25
+ │ │ │ │
26
+ │ │ │ 3. forward │
27
+ │ │ │ to td01 │
28
+ │ │ ├───────────►│
29
+ │ │ │ │
30
+ │ │ │ │ 4. execute
31
+ │ │ │ ├─┐
32
+ │ │ │ │ │
33
+ │ │ │ │◄┘
34
+ │ │ │ │
35
+ │ │ │ 5. response│
36
+ │ │ │◄───────────┤
37
+ │ │ │ │
38
+ │ │ 6. response │ │
39
+ │ │◄─────────────┤ │
40
+ │ │ │ │
41
+ │ 7. response │ │ │
42
+ │◄─────────────┤ │ │
43
+ │ │ │ │
44
+ ```
45
+
46
+ ## 关键组件职责
47
+
48
+ ### Backend
49
+ - 发起命令请求
50
+ - 指定目标设备(targetClientId = deviceId)
51
+ - 设置超时和优先级
52
+ - 处理命令响应
53
+
54
+ ### Gateway(中央路由器)
55
+ - **路由查找**:根据设备ID查找对应的Edge节点
56
+ - **连接管理**:维护与多个 Edge 的WebSocket连接
57
+ - **超时控制**:监控命令执行超时
58
+ - **响应路由**:根据 requestRef 将响应路由回发起方
59
+ - **回调处理**:如配置了 callback URL,推送响应
60
+ - **负载均衡**:可选,在多个 Edge 之间分配负载
61
+
62
+ ### Edge(设备接入点)
63
+ - **设备管理**:管理本地多个设备的连接
64
+ - **本地路由**:根据 targetClientId(设备ID)路由到设备
65
+ - **协议转换**:可选,将WebSocket协议转换为设备协议
66
+ - **状态监控**:监控本地设备健康状态
67
+ - **断线重连**:处理设备的连接恢复
68
+
69
+ ### Device
70
+ - **命令执行**:执行具体的硬件操作
71
+ - **响应生成**:生成执行结果
72
+ - **错误处理**:处理执行异常
73
+ - **状态上报**:定期向 Edge 汇报状态
74
+
75
+ ## 消息格式
76
+
77
+ ### 命令请求
78
+ ```json
79
+ {
80
+ "type": "COMMAND",
81
+ "requestRef": "cmd-${timestamp}-${random}", // 唯一标识
82
+ "targetClientId": "td-01", // 设备ID
83
+ "command": {
84
+ "commandType": "SIMPLE",
85
+ "commandCode": "SET_COLOR",
86
+ "deviceType": "pillar",
87
+ "deviceId": 1,
88
+ "operationType": "WRITE",
89
+ "parameters": {
90
+ "color": "#FF0000"
91
+ }
92
+ },
93
+ "priority": "NORMAL", // low, normal, high, critical
94
+ "timeout": 10000, // 毫秒
95
+ "callback": "http://backend/api/callback/cmd-123", // 可选
96
+ "timestamp": "2024-01-20T10:00:00Z",
97
+ "version": "1.0"
98
+ }
99
+ ```
100
+
101
+ ### 命令响应
102
+ ```json
103
+ {
104
+ "type": "COMMAND_RESPONSE",
105
+ "requestRef": "cmd-${timestamp}-${random}", // 与请求相同
106
+ "status": "COMPLETED", // 执行状态
107
+ "result": {
108
+ "deviceType": "pillar",
109
+ "deviceId": 1,
110
+ "commandCode": "SET_COLOR",
111
+ "operationType": "WRITE",
112
+ "data": {
113
+ // 成功时返回执行结果
114
+ "previousColor": "#00FF00",
115
+ "currentColor": "#FF0000"
116
+ }
117
+ },
118
+ "executionTime": 150, // 执行耗时(毫秒)
119
+ "timestamp": "2024-01-20T10:00:00.150Z",
120
+ "version": "1.0"
121
+ }
122
+ ```
123
+
124
+ ## targetClientId 格式
125
+
126
+ ```
127
+ 格式: 直接使用设备ID
128
+ 示例:
129
+ - "td-01" - 设备ID,Gateway自动查找对应的Edge
130
+ - "screen-05" - 5号屏幕设备
131
+ - "pillar-123" - 123号光柱设备
132
+ ```
133
+
134
+ **路由流程:**
135
+ 1. Gateway 收到 targetClientId = "td-01",查找路由表
136
+ 2. Gateway 发现 td-01 在 edge-001 节点下
137
+ 3. Gateway 将命令路由到 edge-001
138
+ 4. Edge 收到命令,targetClientId 就是设备ID
139
+ 5. Edge 将命令转发到设备 td-01
140
+
141
+ ## 超时处理
142
+
143
+ 1. **Backend设置超时**:在命令中指定 timeout 字段
144
+ 2. **Gateway监控超时**:
145
+ ```javascript
146
+ setTimeout(() => {
147
+ if (!hasResponse) {
148
+ sendTimeoutResponse(requestRef);
149
+ }
150
+ }, command.timeout);
151
+ ```
152
+ 3. **超时响应**:
153
+ ```json
154
+ {
155
+ "type": "COMMAND_RESPONSE",
156
+ "requestRef": "cmd-123",
157
+ "status": "TIMEOUT",
158
+ "log": {
159
+ "level": "ERROR",
160
+ "message": "Command execution timeout",
161
+ "code": "COMMAND_TIMEOUT",
162
+ "data": {
163
+ "timeout": 10000,
164
+ "elapsed": 10500
165
+ }
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## 错误处理
171
+
172
+ ### Edge 不存在
173
+ ```json
174
+ {
175
+ "type": "ERROR",
176
+ "requestRef": "cmd-123",
177
+ "code": "EDGE_NOT_FOUND",
178
+ "message": "Target edge edge-999 not found",
179
+ "details": {
180
+ "targetClientId": "td-01",
181
+ "requestedEdge": "edge-999",
182
+ "availableEdges": ["edge-001", "edge-002"]
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### 设备离线
188
+ ```json
189
+ {
190
+ "type": "COMMAND_RESPONSE",
191
+ "requestRef": "cmd-123",
192
+ "status": "FAILED",
193
+ "log": {
194
+ "level": "ERROR",
195
+ "message": "Device td-01 is offline at edge-001",
196
+ "code": "DEVICE_OFFLINE",
197
+ "data": {
198
+ "edgeId": "edge-001",
199
+ "deviceId": "td-01",
200
+ "lastSeen": "2024-01-20T09:55:00Z"
201
+ }
202
+ }
203
+ }
204
+ ```
205
+
206
+ ### 执行失败
207
+ ```json
208
+ {
209
+ "type": "COMMAND_RESPONSE",
210
+ "requestRef": "cmd-123",
211
+ "status": "FAILED",
212
+ "result": {
213
+ "deviceType": "pillar",
214
+ "deviceId": 1,
215
+ "commandCode": "SET_COLOR",
216
+ "operationType": "WRITE",
217
+ "data": {
218
+ "Uerror": "Hardware malfunction",
219
+ "errorCode": "HW_ERROR_001"
220
+ }
221
+ }
222
+ }
223
+ ```
224
+
225
+ ## 最佳实践
226
+
227
+ ### 1. RequestRef 生成
228
+ ```javascript
229
+ function generateRequestRef(prefix = 'cmd') {
230
+ const timestamp = Date.now();
231
+ const random = Math.random().toString(36).substr(2, 9);
232
+ return `${prefix}-${timestamp}-${random}`;
233
+ }
234
+ ```
235
+
236
+ ### 2. 超时设置建议
237
+ - 读操作:5-10秒
238
+ - 写操作:10-30秒
239
+ - 复杂操作:30-60秒
240
+
241
+ ### 3. 错误重试
242
+ ```javascript
243
+ async function executeWithRetry(command, maxRetries = 3) {
244
+ for (let i = 0; i < maxRetries; i++) {
245
+ try {
246
+ const response = await sendCommand(command);
247
+ if (response.status === 'completed') {
248
+ return response;
249
+ }
250
+
251
+ // 仅在特定错误时重试
252
+ if (!isRetryableError(response)) {
253
+ return response;
254
+ }
255
+ } catch (error) {
256
+ if (i === maxRetries - 1) throw error;
257
+ }
258
+
259
+ // 指数退避
260
+ await sleep(Math.pow(2, i) * 1000);
261
+ }
262
+ }
263
+ ```
264
+
265
+ ### 4. 设备端实现
266
+ ```javascript
267
+ class DeviceHandler {
268
+ async handleCommand(message) {
269
+ // 只处理 simple 命令
270
+ if (message.command.commandType !== 'simple') {
271
+ throw new Error('Device only supports simple commands');
272
+ }
273
+
274
+ try {
275
+ // 执行命令
276
+ const result = await this.executeCommand(message.command);
277
+
278
+ // 返回成功响应
279
+ return {
280
+ type: 'command_response',
281
+ requestRef: message.requestRef,
282
+ status: 'completed',
283
+ result: {
284
+ deviceType: message.command.deviceType,
285
+ deviceId: message.command.deviceId,
286
+ commandCode: message.command.commandCode,
287
+ operationType: message.command.operationType,
288
+ data: result
289
+ },
290
+ executionTime: Date.now() - startTime,
291
+ timestamp: new Date().toISOString(),
292
+ version: '1.0'
293
+ };
294
+ } catch (error) {
295
+ // 返回错误响应
296
+ return {
297
+ type: 'command_response',
298
+ requestRef: message.requestRef,
299
+ status: 'failed',
300
+ result: {
301
+ deviceType: message.command.deviceType,
302
+ deviceId: message.command.deviceId,
303
+ commandCode: message.command.commandCode,
304
+ operationType: message.command.operationType,
305
+ data: {
306
+ error: error.message,
307
+ errorCode: error.code
308
+ }
309
+ },
310
+ log: {
311
+ level: 'error',
312
+ message: error.message,
313
+ code: error.code
314
+ },
315
+ timestamp: new Date().toISOString(),
316
+ version: '1.0'
317
+ };
318
+ }
319
+ }
320
+ }
321
+ ```
322
+
323
+ ## 总结
324
+
325
+ Simple 命令是整个协议的基础,具有以下特点:
326
+
327
+ 1. **简单直接**:一次请求,一次响应
328
+ 2. **路由透明**:Backend无需知道Edge拓扑,Gateway自动路由
329
+ 3. **错误处理完善**:超时、离线、执行失败都有明确处理
330
+ 4. **扩展性好**:通过 parameters 支持各种命令参数
331
+
332
+ 其他命令类型(Batch、Complex)最终都会分解为 Simple 命令执行,这保证了设备端实现的简单性。
@@ -0,0 +1,362 @@
1
+ # 强类型命令系统
2
+
3
+ ## 概述
4
+
5
+ 强类型命令系统通过从 C# 模型自动生成 TypeScript 类型定义,实现端到端的类型安全。该系统提供编译时类型检查、智能提示和运行时验证,同时保持向后兼容性。
6
+
7
+ ## 架构设计
8
+
9
+ ### 分层架构
10
+
11
+ ```
12
+ C# 模型定义 → TypeScript 类型生成 → WebSocket 协议集成
13
+ ```
14
+
15
+ - **C# 模型层**:定义命令的业务逻辑和数据结构
16
+ - **类型生成层**:自动将 C# 类型转换为 TypeScript 定义
17
+ - **协议集成层**:将强类型集成到 WebSocket 协议中
18
+
19
+ ### 核心组件
20
+
21
+ 1. **命令类型定义** (`command-types.ts`)
22
+ - 所有强类型命令的 TypeScript 接口
23
+ - 命令代码到类型的映射
24
+ - 类型守卫函数
25
+
26
+ 2. **命令工厂** (`command-factory.ts`)
27
+ - 类型安全的命令创建函数
28
+ - 参数验证和默认值处理
29
+ - 通用工厂方法
30
+
31
+ 3. **类型验证器** (`CommandTypeValidator`)
32
+ - 运行时类型验证
33
+ - 详细的错误报告
34
+ - 可扩展的验证规则
35
+
36
+ ## 使用方法
37
+
38
+ ### 1. 基础使用
39
+
40
+ ```typescript
41
+ import {
42
+ createLedSwitchCommand,
43
+ createBlockPlayCommand,
44
+ Priority
45
+ } from '@jrsoft/subway-protocol';
46
+
47
+ // 创建 LED 开关命令
48
+ const ledCommand = createLedSwitchCommand(
49
+ 'led-req-001', // requestRef
50
+ 'td-01', // targetClientId (设备ID)
51
+ 15, // deviceId (子硬件ID)
52
+ 'ON', // switch state
53
+ 'write', // operation type
54
+ {
55
+ priority: Priority.HIGH,
56
+ timeout: 5000,
57
+ callback: 'http://backend/api/callback'
58
+ }
59
+ );
60
+
61
+ // 创建区块播放命令
62
+ const playCommand = createBlockPlayCommand(
63
+ 'play-req-002',
64
+ 'td-01', // targetClientId (设备ID)
65
+ 15, // deviceId (子硬件ID)
66
+ 3, // blockNumber
67
+ 'loop', // playMode
68
+ 'write',
69
+ { priority: Priority.NORMAL }
70
+ );
71
+ ```
72
+
73
+ ### 2. 类型安全的优势
74
+
75
+ ```typescript
76
+ // ✅ 强类型:编译时类型检查
77
+ const command = createLedSwitchCommand(
78
+ 'req-123',
79
+ 'td-01',
80
+ 42,
81
+ 'ON' // 只能是 'ON' | 'OFF'
82
+ );
83
+
84
+ // ❌ 编译错误:类型不匹配
85
+ const badCommand = createLedSwitchCommand(
86
+ 'req-123',
87
+ 'td-01',
88
+ 42,
89
+ 'INVALID' // Error: Argument of type '"INVALID"' is not assignable
90
+ );
91
+
92
+ // IDE 智能提示
93
+ command.parameters.switch // 自动提示: 'ON' | 'OFF'
94
+ command.deviceType // 自动提示: 'pillar'
95
+ command.operationType // 自动提示: 'read' | 'write'
96
+ ```
97
+
98
+ ### 3. 运行时验证
99
+
100
+ ```typescript
101
+ import { CommandTypeValidator } from '@jrsoft/subway-protocol';
102
+
103
+ // 验证命令
104
+ const validation = CommandTypeValidator.validateCommand(command);
105
+ if (!validation.valid) {
106
+ console.error('Command validation failed:', validation.errors);
107
+ }
108
+
109
+ // 验证特定命令类型
110
+ if (CommandTypeValidator.isLedSwitchCommand(command)) {
111
+ // TypeScript 知道这是 LedSwitchCommand
112
+ console.log(command.parameters.switch); // 'ON' | 'OFF'
113
+ }
114
+ ```
115
+
116
+ ### 4. 批量命令支持
117
+
118
+ ```typescript
119
+ import { createBatchCommand } from '@jrsoft/subway-protocol';
120
+
121
+ // 创建批量 LED 控制命令
122
+ const batchLedCommand = createBatchCommand(
123
+ 'batch-req-001',
124
+ {
125
+ commandCode: 'LedSwitch',
126
+ deviceType: 'pillar',
127
+ operationType: 'write',
128
+ parameters: {
129
+ switch: 'ON',
130
+ targets: '1-10,30-40', // 批量目标
131
+ batch: true
132
+ }
133
+ },
134
+ {
135
+ priority: Priority.HIGH,
136
+ timeout: 30000
137
+ }
138
+ );
139
+ ```
140
+
141
+ ### 5. 泛型工厂方法
142
+
143
+ ```typescript
144
+ import {
145
+ TypedCommandFactory,
146
+ CommandTypeMap
147
+ } from '@jrsoft/subway-protocol';
148
+
149
+ // 使用泛型工厂创建任意类型的命令
150
+ const typedCommand = TypedCommandFactory.createTypedCommandMessage(
151
+ 'generic-req-003',
152
+ 'device-01',
153
+ 'BlockPlay', // 命令代码作为类型参数
154
+ {
155
+ blockNumber: 5,
156
+ playMode: 'sequence'
157
+ },
158
+ { priority: Priority.LOW }
159
+ );
160
+
161
+ // TypeScript 自动推断返回类型为 CommandMessage<BlockPlayCommand>
162
+ ```
163
+
164
+ ## 支持的命令类型
165
+
166
+ 此处省略
167
+
168
+ 完整的命令列表请参考 [API 文档](../06-reference/api.md)。
169
+
170
+ ## 与通用命令的互操作
171
+
172
+ ### 向后兼容
173
+
174
+ ```typescript
175
+ // 强类型命令仍然是标准的 Command
176
+ export type Command = SpecificCommand | GenericCommand;
177
+
178
+ // 可以混合使用
179
+ const commands: Command[] = [
180
+ createLedSwitchCommand(...), // 强类型
181
+ { // 通用类型
182
+ commandCode: 'CUSTOM_COMMAND',
183
+ deviceType: 'custom',
184
+ operationType: 'write',
185
+ parameters: { customParam: 'value' }
186
+ }
187
+ ];
188
+ ```
189
+
190
+ ### 类型转换
191
+
192
+ ```typescript
193
+ import { CommandTypeConverter } from '@jrsoft/subway-protocol';
194
+
195
+ // 将通用命令转换为强类型(如果可能)
196
+ const genericCommand = {
197
+ commandCode: 'LedSwitch',
198
+ parameters: { switch: 'ON' }
199
+ };
200
+
201
+ const specificCommand = CommandTypeConverter.toSpecificCommand(genericCommand);
202
+ if (specificCommand && CommandTypeValidator.isLedSwitchCommand(specificCommand)) {
203
+ // 现在有完整的类型信息
204
+ }
205
+ ```
206
+
207
+ ## 最佳实践
208
+
209
+ ### 1. 优先使用强类型
210
+
211
+ ```typescript
212
+ // ✅ 推荐:使用强类型命令工厂
213
+ const command = createLedSwitchCommand(...);
214
+
215
+ // ❌ 避免:手动构造命令对象
216
+ const command = {
217
+ commandCode: 'LedSwitch',
218
+ parameters: { switch: 'ON' }
219
+ };
220
+ ```
221
+
222
+ ### 2. 统一错误处理
223
+
224
+ ```typescript
225
+ try {
226
+ const command = createLedSwitchCommand(...);
227
+ const validation = CommandTypeValidator.validateCommand(command);
228
+
229
+ if (!validation.valid) {
230
+ throw new Error(`Invalid command: ${validation.errors.join(', ')}`);
231
+ }
232
+
233
+ // 发送命令
234
+ } catch (error) {
235
+ console.error('Command creation failed:', error);
236
+ }
237
+ ```
238
+
239
+ ### 3. 类型守卫的使用
240
+
241
+ ```typescript
242
+ function handleCommand(command: Command) {
243
+ if (CommandTypeValidator.isLedSwitchCommand(command)) {
244
+ // 处理 LED 开关命令
245
+ console.log(`Switching LED to ${command.parameters.switch}`);
246
+ } else if (CommandTypeValidator.isBlockPlayCommand(command)) {
247
+ // 处理区块播放命令
248
+ console.log(`Playing block ${command.parameters.blockNumber}`);
249
+ } else {
250
+ // 处理通用命令
251
+ console.log(`Generic command: ${command.commandCode}`);
252
+ }
253
+ }
254
+ ```
255
+
256
+ ### 4. 扩展自定义命令
257
+
258
+ ```typescript
259
+ // 定义自定义命令接口
260
+ interface CustomCommand extends BaseSpecificCommand {
261
+ commandCode: 'CustomCommand';
262
+ parameters: {
263
+ customField: string;
264
+ customValue: number;
265
+ };
266
+ }
267
+
268
+ // 添加到命令映射
269
+ declare module '@jrsoft/subway-protocol' {
270
+ interface CommandTypeMap {
271
+ CustomCommand: CustomCommand;
272
+ }
273
+ }
274
+
275
+ // 创建自定义工厂函数
276
+ export function createCustomCommand(
277
+ requestRef: string,
278
+ targetClientId: string,
279
+ customField: string,
280
+ customValue: number,
281
+ options?: CommandOptions
282
+ ): CommandMessage<CustomCommand> {
283
+ return TypedCommandFactory.createTypedCommandMessage(
284
+ requestRef,
285
+ targetClientId,
286
+ 'CustomCommand',
287
+ { customField, customValue },
288
+ options
289
+ );
290
+ }
291
+ ```
292
+
293
+ ## 工具支持
294
+
295
+ ### TypeScript 配置
296
+
297
+ ```json
298
+ {
299
+ "compilerOptions": {
300
+ "strict": true,
301
+ "strictNullChecks": true,
302
+ "noImplicitAny": true
303
+ }
304
+ }
305
+ ```
306
+
307
+ ### ESLint 规则
308
+
309
+ ```json
310
+ {
311
+ "rules": {
312
+ "@typescript-eslint/no-explicit-any": "Uerror",
313
+ "@typescript-eslint/explicit-function-return-type": "warn"
314
+ }
315
+ }
316
+ ```
317
+
318
+ ## 迁移指南
319
+
320
+ ### 从通用命令迁移到强类型
321
+
322
+ 1. **识别使用的命令代码**
323
+ ```typescript
324
+ // 旧代码
325
+ const command = {
326
+ commandCode: 'LedSwitch',
327
+ parameters: { switch: 'ON' }
328
+ };
329
+ ```
330
+
331
+ 2. **使用对应的工厂函数**
332
+ ```typescript
333
+ // 新代码
334
+ const command = createLedSwitchCommand(
335
+ requestRef,
336
+ targetClientId,
337
+ deviceId,
338
+ 'ON',
339
+ 'write'
340
+ );
341
+ ```
342
+
343
+ 3. **更新类型注解**
344
+ ```typescript
345
+ // 旧代码
346
+ function handleCommand(command: any) { }
347
+
348
+ // 新代码
349
+ function handleCommand(command: LedSwitchCommand) { }
350
+ ```
351
+
352
+ ## 总结
353
+
354
+ 强类型命令系统提供了:
355
+
356
+ 1. **编译时安全** - 在开发阶段捕获类型错误
357
+ 2. **更好的开发体验** - IDE 智能提示和自动补全
358
+ 3. **运行时验证** - 确保数据完整性
359
+ 4. **向后兼容** - 可以渐进式迁移
360
+ 5. **可扩展性** - 轻松添加新的命令类型
361
+
362
+ 这种设计既保证了类型安全,又保持了系统的灵活性,是现代 TypeScript 应用的最佳实践。