@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,108 @@
1
+ /**
2
+ * 协议工具类 - 提供状态转换、类型判断和请求引用管理功能
3
+ */
4
+ import { CommandStatus, Priority, ClientType, AnyMessage, CommandMessage, ProgressUpdateMessage, ProgramMessage } from './index';
5
+ /**
6
+ * 协议工具类
7
+ */
8
+ export declare class ProtocolUtils {
9
+ /**
10
+ * 将 CommandStatus 枚举转换为字符串
11
+ */
12
+ static statusToString(status: CommandStatus): string;
13
+ /**
14
+ * 将字符串转换为 CommandStatus 枚举
15
+ * @throws {Error} 如果字符串不是有效的状态值
16
+ */
17
+ static stringToStatus(status: string): CommandStatus;
18
+ /**
19
+ * 将字符串转换为 Priority 枚举
20
+ * @throws {Error} 如果字符串不是有效的优先级值
21
+ */
22
+ static priorityToEnum(priority: string): Priority;
23
+ /**
24
+ * 将 Priority 枚举转换为字符串
25
+ */
26
+ static enumToPriority(priority: Priority): string;
27
+ /**
28
+ * 将字符串转换为 ClientType 枚举
29
+ * @throws {Error} 如果字符串不是有效的客户端类型
30
+ */
31
+ static clientTypeToEnum(clientType: string): ClientType;
32
+ /**
33
+ * 将 ClientType 枚举转换为字符串
34
+ */
35
+ static enumToClientType(clientType: ClientType): string;
36
+ /**
37
+ * 检查消息是否为命令消息
38
+ * 增强版本:不仅检查类型,还验证结构
39
+ */
40
+ static isCommandMessage(message: any): message is CommandMessage;
41
+ /**
42
+ * 检查消息是否为进度更新消息
43
+ * 增强版本:包含额外的结构验证
44
+ */
45
+ static isProgressUpdate(message: any): message is ProgressUpdateMessage;
46
+ /**
47
+ * 检查消息是否为程序消息
48
+ * 增强版本:包含额外的结构验证
49
+ */
50
+ static isProgramMessage(message: any): message is ProgramMessage;
51
+ /**
52
+ * 从任意消息中提取请求引用
53
+ * @returns 请求引用,如果消息类型不包含请求引用则返回 undefined
54
+ */
55
+ static extractRequestRef(message: AnyMessage): string | undefined;
56
+ /**
57
+ * 生成唯一的请求引用 ID
58
+ * @param prefix 可选的前缀,用于标识请求来源
59
+ * @returns 格式为 "prefix-timestamp-random" 或 "timestamp-random"
60
+ */
61
+ static generateRequestRef(prefix?: string): string;
62
+ /**
63
+ * 生成带有特定格式的请求引用
64
+ * @param service 服务名称
65
+ * @param operation 操作名称
66
+ * @returns 格式为 "service:operation:timestamp:random"
67
+ */
68
+ static generateStructuredRequestRef(service: string, operation: string): string;
69
+ /**
70
+ * 安全的枚举转换(不抛出异常)
71
+ * @returns 枚举值或 null
72
+ */
73
+ static tryParseStatus(status: string): CommandStatus | null;
74
+ /**
75
+ * 安全的优先级转换(不抛出异常)
76
+ * @returns 枚举值或 null
77
+ */
78
+ static tryParsePriority(priority: string): Priority | null;
79
+ /**
80
+ * 安全的客户端类型转换(不抛出异常)
81
+ * @returns 枚举值或 null
82
+ */
83
+ static tryParseClientType(clientType: string): ClientType | null;
84
+ /**
85
+ * 从请求引用中解析信息
86
+ * @returns 解析后的组件,如果格式不匹配则返回 null
87
+ */
88
+ static parseRequestRef(requestRef: string): {
89
+ prefix?: string;
90
+ timestamp?: number;
91
+ random?: string;
92
+ service?: string;
93
+ operation?: string;
94
+ } | null;
95
+ /**
96
+ * 获取消息的类型名称(友好的字符串格式)
97
+ */
98
+ static getMessageTypeName(message: AnyMessage): string;
99
+ /**
100
+ * 检查是否为请求消息(需要响应的消息)
101
+ */
102
+ static isRequestMessage(message: AnyMessage): boolean;
103
+ /**
104
+ * 检查是否为响应消息
105
+ */
106
+ static isResponseMessage(message: AnyMessage): boolean;
107
+ }
108
+ //# sourceMappingURL=protocol-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-utils.d.ts","sourceRoot":"","sources":["../src/protocol-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,aAAa,EACb,QAAQ,EACR,UAAU,EAEV,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,cAAc,EASf,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;IAIpD;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAYpD;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAUjD;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM;IAIjD;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU;IAUvD;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAIvD;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,cAAc;IAgBhE;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,qBAAqB;IAgBvE;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,cAAc;IAkBhE;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS;IAgCjE;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAalD;;;;;OAKG;IACH,MAAM,CAAC,4BAA4B,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAS/E;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAQ3D;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAQ1D;;;OAGG;IACH,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAQhE;;;OAGG;IACH,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG;QAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI;IAkCR;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM;IAmBtD;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAYrD;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;CAWvD"}
@@ -0,0 +1,293 @@
1
+ "use strict";
2
+ /**
3
+ * 协议工具类 - 提供状态转换、类型判断和请求引用管理功能
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ProtocolUtils = void 0;
7
+ const index_1 = require("./index");
8
+ /**
9
+ * 协议工具类
10
+ */
11
+ class ProtocolUtils {
12
+ /**
13
+ * 将 CommandStatus 枚举转换为字符串
14
+ */
15
+ static statusToString(status) {
16
+ return status.toString();
17
+ }
18
+ /**
19
+ * 将字符串转换为 CommandStatus 枚举
20
+ * @throws {Error} 如果字符串不是有效的状态值
21
+ */
22
+ static stringToStatus(status) {
23
+ // 处理大小写和空格
24
+ const normalizedStatus = status.trim().toUpperCase();
25
+ // 检查是否是有效的枚举值
26
+ if (!Object.values(index_1.CommandStatus).includes(normalizedStatus)) {
27
+ throw new Error(`Invalid command status: ${status}. Valid values are: ${Object.values(index_1.CommandStatus).join(', ')}`);
28
+ }
29
+ return normalizedStatus;
30
+ }
31
+ /**
32
+ * 将字符串转换为 Priority 枚举
33
+ * @throws {Error} 如果字符串不是有效的优先级值
34
+ */
35
+ static priorityToEnum(priority) {
36
+ const normalizedPriority = priority.trim().toUpperCase();
37
+ if (!Object.values(index_1.Priority).includes(normalizedPriority)) {
38
+ throw new Error(`Invalid priority: ${priority}. Valid values are: ${Object.values(index_1.Priority).join(', ')}`);
39
+ }
40
+ return normalizedPriority;
41
+ }
42
+ /**
43
+ * 将 Priority 枚举转换为字符串
44
+ */
45
+ static enumToPriority(priority) {
46
+ return priority.toString();
47
+ }
48
+ /**
49
+ * 将字符串转换为 ClientType 枚举
50
+ * @throws {Error} 如果字符串不是有效的客户端类型
51
+ */
52
+ static clientTypeToEnum(clientType) {
53
+ const normalizedType = clientType.trim().toUpperCase();
54
+ if (!Object.values(index_1.ClientType).includes(normalizedType)) {
55
+ throw new Error(`Invalid client type: ${clientType}. Valid values are: ${Object.values(index_1.ClientType).join(', ')}`);
56
+ }
57
+ return normalizedType;
58
+ }
59
+ /**
60
+ * 将 ClientType 枚举转换为字符串
61
+ */
62
+ static enumToClientType(clientType) {
63
+ return clientType.toString();
64
+ }
65
+ /**
66
+ * 检查消息是否为命令消息
67
+ * 增强版本:不仅检查类型,还验证结构
68
+ */
69
+ static isCommandMessage(message) {
70
+ if (!(0, index_1.isCommandMessage)(message)) {
71
+ return false;
72
+ }
73
+ // 额外的结构验证
74
+ return !!(message.requestRef &&
75
+ message.targetClientId &&
76
+ message.command &&
77
+ message.priority &&
78
+ message.timeout !== undefined &&
79
+ message.callback);
80
+ }
81
+ /**
82
+ * 检查消息是否为进度更新消息
83
+ * 增强版本:包含额外的结构验证
84
+ */
85
+ static isProgressUpdate(message) {
86
+ if (!(0, index_1.isProgressUpdateMessage)(message)) {
87
+ return false;
88
+ }
89
+ // 额外的结构验证
90
+ return !!(message.requestRef &&
91
+ message.status &&
92
+ message.phase &&
93
+ typeof message.progress === 'number' &&
94
+ message.sourceType &&
95
+ (message.sourceType === 'COMMAND' || message.sourceType === 'SYSTEM'));
96
+ }
97
+ /**
98
+ * 检查消息是否为程序消息
99
+ * 增强版本:包含额外的结构验证
100
+ */
101
+ static isProgramMessage(message) {
102
+ if (!(0, index_1.isProgramMessage)(message)) {
103
+ return false;
104
+ }
105
+ // 额外的结构验证
106
+ return !!(message.requestRef &&
107
+ message.targetClientId &&
108
+ message.command &&
109
+ message.command.commandCode === 'UPLOAD_PROGRAM' &&
110
+ message.command.parameters &&
111
+ message.priority &&
112
+ message.timeout !== undefined &&
113
+ message.callback);
114
+ }
115
+ /**
116
+ * 从任意消息中提取请求引用
117
+ * @returns 请求引用,如果消息类型不包含请求引用则返回 undefined
118
+ */
119
+ static extractRequestRef(message) {
120
+ switch (message.type) {
121
+ // 包含 requestRef 的消息类型
122
+ case index_1.MessageType.COMMAND:
123
+ case index_1.MessageType.COMMAND_RESPONSE:
124
+ case index_1.MessageType.PROGRAM:
125
+ case index_1.MessageType.PROGRAM_RESPONSE:
126
+ case index_1.MessageType.PROGRESS_UPDATE:
127
+ return message.requestRef;
128
+ // ERROR 消息可能在 context 中包含 requestRef
129
+ case index_1.MessageType.ERROR:
130
+ const errorMsg = message;
131
+ if (errorMsg.context && typeof errorMsg.context === 'object') {
132
+ return errorMsg.context.requestRef;
133
+ }
134
+ return undefined;
135
+ // 其他消息类型不包含 requestRef
136
+ case index_1.MessageType.REGISTER:
137
+ case index_1.MessageType.REGISTER_ACK:
138
+ case index_1.MessageType.UNREGISTER:
139
+ case index_1.MessageType.UNREGISTER_ACK:
140
+ case index_1.MessageType.HEARTBEAT:
141
+ case index_1.MessageType.HEARTBEAT_ACK:
142
+ return undefined;
143
+ default:
144
+ return undefined;
145
+ }
146
+ }
147
+ /**
148
+ * 生成唯一的请求引用 ID
149
+ * @param prefix 可选的前缀,用于标识请求来源
150
+ * @returns 格式为 "prefix-timestamp-random" 或 "timestamp-random"
151
+ */
152
+ static generateRequestRef(prefix) {
153
+ const timestamp = Date.now();
154
+ const random = Math.random().toString(36).substr(2, 9);
155
+ if (prefix) {
156
+ // 清理前缀,只保留字母数字和连字符
157
+ const cleanPrefix = prefix.replace(/[^a-zA-Z0-9-]/g, '');
158
+ return `${cleanPrefix}-${timestamp}-${random}`;
159
+ }
160
+ return `${timestamp}-${random}`;
161
+ }
162
+ /**
163
+ * 生成带有特定格式的请求引用
164
+ * @param service 服务名称
165
+ * @param operation 操作名称
166
+ * @returns 格式为 "service:operation:timestamp:random"
167
+ */
168
+ static generateStructuredRequestRef(service, operation) {
169
+ const timestamp = Date.now();
170
+ const random = Math.random().toString(36).substr(2, 6);
171
+ const cleanService = service.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
172
+ const cleanOperation = operation.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
173
+ return `${cleanService}:${cleanOperation}:${timestamp}:${random}`;
174
+ }
175
+ /**
176
+ * 安全的枚举转换(不抛出异常)
177
+ * @returns 枚举值或 null
178
+ */
179
+ static tryParseStatus(status) {
180
+ try {
181
+ return this.stringToStatus(status);
182
+ }
183
+ catch {
184
+ return null;
185
+ }
186
+ }
187
+ /**
188
+ * 安全的优先级转换(不抛出异常)
189
+ * @returns 枚举值或 null
190
+ */
191
+ static tryParsePriority(priority) {
192
+ try {
193
+ return this.priorityToEnum(priority);
194
+ }
195
+ catch {
196
+ return null;
197
+ }
198
+ }
199
+ /**
200
+ * 安全的客户端类型转换(不抛出异常)
201
+ * @returns 枚举值或 null
202
+ */
203
+ static tryParseClientType(clientType) {
204
+ try {
205
+ return this.clientTypeToEnum(clientType);
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ /**
212
+ * 从请求引用中解析信息
213
+ * @returns 解析后的组件,如果格式不匹配则返回 null
214
+ */
215
+ static parseRequestRef(requestRef) {
216
+ // 尝试解析结构化格式 "service:operation:timestamp:random"
217
+ const structuredMatch = requestRef.match(/^([a-z]+):([a-z]+):(\d+):([a-z0-9]+)$/);
218
+ if (structuredMatch) {
219
+ return {
220
+ service: structuredMatch[1],
221
+ operation: structuredMatch[2],
222
+ timestamp: parseInt(structuredMatch[3], 10),
223
+ random: structuredMatch[4]
224
+ };
225
+ }
226
+ // 尝试解析带前缀格式 "prefix-timestamp-random"
227
+ const prefixMatch = requestRef.match(/^([a-zA-Z0-9-]+)-(\d+)-([a-z0-9]+)$/);
228
+ if (prefixMatch) {
229
+ return {
230
+ prefix: prefixMatch[1],
231
+ timestamp: parseInt(prefixMatch[2], 10),
232
+ random: prefixMatch[3]
233
+ };
234
+ }
235
+ // 尝试解析简单格式 "timestamp-random"
236
+ const simpleMatch = requestRef.match(/^(\d+)-([a-z0-9]+)$/);
237
+ if (simpleMatch) {
238
+ return {
239
+ timestamp: parseInt(simpleMatch[1], 10),
240
+ random: simpleMatch[2]
241
+ };
242
+ }
243
+ return null;
244
+ }
245
+ /**
246
+ * 获取消息的类型名称(友好的字符串格式)
247
+ */
248
+ static getMessageTypeName(message) {
249
+ const typeNames = {
250
+ [index_1.MessageType.REGISTER]: 'Register',
251
+ [index_1.MessageType.REGISTER_ACK]: 'Register Acknowledgment',
252
+ [index_1.MessageType.UNREGISTER]: 'Unregister',
253
+ [index_1.MessageType.UNREGISTER_ACK]: 'Unregister Acknowledgment',
254
+ [index_1.MessageType.HEARTBEAT]: 'Heartbeat',
255
+ [index_1.MessageType.HEARTBEAT_ACK]: 'Heartbeat Acknowledgment',
256
+ [index_1.MessageType.COMMAND]: 'Command',
257
+ [index_1.MessageType.COMMAND_RESPONSE]: 'Command Response',
258
+ [index_1.MessageType.PROGRAM]: 'Program Upload',
259
+ [index_1.MessageType.PROGRAM_RESPONSE]: 'Program Response',
260
+ [index_1.MessageType.PROGRESS_UPDATE]: 'Progress Update',
261
+ [index_1.MessageType.ERROR]: 'Error'
262
+ };
263
+ return typeNames[message.type] || 'Unknown';
264
+ }
265
+ /**
266
+ * 检查是否为请求消息(需要响应的消息)
267
+ */
268
+ static isRequestMessage(message) {
269
+ const requestTypes = [
270
+ index_1.MessageType.REGISTER,
271
+ index_1.MessageType.UNREGISTER,
272
+ index_1.MessageType.HEARTBEAT,
273
+ index_1.MessageType.COMMAND,
274
+ index_1.MessageType.PROGRAM
275
+ ];
276
+ return requestTypes.includes(message.type);
277
+ }
278
+ /**
279
+ * 检查是否为响应消息
280
+ */
281
+ static isResponseMessage(message) {
282
+ const responseTypes = [
283
+ index_1.MessageType.REGISTER_ACK,
284
+ index_1.MessageType.UNREGISTER_ACK,
285
+ index_1.MessageType.HEARTBEAT_ACK,
286
+ index_1.MessageType.COMMAND_RESPONSE,
287
+ index_1.MessageType.PROGRAM_RESPONSE
288
+ ];
289
+ return responseTypes.includes(message.type);
290
+ }
291
+ }
292
+ exports.ProtocolUtils = ProtocolUtils;
293
+ //# sourceMappingURL=protocol-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-utils.js","sourceRoot":"","sources":["../src/protocol-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ # 协议规范文档
2
+
3
+ 本目录包含 JRSoft Subway WebSocket 协议的核心规范文档。
4
+
5
+ ## 📚 文档列表
6
+
7
+ ### [协议规范](./specification.md)
8
+ 完整的 WebSocket 协议定义,包括:
9
+ - 消息格式和类型
10
+ - 客户端类型定义
11
+ - 命令系统设计
12
+ - 错误处理机制
13
+ - 协议版本管理
14
+
15
+ ### [消息类型详解](./message-types.md)
16
+ 所有消息类型的详细说明:
17
+ - register - 客户端注册
18
+ - command - 命令请求
19
+ - command_response - 命令响应
20
+ - progress_update - 进度更新
21
+ - program - 节目上传
22
+ - program_response - 节目响应
23
+ - heartbeat - 心跳保活
24
+ - error - 错误消息
25
+
26
+ ### [设计理念](./design-rationale.md)
27
+ 协议设计的核心理念和决策:
28
+ - 为什么选择 WebSocket
29
+ - 消息格式设计考量
30
+ - 命令系统架构决策
31
+ - 扩展性和兼容性设计
32
+
33
+ ## 🚀 快速开始
34
+
35
+ 如果您是第一次接触本协议,建议按以下顺序阅读:
36
+
37
+ 1. 先阅读[设计理念](./design-rationale.md)了解协议的设计思想
38
+ 2. 然后查看[协议规范](./specification.md)掌握整体结构
39
+ 3. 最后深入[消息类型详解](./message-types.md)了解具体实现
40
+
41
+ ## 🔗 相关文档
42
+
43
+ - [命令系统文档](../02-commands/) - 了解不同类型的命令
44
+ - [架构文档](../03-architecture/) - 了解系统架构和消息流
45
+ - [集成指南](../04-integration/) - 如何集成协议到您的系统
@@ -0,0 +1,198 @@
1
+ # JRSoft Subway 协议设计理念
2
+
3
+ 本文档记录了 JRSoft Subway WebSocket 协议的核心设计决策和理念。
4
+
5
+ ## 目录
6
+
7
+ - [总体设计理念](#总体设计理念)
8
+ - [长时间运行操作](#长时间运行操作)
9
+ - [消息类型设计](#消息类型设计)
10
+ - [进度上报机制](#进度上报机制)
11
+ - [错误处理策略](#错误处理策略)
12
+
13
+ ## 总体设计理念
14
+
15
+ ### 1. 分层架构设计
16
+
17
+ 系统采用严格的分层架构:
18
+ - **Backend** → **Gateway** → **Edge** → **Device**
19
+ - Gateway 作为中央路由器,管理所有 Edge 连接
20
+ - Edge 作为设备接入点,管理本地设备连接
21
+ - 设备不直接连接 Gateway,确保架构清晰
22
+
23
+ ### 2. 渐进式复杂度
24
+
25
+ 协议采用渐进式设计,从简单到复杂:
26
+ - **Simple命令**:一次请求,一次响应
27
+ - **Batch命令**:一次请求,批量执行,汇总响应
28
+ - **Complex命令**:一次请求,多次进度更新,最终响应
29
+
30
+ ### 3. 明确的生命周期
31
+
32
+ 每个操作都有清晰的开始和结束:
33
+ - 开始:特定的请求消息(command、program)
34
+ - 过程:可选的进度更新(progress_update)
35
+ - 结束:明确的响应消息(command_response、program_response)
36
+
37
+ ## 长时间运行操作
38
+
39
+ ### Complex命令设计
40
+
41
+ **为什么需要Complex类型?**
42
+ - 某些操作需要执行多个步骤,每个步骤都有独立的结果
43
+ - 客户端需要实时了解执行进度
44
+ - 传统的请求-响应模式无法满足需求
45
+
46
+ **设计决策:**
47
+ 1. 复用现有的 `command` 消息结构,通过 `commandType: 'complex'` 区分
48
+ 2. 使用 `progress_update` 报告中间结果,保持消息格式统一
49
+ 3. 最终通过 `command_response` 结束,确保有明确的终止信号
50
+
51
+ **典型应用场景:**
52
+ - 健康检查:需要检查多个组件状态
53
+ - 系统诊断:逐步执行多项测试
54
+ - 状态监控:持续报告状态变化
55
+
56
+ ### 批量命令新设计(借鉴Complex模式)
57
+
58
+ **为什么要重新设计批量命令?**
59
+ - 当前设计要求设备理解批量概念,增加了复杂度
60
+ - 设备需要处理范围解析、批量执行等逻辑
61
+ - 难以实时跟踪每个设备的执行状态
62
+
63
+ **新的设计理念:**
64
+ 1. 批量命令由 Gateway/Edge 处理向下游传递到 Device
65
+ 2. Device 将批量命令分解为多个 Simple 命令
66
+ 3. 每个设备的响应通过 `progress_update` 实时上报
67
+ 4. 最终通过 `command_response` 返回汇总结果
68
+
69
+ **优势:**
70
+ - **设备端简化**:只需实现 Simple 命令
71
+ - **更好的可观察性**:实时看到每个设备状态
72
+ - **灵活的执行策略**:Gateway 可控制并发、失败处理等
73
+ - **协议统一**:批量和 Complex 都使用相同的进度机制
74
+
75
+ ### 程序上传设计
76
+
77
+ **为什么程序上传独立于命令系统?**
78
+ - 程序上传是特殊的业务流程,不是简单的命令执行
79
+ - 需要携带大量元数据(任务ID、程序ID、发布时间等)
80
+ - 上传过程涉及多个明确的阶段
81
+
82
+ **设计决策:**
83
+ 1. 使用专门的 `program` 和 `program_response` 消息类型
84
+ 2. 引入 `context` 确保每个进度更新都能关联到具体程序
85
+ 3. `program_response` 简化设计,仅作为流程结束标志
86
+
87
+ **阶段划分理由:**
88
+ - **downloading**:网络传输阶段
89
+ - **decompressing**:文件处理阶段
90
+ - **preprocessing**:内容验证阶段
91
+ - **createFrames**:数据转换阶段
92
+ - **uploading**:设备写入阶段
93
+ - **statistics**:结果统计阶段
94
+
95
+ ## 消息类型设计
96
+
97
+ ### 为什么不合并program和command?
98
+
99
+ 虽然两者都支持进度更新,但本质不同:
100
+ - **命令**:执行设备操作,关注操作结果
101
+ - **程序上传**:传输和安装内容,关注传输进度
102
+
103
+ 保持分离的好处:
104
+ 1. 语义清晰,易于理解
105
+ 2. 可以独立演进,互不影响
106
+ 3. 便于实现不同的业务逻辑
107
+
108
+ ### progress_update的通用性
109
+
110
+ `progress_update` 设计为通用的进度报告机制,可用于:
111
+ - Batch命令、Complex命令的中间结果
112
+ - 程序上传的阶段进度
113
+ - 未来其他长时间操作
114
+
115
+ 关键设计:
116
+ - `sourceType` 区分来源类型
117
+ - `report` 提供结构化日志
118
+ - `command` 记录设备操作
119
+ - `context` 关联程序信息
120
+
121
+ ## 进度上报机制
122
+
123
+ ### 状态管理
124
+
125
+ 六种状态覆盖所有场景:
126
+ - **pending**:等待开始
127
+ - **in_progress**:执行中
128
+ - **paused**:已暂停
129
+ - **completed**:成功完成
130
+ - **failed**:执行失败
131
+ - **cancelled**:已取消
132
+
133
+ ### 日志结构化
134
+
135
+ 统一的 `ReportMessage` 结构:
136
+ ```typescript
137
+ {
138
+ level: 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL';
139
+ message: string; // 必需的消息内容
140
+ code?: string; // 可选的标准化代码
141
+ data?: object; // 可选的附加数据
142
+ }
143
+ ```
144
+
145
+ 优势:
146
+ - 便于日志分级处理
147
+ - 支持错误代码标准化
148
+ - 可携带结构化数据
149
+
150
+ ## 错误处理策略
151
+
152
+ ### 分层错误处理
153
+
154
+ 1. **传输层错误**:WebSocket连接问题,由Gateway处理
155
+ 2. **协议层错误**:消息格式错误,返回error消息
156
+ 3. **业务层错误**:命令执行失败,在响应中体现
157
+
158
+ ### 错误信息设计
159
+
160
+ - 使用 `report` 结构统一错误信息
161
+ - `code` 用于错误分类
162
+ - `data` 携带错误详情
163
+ - `retryable` 标记是否可重试
164
+
165
+ ## 设计权衡
166
+
167
+ ### 1. 简单性 vs 功能性
168
+
169
+ 选择:优先简单性,通过可选字段扩展功能
170
+ - 基础功能保持简单
171
+ - 高级功能通过可选字段实现
172
+ - 避免过度设计
173
+
174
+ ### 2. 统一性 vs 特殊性
175
+
176
+ 选择:在统一框架下支持特殊需求
177
+ - 统一的消息基础结构
178
+ - 统一的进度上报机制
179
+ - 特殊需求通过扩展字段满足
180
+
181
+ ### 3. 同步 vs 异步
182
+
183
+ 选择:支持两种模式
184
+ - Simple命令:同步模式
185
+ - Complex命令和程序上传:异步模式
186
+ - 通过消息类型自然区分
187
+
188
+ ## 未来扩展性
189
+
190
+ 协议设计考虑了未来扩展:
191
+ 1. 版本字段支持协议演进
192
+ 2. 可选字段支持功能扩展
193
+ 3. 新的消息类型可以无缝添加
194
+ 4. 向后兼容性通过版本协商实现
195
+
196
+ ---
197
+
198
+ *本文档会随着协议演进持续更新*