@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.
- package/ACK_MESSAGES_IMPLEMENTATION_SUMMARY.md +128 -0
- package/ACK_MESSAGE_DESIGN.md +457 -0
- package/CHANGELOG.md +58 -0
- package/COMMAND_VALIDATION_RULES.md +178 -0
- package/DOCUMENTATION_REORGANIZATION_SUMMARY.md +81 -0
- package/DOCUMENTATION_STRUCTURE.md +106 -0
- package/GATEWAY_MIGRATION_GUIDE.md +130 -0
- package/GATEWAY_PROTOCOL_COMPARISON.md +216 -0
- package/INTEGRATION_GUIDE.md +190 -0
- package/OPTIONAL_FIELDS_WITHOUT_DEFAULTS.md +97 -0
- package/PROTOCOL_UTILS_USAGE.md +278 -0
- package/README.md +237 -0
- package/TYPE_FIXES_SUMMARY.md +210 -0
- package/UPDATE_ENUM_VALUES.md +139 -0
- package/dist/asyncapi-sync.d.ts +47 -0
- package/dist/asyncapi-sync.d.ts.map +1 -0
- package/dist/asyncapi-sync.js +85 -0
- package/dist/asyncapi-sync.js.map +1 -0
- package/dist/command-factory.d.ts +62 -0
- package/dist/command-factory.d.ts.map +1 -0
- package/dist/command-factory.js +137 -0
- package/dist/command-factory.js.map +1 -0
- package/dist/command-types.d.ts +27 -0
- package/dist/command-types.d.ts.map +1 -0
- package/dist/command-types.js +31 -0
- package/dist/command-types.js.map +1 -0
- package/dist/index.d.ts +403 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +413 -0
- package/dist/index.js.map +1 -0
- package/dist/message-validator.d.ts +102 -0
- package/dist/message-validator.d.ts.map +1 -0
- package/dist/message-validator.js +640 -0
- package/dist/message-validator.js.map +1 -0
- package/dist/protocol-utils.d.ts +108 -0
- package/dist/protocol-utils.d.ts.map +1 -0
- package/dist/protocol-utils.js +293 -0
- package/dist/protocol-utils.js.map +1 -0
- package/docs/01-protocol/README.md +45 -0
- package/docs/01-protocol/design-rationale.md +198 -0
- package/docs/01-protocol/message-types.md +669 -0
- package/docs/01-protocol/specification.md +1466 -0
- package/docs/02-commands/README.md +56 -0
- package/docs/02-commands/batch-command.md +435 -0
- package/docs/02-commands/complex-command.md +537 -0
- package/docs/02-commands/simple-command.md +332 -0
- package/docs/02-commands/typed-commands.md +362 -0
- package/docs/03-architecture/README.md +66 -0
- package/docs/03-architecture/device-protocol.md +430 -0
- package/docs/03-architecture/edge-proxy.md +727 -0
- package/docs/03-architecture/routing-flow.md +893 -0
- package/docs/04-integration/README.md +144 -0
- package/docs/04-integration/backend-guide.md +551 -0
- package/docs/04-integration/edge-guide.md +684 -0
- package/docs/04-integration/gateway-guide.md +180 -0
- package/docs/04-integration/migration-guide.md +226 -0
- package/docs/05-examples/README.md +141 -0
- package/docs/05-examples/progress-update-examples.md +757 -0
- package/docs/06-reference/README.md +67 -0
- package/docs/06-reference/api.md +572 -0
- package/docs/06-reference/faq.md +302 -0
- package/docs/06-reference/glossary.md +232 -0
- package/examples/backend-upgrade.ts +279 -0
- package/examples/edge-multi-device.ts +513 -0
- package/examples/gateway-upgrade.ts +150 -0
- package/examples/protocol-implementation.ts +715 -0
- package/package.json +48 -0
- package/scripts/validate-asyncapi.ts +78 -0
- package/src/__tests__/protocol.test.ts +297 -0
- package/src/asyncapi-sync.ts +84 -0
- package/src/command-factory.ts +183 -0
- package/src/command-types.ts +72 -0
- package/src/edge-proxy.ts +494 -0
- package/src/gateway-extensions.ts +278 -0
- package/src/index.ts +792 -0
- package/src/message-validator.ts +726 -0
- package/src/protocol-utils.ts +355 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# 命令系统文档
|
|
2
|
+
|
|
3
|
+
本目录包含 JRSoft Subway 协议的命令系统相关文档。
|
|
4
|
+
|
|
5
|
+
## 📚 文档列表
|
|
6
|
+
|
|
7
|
+
### [Simple 命令](./simple-command.md)
|
|
8
|
+
点对点的简单命令:
|
|
9
|
+
- 快速执行的单一操作
|
|
10
|
+
- 一次请求,一次响应
|
|
11
|
+
- 适用于开关控制、参数读写等
|
|
12
|
+
- 完整的路由流程和错误处理
|
|
13
|
+
|
|
14
|
+
### [Batch 命令](./batch-command.md)
|
|
15
|
+
批量控制命令:
|
|
16
|
+
- 向同一设备的多个子硬件发送相同命令
|
|
17
|
+
- 通过 progress_update 报告进度
|
|
18
|
+
- 支持范围语法(如 "1-10,30-40")
|
|
19
|
+
- 适用于批量设置光柱颜色、屏幕内容等
|
|
20
|
+
|
|
21
|
+
### [Complex 命令](./complex-command.md)
|
|
22
|
+
复杂交互命令:
|
|
23
|
+
- 支持多次响应的长时间运行命令
|
|
24
|
+
- 通过 progress_update 持续反馈
|
|
25
|
+
- 适用于健康检查、数据导出、日志收集等
|
|
26
|
+
- 设备端可自主控制响应节奏
|
|
27
|
+
|
|
28
|
+
### [强类型命令](./typed-commands.md)
|
|
29
|
+
基于 C# 模型的类型安全命令:
|
|
30
|
+
- 从 C# 模型自动生成 TypeScript 类型
|
|
31
|
+
- 编译时类型检查
|
|
32
|
+
- IntelliSense 支持
|
|
33
|
+
- 运行时验证
|
|
34
|
+
|
|
35
|
+
## 🎯 命令类型对比
|
|
36
|
+
|
|
37
|
+
| 特性 | Simple | Batch | Complex |
|
|
38
|
+
|------|--------|-------|---------|
|
|
39
|
+
| 响应次数 | 1次 | 多次(进度+结果) | 多次(进度+结果) |
|
|
40
|
+
| 执行时间 | 短(秒级) | 中等(分钟级) | 长(分钟到小时) |
|
|
41
|
+
| 适用场景 | 单一操作 | 批量操作 | 复杂任务 |
|
|
42
|
+
| 进度反馈 | 无 | 有 | 有 |
|
|
43
|
+
| 实现复杂度 | 低 | 中 | 中高 |
|
|
44
|
+
|
|
45
|
+
## 🚀 快速选择指南
|
|
46
|
+
|
|
47
|
+
- **需要控制单个设备?** → 使用 [Simple 命令](./simple-command.md)
|
|
48
|
+
- **需要批量控制多个子硬件?** → 使用 [Batch 命令](./batch-command.md)
|
|
49
|
+
- **需要执行长时间任务并获取进度?** → 使用 [Complex 命令](./complex-command.md)
|
|
50
|
+
- **需要类型安全和编译时检查?** → 使用 [强类型命令](./typed-commands.md)
|
|
51
|
+
|
|
52
|
+
## 🔗 相关文档
|
|
53
|
+
|
|
54
|
+
- [协议规范](../01-protocol/) - 了解底层协议
|
|
55
|
+
- [示例代码](../05-examples/) - 查看实际使用示例
|
|
56
|
+
- [API 参考](../06-reference/api.md) - 详细的 API 文档
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
# 批量命令详解
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
批量命令用于控制同一设备内的多个子硬件(如光柱1-480)。为了提供更好的用户体验和实时反馈,批量命令采用与 Complex 命令和程序上传相同的执行模式:通过 progress_update 报告进度,最后返回汇总响应。
|
|
6
|
+
|
|
7
|
+
## 核心理念
|
|
8
|
+
|
|
9
|
+
批量命令是针对同一设备内的多个子硬件(如光柱1-480)执行相同操作。设备端负责解析批量目标并执行,通过 progress_update 报告每个子硬件的执行进度。
|
|
10
|
+
|
|
11
|
+
## 重要限制
|
|
12
|
+
|
|
13
|
+
⚠️ **批量命令仅适用于同一类型的子硬件**:
|
|
14
|
+
- ✅ 可以:向编号1-20的光柱发送相同的颜色设置命令
|
|
15
|
+
- ✅ 可以:向编号1-5的显示屏发送相同的内容更新命令
|
|
16
|
+
- ❌ 不可以:在同一批量命令中混合光柱和显示屏
|
|
17
|
+
- ❌ 不可以:在同一批量命令中混合不同型号的硬件
|
|
18
|
+
|
|
19
|
+
## 执行流程
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Backend Gateway Edge Device
|
|
23
|
+
| | | |
|
|
24
|
+
| Batch Command | | |
|
|
25
|
+
| (targets:"1-10")| | |
|
|
26
|
+
|----------------->| | |
|
|
27
|
+
| | | |
|
|
28
|
+
| | Route to Edge | |
|
|
29
|
+
| |------------------>| |
|
|
30
|
+
| | | |
|
|
31
|
+
| | | Device内部处理 |
|
|
32
|
+
| | |----------------->|
|
|
33
|
+
| | | | 执行子硬件1
|
|
34
|
+
| | | |
|
|
35
|
+
| | | progress_update |
|
|
36
|
+
| | | (子硬件1) |
|
|
37
|
+
| | |<-----------------|
|
|
38
|
+
| | | |
|
|
39
|
+
| | progress_update | |
|
|
40
|
+
| progress_update |<------------------| |
|
|
41
|
+
| (子硬件1完成) | | |
|
|
42
|
+
|<-----------------| | |
|
|
43
|
+
| | | | 执行子硬件2
|
|
44
|
+
| | | |
|
|
45
|
+
| | | progress_update |
|
|
46
|
+
| | | (子硬件2) |
|
|
47
|
+
| | |<-----------------|
|
|
48
|
+
| | | |
|
|
49
|
+
| | progress_update | |
|
|
50
|
+
| progress_update |<------------------| |
|
|
51
|
+
| (子硬件2完成) | | |
|
|
52
|
+
|<-----------------| | |
|
|
53
|
+
| | | |
|
|
54
|
+
| | | ... |
|
|
55
|
+
| | | | 执行子硬件10
|
|
56
|
+
| | | |
|
|
57
|
+
| | | command_response |
|
|
58
|
+
| | | (全部完成) |
|
|
59
|
+
| | |<-----------------|
|
|
60
|
+
| | | |
|
|
61
|
+
| | command_response | |
|
|
62
|
+
| command_response |<------------------| |
|
|
63
|
+
| (summary) | | |
|
|
64
|
+
|<-----------------| | |
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**注意**:批量命令是发送给同一个设备,由该设备内部处理多个子硬件的操作。
|
|
68
|
+
|
|
69
|
+
## 应用场景
|
|
70
|
+
|
|
71
|
+
### 典型硬件布局
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
隧道媒体广告设备端 (TC-01)
|
|
75
|
+
├─ 光柱系统 (1-480编号)
|
|
76
|
+
│ ├─ 光柱 001 ~ 020 (区域A)
|
|
77
|
+
│ ├─ 光柱 021 ~ 040 (区域B)
|
|
78
|
+
│ ├─ 光柱 041 ~ 060 (区域C)
|
|
79
|
+
│ │ ...
|
|
80
|
+
│ └─ 光柱 461 ~ 480 (区域Z)
|
|
81
|
+
├─ 同步器 (1编号)
|
|
82
|
+
├─ 测速器 (1-5编号)
|
|
83
|
+
└─ 通讯板 (1-10编号)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 范围语法
|
|
87
|
+
|
|
88
|
+
批量命令支持灵活的范围语法来指定目标子硬件:
|
|
89
|
+
|
|
90
|
+
### 基本格式
|
|
91
|
+
|
|
92
|
+
- **单个目标**: `"5"` - 仅目标5
|
|
93
|
+
- **连续范围**: `"1-10"` - 目标1到10
|
|
94
|
+
- **离散目标**: `"1,3,5,7"` - 目标1、3、5、7
|
|
95
|
+
- **混合模式**: `"1-10,30-40,51,52,53,54"` - 组合使用
|
|
96
|
+
- **全部目标**: `"0"` - 所有子硬件
|
|
97
|
+
|
|
98
|
+
### 语法示例
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// 范围解析示例
|
|
102
|
+
"1-5" → [1, 2, 3, 4, 5]
|
|
103
|
+
"1,3,5" → [1, 3, 5]
|
|
104
|
+
"1-3,7-9" → [1, 2, 3, 7, 8, 9]
|
|
105
|
+
"1-100,200-300" → [1...100, 200...300]
|
|
106
|
+
"0" → [所有可用设备]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 消息结构
|
|
110
|
+
|
|
111
|
+
### 1. 批量命令请求(Backend → Gateway)
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"type": "COMMAND",
|
|
116
|
+
"requestRef": "batch-123",
|
|
117
|
+
"targetClientId": "td-01", // 设备ID
|
|
118
|
+
"command": {
|
|
119
|
+
"commandType": "BATCH",
|
|
120
|
+
"commandCode": "SET_COLOR",
|
|
121
|
+
"deviceType": "pillar",
|
|
122
|
+
"deviceId": "1-10,30-40", // 批量目标
|
|
123
|
+
"operationType": "WRITE",
|
|
124
|
+
"parameters": {
|
|
125
|
+
"color": "#FF0000"
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"priority": "NORMAL",
|
|
129
|
+
"timeout": 60000
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 2. Edge 转发批量命令到设备(Edge → Device)
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"type": "COMMAND",
|
|
138
|
+
"requestRef": "batch-123",
|
|
139
|
+
"targetClientId": "td-01", // 设备ID
|
|
140
|
+
"command": {
|
|
141
|
+
"commandType": "BATCH",
|
|
142
|
+
"commandCode": "SET_COLOR",
|
|
143
|
+
"deviceType": "pillar",
|
|
144
|
+
"deviceId": "1-10,30-40", // 子硬件范围
|
|
145
|
+
"operationType": "WRITE",
|
|
146
|
+
"parameters": {
|
|
147
|
+
"color": "#FF0000",
|
|
148
|
+
"targets": "1-10,30-40", // 明确的目标列表
|
|
149
|
+
"Ubatch": true
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"priority": "NORMAL",
|
|
153
|
+
"timeout": 60000
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 3. 进度更新(Device → Edge → Gateway → Backend)
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"type": "PROGRESS_UPDATE",
|
|
162
|
+
"requestRef": "batch-123",
|
|
163
|
+
"status": "IN_PROGRESS",
|
|
164
|
+
"phase": "executing",
|
|
165
|
+
"progress": 10, // 1/10 子硬件完成
|
|
166
|
+
"sourceType": "COMMAND",
|
|
167
|
+
"command": {
|
|
168
|
+
"commandType": "SIMPLE",
|
|
169
|
+
"commandCode": "SET_COLOR",
|
|
170
|
+
"deviceType": "pillar",
|
|
171
|
+
"deviceId": 1, // 子硬件ID
|
|
172
|
+
"operationType": "WRITE",
|
|
173
|
+
"result": {
|
|
174
|
+
"previousColor": "#00FF00",
|
|
175
|
+
"currentColor": "#FF0000"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"log": {
|
|
179
|
+
"level": "INFO",
|
|
180
|
+
"message": "光柱 1 颜色设置成功"
|
|
181
|
+
},
|
|
182
|
+
"timestamp": "2024-01-20T10:00:01Z",
|
|
183
|
+
"version": "1.0"
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 4. 最终响应(Device → Edge → Gateway → Backend)
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"type": "COMMAND_RESPONSE",
|
|
192
|
+
"requestRef": "batch-123",
|
|
193
|
+
"status": "COMPLETED",
|
|
194
|
+
"result": {
|
|
195
|
+
"deviceType": "pillar",
|
|
196
|
+
"deviceId": "1-10,30-40",
|
|
197
|
+
"commandCode": "SET_COLOR",
|
|
198
|
+
"operationType": "WRITE",
|
|
199
|
+
"data": {
|
|
200
|
+
"message": "批量设置颜色完成",
|
|
201
|
+
"color": "#FF0000",
|
|
202
|
+
"targetCount": 16,
|
|
203
|
+
"successCount": 15,
|
|
204
|
+
"failureCount": 1
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"summary": {
|
|
208
|
+
"total": 16,
|
|
209
|
+
"successful": 15,
|
|
210
|
+
"Ufailed": 1,
|
|
211
|
+
"failedTargets": [35]
|
|
212
|
+
},
|
|
213
|
+
"executionTime": 5200,
|
|
214
|
+
"timestamp": "2024-01-20T10:00:05Z",
|
|
215
|
+
"version": "1.0"
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 设备端实现指南
|
|
220
|
+
|
|
221
|
+
### 基本实现模式
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
class DeviceHandler {
|
|
225
|
+
async handleBatchCommand(message: CommandMessage) {
|
|
226
|
+
const { command } = message;
|
|
227
|
+
const targets = this.parseTargets(command.parameters.targets);
|
|
228
|
+
let completedCount = 0;
|
|
229
|
+
let successCount = 0;
|
|
230
|
+
let failedTargets = [];
|
|
231
|
+
|
|
232
|
+
// 处理每个子硬件
|
|
233
|
+
for (const targetId of targets) {
|
|
234
|
+
try {
|
|
235
|
+
// 执行子硬件操作
|
|
236
|
+
const result = await this.executeOnSubHardware(targetId, command);
|
|
237
|
+
|
|
238
|
+
completedCount++;
|
|
239
|
+
successCount++;
|
|
240
|
+
|
|
241
|
+
// 发送进度更新
|
|
242
|
+
await this.sendProgressUpdate({
|
|
243
|
+
requestRef: message.requestRef,
|
|
244
|
+
phase: 'executing',
|
|
245
|
+
progress: (completedCount / targets.length) * 100,
|
|
246
|
+
command: {
|
|
247
|
+
commandType: 'simple',
|
|
248
|
+
commandCode: command.commandCode,
|
|
249
|
+
deviceType: command.deviceType,
|
|
250
|
+
deviceId: targetId, // 子硬件ID
|
|
251
|
+
operationType: command.operationType,
|
|
252
|
+
result
|
|
253
|
+
},
|
|
254
|
+
log: {
|
|
255
|
+
level: 'info',
|
|
256
|
+
message: `子硬件 ${targetId} 执行成功`
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
} catch (error) {
|
|
261
|
+
completedCount++;
|
|
262
|
+
failedTargets.push(targetId);
|
|
263
|
+
|
|
264
|
+
// 发送错误进度
|
|
265
|
+
await this.sendProgressUpdate({
|
|
266
|
+
requestRef: message.requestRef,
|
|
267
|
+
phase: 'executing',
|
|
268
|
+
progress: (completedCount / targets.length) * 100,
|
|
269
|
+
command: {
|
|
270
|
+
commandType: 'simple',
|
|
271
|
+
commandCode: command.commandCode,
|
|
272
|
+
deviceType: command.deviceType,
|
|
273
|
+
deviceId: targetId,
|
|
274
|
+
operationType: command.operationType,
|
|
275
|
+
result: { error: error.message }
|
|
276
|
+
},
|
|
277
|
+
log: {
|
|
278
|
+
level: 'error',
|
|
279
|
+
message: `子硬件 ${targetId} 执行失败: ${error.message}`
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 发送最终响应
|
|
286
|
+
return {
|
|
287
|
+
type: 'command_response',
|
|
288
|
+
requestRef: message.requestRef,
|
|
289
|
+
status: 'completed',
|
|
290
|
+
result: {
|
|
291
|
+
deviceType: command.deviceType,
|
|
292
|
+
deviceId: command.deviceId,
|
|
293
|
+
commandCode: command.commandCode,
|
|
294
|
+
operationType: command.operationType,
|
|
295
|
+
data: {
|
|
296
|
+
message: '批量命令执行完成',
|
|
297
|
+
targetCount: targets.length,
|
|
298
|
+
successCount,
|
|
299
|
+
failureCount: failedTargets.length
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
summary: {
|
|
303
|
+
total: targets.length,
|
|
304
|
+
successful: successCount,
|
|
305
|
+
failed: failedTargets.length,
|
|
306
|
+
failedTargets
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private parseTargets(targets: string | number[]): number[] {
|
|
312
|
+
if (Array.isArray(targets)) {
|
|
313
|
+
return targets;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// 解析 "1-10,30-40,51,52" 格式
|
|
317
|
+
const result = [];
|
|
318
|
+
const parts = targets.split(',');
|
|
319
|
+
|
|
320
|
+
for (const part of parts) {
|
|
321
|
+
if (part.includes('-')) {
|
|
322
|
+
const [start, end] = part.split('-').map(Number);
|
|
323
|
+
for (let i = start; i <= end; i++) {
|
|
324
|
+
result.push(i);
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
result.push(Number(part));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 范围解析函数
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
function parseRangeString(rangeStr: string): number[] {
|
|
340
|
+
// 特殊情况:0 或 * 表示全部
|
|
341
|
+
if (rangeStr === '0' || rangeStr === '*') {
|
|
342
|
+
return getAllAvailableTargets();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const targets = new Set<number>();
|
|
346
|
+
const parts = rangeStr.split(',').map(s => s.trim());
|
|
347
|
+
|
|
348
|
+
for (const part of parts) {
|
|
349
|
+
if (part.includes('-')) {
|
|
350
|
+
// 处理范围:1-10
|
|
351
|
+
const [start, end] = part.split('-').map(Number);
|
|
352
|
+
if (!isNaN(start) && !isNaN(end) && start <= end) {
|
|
353
|
+
for (let i = start; i <= end; i++) {
|
|
354
|
+
targets.add(i);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} else {
|
|
358
|
+
// 处理单个数字
|
|
359
|
+
const num = Number(part);
|
|
360
|
+
if (!isNaN(num)) {
|
|
361
|
+
targets.add(num);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return Array.from(targets).sort((a, b) => a - b);
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## 最佳实践
|
|
371
|
+
|
|
372
|
+
### 1. 进度报告策略
|
|
373
|
+
|
|
374
|
+
- **合理的报告频率** - 避免过于频繁的进度更新
|
|
375
|
+
- **关键节点报告** - 在开始、25%、50%、75%、完成时报告
|
|
376
|
+
|
|
377
|
+
### 2. 错误处理
|
|
378
|
+
|
|
379
|
+
- **失败继续** - 单个子硬件失败不应停止整个批量操作
|
|
380
|
+
- **详细记录** - 记录每个失败的子硬件ID和原因
|
|
381
|
+
- **部分成功** - 支持部分成功的场景
|
|
382
|
+
|
|
383
|
+
### 3. 性能优化
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// 并行执行示例
|
|
387
|
+
async function executeBatchParallel(targets: number[], command: Command) {
|
|
388
|
+
const batchSize = 10; // 每批处理10个
|
|
389
|
+
const results = [];
|
|
390
|
+
|
|
391
|
+
for (let i = 0; i < targets.length; i += batchSize) {
|
|
392
|
+
const batch = targets.slice(i, i + batchSize);
|
|
393
|
+
const batchResults = await Promise.all(
|
|
394
|
+
batch.map(target => executeOnSubHardware(target, command))
|
|
395
|
+
);
|
|
396
|
+
results.push(...batchResults);
|
|
397
|
+
|
|
398
|
+
// 报告批次进度
|
|
399
|
+
await reportProgress(((i + batch.length) / targets.length) * 100);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return results;
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### 4. 超时处理
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
// 设置合理的超时时间
|
|
410
|
+
const timeoutMs = Math.max(
|
|
411
|
+
5000, // 最小5秒
|
|
412
|
+
targets.length * 100 // 每个目标100ms
|
|
413
|
+
);
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## 与其他命令类型的对比
|
|
417
|
+
|
|
418
|
+
| 特性 | Simple | Batch | Complex |
|
|
419
|
+
|------|--------|-------|---------|
|
|
420
|
+
| 目标数量 | 单个 | 多个子硬件 | 单个 |
|
|
421
|
+
| 响应次数 | 1次 | 多次(进度+结果) | 多次(进度+结果) |
|
|
422
|
+
| 进度反馈 | 无 | 有 | 有 |
|
|
423
|
+
| 适用场景 | 单一操作 | 批量控制 | 复杂任务 |
|
|
424
|
+
| 超时设置 | 较短 | 中等 | 较长 |
|
|
425
|
+
|
|
426
|
+
## 设计优势
|
|
427
|
+
|
|
428
|
+
1. **统一的执行模式** - 批量命令、Complex 命令、程序上传都使用 progress_update 报告进度
|
|
429
|
+
2. **更好的可观察性** - 实时看到每个子硬件的执行状态
|
|
430
|
+
3. **灵活的执行策略** - 设备可以控制子硬件的执行顺序
|
|
431
|
+
4. **清晰的职责划分** - Gateway 路由、Edge 管理连接、Device 执行操作
|
|
432
|
+
|
|
433
|
+
## 总结
|
|
434
|
+
|
|
435
|
+
批量命令通过引入 progress_update 机制,为批量操作提供了实时的执行反馈。这种设计既保证了协议的灵活性,又维持了实现的简洁性,为用户提供了良好的体验。
|