@onekeyfe/hd-transport 1.2.0-alpha.0 → 1.2.0-alpha.10
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/README.md +1 -1
- package/__tests__/messages.test.js +76 -0
- package/__tests__/protocol-v2-link-manager.test.js +326 -0
- package/__tests__/protocol-v2-usb-transport-base.test.js +296 -0
- package/__tests__/protocol-v2.test.js +252 -84
- package/dist/constants.d.ts +4 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +564 -326
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +434 -102
- package/dist/protocols/index.d.ts +2 -0
- package/dist/protocols/index.d.ts.map +1 -1
- package/dist/protocols/v2/constants.d.ts +1 -0
- package/dist/protocols/v2/constants.d.ts.map +1 -1
- package/dist/protocols/v2/decode.d.ts +1 -0
- package/dist/protocols/v2/decode.d.ts.map +1 -1
- package/dist/protocols/v2/link-manager.d.ts +35 -0
- package/dist/protocols/v2/link-manager.d.ts.map +1 -0
- package/dist/protocols/v2/sequence-cursor.d.ts +5 -0
- package/dist/protocols/v2/sequence-cursor.d.ts.map +1 -0
- package/dist/protocols/v2/session.d.ts +16 -4
- package/dist/protocols/v2/session.d.ts.map +1 -1
- package/dist/protocols/v2/usb-transport-base.d.ts +31 -0
- package/dist/protocols/v2/usb-transport-base.d.ts.map +1 -0
- package/dist/serialization/protobuf/messages.d.ts.map +1 -1
- package/dist/types/messages.d.ts +337 -221
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/transport.d.ts +1 -1
- package/dist/types/transport.d.ts.map +1 -1
- package/messages-protocol-v2.json +992 -1420
- package/package.json +2 -2
- package/scripts/protobuf-build.sh +60 -142
- package/src/constants.ts +8 -2
- package/src/index.ts +8 -0
- package/src/protocols/index.ts +4 -1
- package/src/protocols/v2/constants.ts +1 -0
- package/src/protocols/v2/decode.ts +36 -17
- package/src/protocols/v2/link-manager.ts +160 -0
- package/src/protocols/v2/sequence-cursor.ts +10 -0
- package/src/protocols/v2/session.ts +86 -51
- package/src/protocols/v2/usb-transport-base.ts +194 -0
- package/src/serialization/protobuf/messages.ts +6 -1
- package/src/types/messages.ts +419 -272
- package/src/types/transport.ts +1 -1
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
const { ProtocolV2 } = require('../src/protocols');
|
|
2
2
|
const { parseConfigure } = require('../src/serialization/protobuf/messages');
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const {
|
|
4
|
+
ProtocolV2FrameAssembler,
|
|
5
|
+
ProtocolV2SequenceCursor,
|
|
6
|
+
ProtocolV2Session,
|
|
7
|
+
hexToBytes,
|
|
8
|
+
probeProtocolV2,
|
|
9
|
+
} = require('../src/protocols/v2/session');
|
|
6
10
|
const protocolV2 = require('../src/protocols/v2');
|
|
7
11
|
|
|
8
12
|
const protocolV1Messages = parseConfigure({
|
|
@@ -15,6 +19,18 @@ const protocolV1Messages = parseConfigure({
|
|
|
15
19
|
},
|
|
16
20
|
},
|
|
17
21
|
},
|
|
22
|
+
Failure: {
|
|
23
|
+
fields: {
|
|
24
|
+
code: {
|
|
25
|
+
type: 'uint32',
|
|
26
|
+
id: 1,
|
|
27
|
+
},
|
|
28
|
+
message: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
id: 2,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
18
34
|
ButtonRequest: {
|
|
19
35
|
fields: {
|
|
20
36
|
code: {
|
|
@@ -32,6 +48,7 @@ const protocolV1Messages = parseConfigure({
|
|
|
32
48
|
MessageType: {
|
|
33
49
|
values: {
|
|
34
50
|
MessageType_Success: 2,
|
|
51
|
+
MessageType_Failure: 3,
|
|
35
52
|
MessageType_ButtonRequest: 26,
|
|
36
53
|
MessageType_OnekeyGetFeatures: 10025,
|
|
37
54
|
MessageType_OnekeyFeatures: 10026,
|
|
@@ -42,21 +59,22 @@ const protocolV1Messages = parseConfigure({
|
|
|
42
59
|
|
|
43
60
|
const protocolV2Messages = parseConfigure({
|
|
44
61
|
nested: {
|
|
45
|
-
|
|
62
|
+
ProtocolInfoRequest: {
|
|
46
63
|
fields: {},
|
|
47
64
|
},
|
|
48
|
-
|
|
65
|
+
ProtocolInfo: {
|
|
49
66
|
fields: {
|
|
50
|
-
|
|
67
|
+
version: {
|
|
51
68
|
type: 'uint32',
|
|
52
69
|
id: 1,
|
|
53
70
|
},
|
|
54
|
-
|
|
71
|
+
supported_messages: {
|
|
55
72
|
type: 'uint32',
|
|
56
73
|
id: 2,
|
|
74
|
+
rule: 'repeated',
|
|
57
75
|
},
|
|
58
|
-
|
|
59
|
-
type: '
|
|
76
|
+
protobuf_definition: {
|
|
77
|
+
type: 'string',
|
|
60
78
|
id: 3,
|
|
61
79
|
},
|
|
62
80
|
},
|
|
@@ -77,18 +95,53 @@ const protocolV2Messages = parseConfigure({
|
|
|
77
95
|
},
|
|
78
96
|
},
|
|
79
97
|
},
|
|
80
|
-
|
|
81
|
-
fields: {
|
|
98
|
+
DeviceFirmwareTarget: {
|
|
99
|
+
fields: {
|
|
100
|
+
target_id: {
|
|
101
|
+
type: 'uint32',
|
|
102
|
+
id: 1,
|
|
103
|
+
},
|
|
104
|
+
path: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
id: 2,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
DeviceFirmwareUpdateRequest: {
|
|
111
|
+
fields: {
|
|
112
|
+
targets: {
|
|
113
|
+
type: 'DeviceFirmwareTarget',
|
|
114
|
+
id: 1,
|
|
115
|
+
rule: 'repeated',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
82
118
|
},
|
|
83
|
-
|
|
119
|
+
DeviceFirmwareUpdateRecord: {
|
|
84
120
|
fields: {
|
|
85
121
|
target_id: {
|
|
86
122
|
type: 'uint32',
|
|
87
123
|
id: 1,
|
|
88
124
|
},
|
|
89
|
-
|
|
125
|
+
status: {
|
|
90
126
|
type: 'uint32',
|
|
91
|
-
id:
|
|
127
|
+
id: 10,
|
|
128
|
+
},
|
|
129
|
+
payload_version: {
|
|
130
|
+
type: 'uint32',
|
|
131
|
+
id: 20,
|
|
132
|
+
},
|
|
133
|
+
path: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
id: 30,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
DeviceFirmwareUpdateStatus: {
|
|
140
|
+
fields: {
|
|
141
|
+
records: {
|
|
142
|
+
type: 'DeviceFirmwareUpdateRecord',
|
|
143
|
+
id: 1,
|
|
144
|
+
rule: 'repeated',
|
|
92
145
|
},
|
|
93
146
|
},
|
|
94
147
|
},
|
|
@@ -117,13 +170,13 @@ const protocolV2Messages = parseConfigure({
|
|
|
117
170
|
},
|
|
118
171
|
MessageType: {
|
|
119
172
|
values: {
|
|
120
|
-
|
|
121
|
-
|
|
173
|
+
MessageType_ProtocolInfoRequest: 60200,
|
|
174
|
+
MessageType_ProtocolInfo: 60201,
|
|
122
175
|
MessageType_Ping: 60206,
|
|
123
176
|
MessageType_Success: 60207,
|
|
124
177
|
MessageType_FileWrite: 60805,
|
|
125
|
-
|
|
126
|
-
|
|
178
|
+
MessageType_DeviceFirmwareUpdateRequest: 61000,
|
|
179
|
+
MessageType_DeviceFirmwareUpdateStatus: 61002,
|
|
127
180
|
MessageType_PartialNested: 62000,
|
|
128
181
|
},
|
|
129
182
|
},
|
|
@@ -144,10 +197,10 @@ const rewriteSeq = (frame, seq) => {
|
|
|
144
197
|
|
|
145
198
|
describe('Protocol V2 framing and session', () => {
|
|
146
199
|
test('encodes and decodes Protocol V2 protobuf frames', () => {
|
|
147
|
-
const frame = ProtocolV2.encodeFrame(schemas, '
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
200
|
+
const frame = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
201
|
+
version: 1,
|
|
202
|
+
supported_messages: [60200, 60201],
|
|
203
|
+
protobuf_definition: 'proto',
|
|
151
204
|
});
|
|
152
205
|
|
|
153
206
|
const parsed = protocolV2.decodeFrame(frame);
|
|
@@ -155,15 +208,15 @@ describe('Protocol V2 framing and session', () => {
|
|
|
155
208
|
|
|
156
209
|
const decoded = ProtocolV2.decodeFrame(schemas, frame);
|
|
157
210
|
expect(decoded).toEqual({
|
|
158
|
-
type: '
|
|
159
|
-
messageName: '
|
|
211
|
+
type: 'ProtocolInfo',
|
|
212
|
+
messageName: 'ProtocolInfo',
|
|
160
213
|
messageTypeId: 60201,
|
|
161
214
|
pbPayload: parsed.pbPayload,
|
|
162
215
|
seq: parsed.seq,
|
|
163
216
|
message: {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
217
|
+
version: 1,
|
|
218
|
+
supported_messages: [60200, 60201],
|
|
219
|
+
protobuf_definition: 'proto',
|
|
167
220
|
},
|
|
168
221
|
});
|
|
169
222
|
});
|
|
@@ -201,10 +254,9 @@ describe('Protocol V2 framing and session', () => {
|
|
|
201
254
|
});
|
|
202
255
|
|
|
203
256
|
test('reassembles split Protocol V2 frames and rejects oversized frames', () => {
|
|
204
|
-
const frame = ProtocolV2.encodeFrame(schemas, '
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
patch_version: 0,
|
|
257
|
+
const frame = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
258
|
+
version: 1,
|
|
259
|
+
supported_messages: [],
|
|
208
260
|
});
|
|
209
261
|
const assembler = new ProtocolV2FrameAssembler();
|
|
210
262
|
|
|
@@ -216,15 +268,13 @@ describe('Protocol V2 framing and session', () => {
|
|
|
216
268
|
});
|
|
217
269
|
|
|
218
270
|
test('keeps bytes after the first complete frame for the next read', () => {
|
|
219
|
-
const first = ProtocolV2.encodeFrame(schemas, '
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
patch_version: 0,
|
|
271
|
+
const first = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
272
|
+
version: 1,
|
|
273
|
+
supported_messages: [],
|
|
223
274
|
});
|
|
224
|
-
const second = ProtocolV2.encodeFrame(schemas, '
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
patch_version: 0,
|
|
275
|
+
const second = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
276
|
+
version: 2,
|
|
277
|
+
supported_messages: [],
|
|
228
278
|
});
|
|
229
279
|
const assembler = new ProtocolV2FrameAssembler();
|
|
230
280
|
const combined = new Uint8Array(first.length + second.length);
|
|
@@ -237,10 +287,9 @@ describe('Protocol V2 framing and session', () => {
|
|
|
237
287
|
|
|
238
288
|
test('session writes one encoded frame and decodes the response frame', async () => {
|
|
239
289
|
const written = [];
|
|
240
|
-
const response = ProtocolV2.encodeFrame(schemas, '
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
patch_version: 1,
|
|
290
|
+
const response = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
291
|
+
version: 2,
|
|
292
|
+
supported_messages: [60206],
|
|
244
293
|
});
|
|
245
294
|
const session = new ProtocolV2Session({
|
|
246
295
|
schemas,
|
|
@@ -253,22 +302,72 @@ describe('Protocol V2 framing and session', () => {
|
|
|
253
302
|
Promise.resolve(rewriteSeq(response, protocolV2.decodeFrame(written[0]).seq)),
|
|
254
303
|
});
|
|
255
304
|
|
|
256
|
-
const result = await session.call('
|
|
305
|
+
const result = await session.call('ProtocolInfoRequest', {});
|
|
257
306
|
|
|
258
307
|
expect(written).toHaveLength(1);
|
|
259
308
|
expect(written[0][4]).toBe(1);
|
|
260
309
|
expect(written[0][5]).toBe(0);
|
|
261
310
|
expect(protocolV2.decodeFrame(written[0]).messageTypeId).toBe(60200);
|
|
262
311
|
expect(result).toEqual({
|
|
263
|
-
type: '
|
|
312
|
+
type: 'ProtocolInfo',
|
|
264
313
|
message: {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
314
|
+
version: 2,
|
|
315
|
+
supported_messages: [60206],
|
|
316
|
+
protobuf_definition: null,
|
|
268
317
|
},
|
|
269
318
|
});
|
|
270
319
|
});
|
|
271
320
|
|
|
321
|
+
test('session skips Proto Link ACK frames before decoding the protobuf response', async () => {
|
|
322
|
+
const ack = new Uint8Array(8);
|
|
323
|
+
ack[0] = 0x5a;
|
|
324
|
+
ack[1] = 8;
|
|
325
|
+
ack[2] = 0;
|
|
326
|
+
ack[4] = 1;
|
|
327
|
+
ack[5] = 1;
|
|
328
|
+
ack[6] = 1;
|
|
329
|
+
ack[3] = protocolV2.crc8(ack, 3);
|
|
330
|
+
ack[7] = protocolV2.crc8(ack, 7);
|
|
331
|
+
|
|
332
|
+
const response = ProtocolV2.encodeFrame(schemas, 'Success', {
|
|
333
|
+
message: 'ok',
|
|
334
|
+
});
|
|
335
|
+
const readFrame = jest.fn().mockResolvedValueOnce(ack).mockResolvedValueOnce(response);
|
|
336
|
+
const session = new ProtocolV2Session({
|
|
337
|
+
schemas,
|
|
338
|
+
router: 1,
|
|
339
|
+
writeFrame: () => Promise.resolve(),
|
|
340
|
+
readFrame,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
await expect(session.call('Ping', { message: 'hello' })).resolves.toEqual({
|
|
344
|
+
type: 'Success',
|
|
345
|
+
message: {
|
|
346
|
+
message: 'ok',
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
expect(readFrame).toHaveBeenCalledTimes(2);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test('session rejects BLE frames above its configured frame limit before writing', async () => {
|
|
353
|
+
const writeFrame = jest.fn().mockResolvedValue(undefined);
|
|
354
|
+
const response = ProtocolV2.encodeFrame(schemas, 'Success', {
|
|
355
|
+
message: 'ok',
|
|
356
|
+
});
|
|
357
|
+
const session = new ProtocolV2Session({
|
|
358
|
+
schemas,
|
|
359
|
+
router: 1,
|
|
360
|
+
maxFrameBytes: 2048,
|
|
361
|
+
writeFrame,
|
|
362
|
+
readFrame: () => Promise.resolve(response),
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
await expect(session.call('Ping', { message: 'x'.repeat(2048) })).rejects.toThrow(
|
|
366
|
+
'Protocol V2 frame too large for transport: 2061 > 2048'
|
|
367
|
+
);
|
|
368
|
+
expect(writeFrame).not.toHaveBeenCalled();
|
|
369
|
+
});
|
|
370
|
+
|
|
272
371
|
test('session starts response timeout after the frame is written', async () => {
|
|
273
372
|
const response = ProtocolV2.encodeFrame(schemas, 'Success', {
|
|
274
373
|
message: 'ok',
|
|
@@ -294,10 +393,9 @@ describe('Protocol V2 framing and session', () => {
|
|
|
294
393
|
});
|
|
295
394
|
|
|
296
395
|
test('session accepts response frames with a device-owned seq', async () => {
|
|
297
|
-
const response = ProtocolV2.encodeFrame(schemas, '
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
patch_version: 1,
|
|
396
|
+
const response = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
397
|
+
version: 2,
|
|
398
|
+
supported_messages: [],
|
|
301
399
|
});
|
|
302
400
|
const logger = {
|
|
303
401
|
debug: jest.fn(),
|
|
@@ -310,12 +408,12 @@ describe('Protocol V2 framing and session', () => {
|
|
|
310
408
|
logger,
|
|
311
409
|
});
|
|
312
410
|
|
|
313
|
-
await expect(session.call('
|
|
314
|
-
type: '
|
|
411
|
+
await expect(session.call('ProtocolInfoRequest', {})).resolves.toEqual({
|
|
412
|
+
type: 'ProtocolInfo',
|
|
315
413
|
message: {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
414
|
+
version: 2,
|
|
415
|
+
supported_messages: [],
|
|
416
|
+
protobuf_definition: null,
|
|
319
417
|
},
|
|
320
418
|
});
|
|
321
419
|
expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('seq differs'));
|
|
@@ -399,10 +497,9 @@ describe('Protocol V2 framing and session', () => {
|
|
|
399
497
|
const stale = ProtocolV2.encodeFrame(schemas, 'Success', {
|
|
400
498
|
message: 'stale response',
|
|
401
499
|
});
|
|
402
|
-
const response = ProtocolV2.encodeFrame(schemas, '
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
patch_version: 1,
|
|
500
|
+
const response = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
501
|
+
version: 2,
|
|
502
|
+
supported_messages: [],
|
|
406
503
|
});
|
|
407
504
|
const logger = {
|
|
408
505
|
debug: jest.fn(),
|
|
@@ -417,13 +514,13 @@ describe('Protocol V2 framing and session', () => {
|
|
|
417
514
|
});
|
|
418
515
|
|
|
419
516
|
await expect(
|
|
420
|
-
session.call('
|
|
517
|
+
session.call('ProtocolInfoRequest', {}, { expectedTypes: ['ProtocolInfo'] })
|
|
421
518
|
).resolves.toEqual({
|
|
422
|
-
type: '
|
|
519
|
+
type: 'ProtocolInfo',
|
|
423
520
|
message: {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
521
|
+
version: 2,
|
|
522
|
+
supported_messages: [],
|
|
523
|
+
protobuf_definition: null,
|
|
427
524
|
},
|
|
428
525
|
});
|
|
429
526
|
|
|
@@ -433,9 +530,8 @@ describe('Protocol V2 framing and session', () => {
|
|
|
433
530
|
|
|
434
531
|
test('session consumes intermediate response frames before returning the final response', async () => {
|
|
435
532
|
const written = [];
|
|
436
|
-
const progress = ProtocolV2.encodeFrame(schemas, '
|
|
437
|
-
target_id:
|
|
438
|
-
progress: 42,
|
|
533
|
+
const progress = ProtocolV2.encodeFrame(schemas, 'DeviceFirmwareUpdateStatus', {
|
|
534
|
+
records: [{ target_id: 4, status: 1 }],
|
|
439
535
|
});
|
|
440
536
|
const success = ProtocolV2.encodeFrame(schemas, 'Success', {
|
|
441
537
|
message: 'ok',
|
|
@@ -459,20 +555,19 @@ describe('Protocol V2 framing and session', () => {
|
|
|
459
555
|
});
|
|
460
556
|
|
|
461
557
|
const result = await session.call(
|
|
462
|
-
'
|
|
463
|
-
{},
|
|
558
|
+
'DeviceFirmwareUpdateRequest',
|
|
559
|
+
{ targets: [{ target_id: 4, path: 'vol1:firmware.bin' }] },
|
|
464
560
|
{
|
|
465
|
-
intermediateTypes: ['
|
|
561
|
+
intermediateTypes: ['DeviceFirmwareUpdateStatus'],
|
|
466
562
|
onIntermediateResponse,
|
|
467
563
|
}
|
|
468
564
|
);
|
|
469
565
|
|
|
470
566
|
expect(readFrame).toHaveBeenCalledTimes(2);
|
|
471
567
|
expect(onIntermediateResponse).toHaveBeenCalledWith({
|
|
472
|
-
type: '
|
|
568
|
+
type: 'DeviceFirmwareUpdateStatus',
|
|
473
569
|
message: {
|
|
474
|
-
target_id:
|
|
475
|
-
progress: 42,
|
|
570
|
+
records: [{ target_id: 4, status: 1, payload_version: null, path: null }],
|
|
476
571
|
},
|
|
477
572
|
});
|
|
478
573
|
expect(result).toEqual({
|
|
@@ -483,7 +578,7 @@ describe('Protocol V2 framing and session', () => {
|
|
|
483
578
|
});
|
|
484
579
|
});
|
|
485
580
|
|
|
486
|
-
test('probeProtocolV2 accepts
|
|
581
|
+
test('probeProtocolV2 accepts Success as a normal V2 probe response', async () => {
|
|
487
582
|
await expect(
|
|
488
583
|
probeProtocolV2({
|
|
489
584
|
call: () => Promise.resolve({ type: 'Success', message: {} }),
|
|
@@ -562,7 +657,7 @@ describe('Protocol V2 framing and session', () => {
|
|
|
562
657
|
});
|
|
563
658
|
|
|
564
659
|
await expect(
|
|
565
|
-
session.call('
|
|
660
|
+
session.call('ProtocolInfoRequest', {}, { timeoutMs: 10, expectedTypes: ['ProtocolInfo'] })
|
|
566
661
|
).rejects.toThrow('Protocol V2 response timeout');
|
|
567
662
|
|
|
568
663
|
// Without cancellation the loop would skip this unexpected Success frame
|
|
@@ -661,6 +756,61 @@ describe('Protocol V2 framing and session', () => {
|
|
|
661
756
|
expect(written.map(frame => frame[6])).toEqual([1, 2, 1]);
|
|
662
757
|
});
|
|
663
758
|
|
|
759
|
+
test('session reuses an injected sequence cursor across recreated sessions', async () => {
|
|
760
|
+
const written = [];
|
|
761
|
+
const cursor = new ProtocolV2SequenceCursor();
|
|
762
|
+
const makeSession = () =>
|
|
763
|
+
new ProtocolV2Session({
|
|
764
|
+
schemas,
|
|
765
|
+
router: 1,
|
|
766
|
+
sequenceCursor: cursor,
|
|
767
|
+
writeFrame: frame => {
|
|
768
|
+
written.push(frame);
|
|
769
|
+
return Promise.resolve();
|
|
770
|
+
},
|
|
771
|
+
readFrame: () => {
|
|
772
|
+
const [frame] = written.slice(-1);
|
|
773
|
+
const { seq } = protocolV2.decodeFrame(frame);
|
|
774
|
+
return Promise.resolve(
|
|
775
|
+
rewriteSeq(ProtocolV2.encodeFrame(schemas, 'Success', { message: 'ok' }), seq)
|
|
776
|
+
);
|
|
777
|
+
},
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
await makeSession().call('Ping', { message: '1' });
|
|
781
|
+
await makeSession().call('Ping', { message: '2' });
|
|
782
|
+
|
|
783
|
+
expect(written.map(frame => frame[6])).toEqual([1, 2]);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
test('session passes per-call context to frame IO callbacks', async () => {
|
|
787
|
+
const writeContexts = [];
|
|
788
|
+
const readContexts = [];
|
|
789
|
+
const response = ProtocolV2.encodeFrame(schemas, 'Success', { message: 'ok' });
|
|
790
|
+
const session = new ProtocolV2Session({
|
|
791
|
+
schemas,
|
|
792
|
+
router: 1,
|
|
793
|
+
generation: 7,
|
|
794
|
+
writeFrame: (_frame, context) => {
|
|
795
|
+
writeContexts.push(context);
|
|
796
|
+
return Promise.resolve();
|
|
797
|
+
},
|
|
798
|
+
readFrame: context => {
|
|
799
|
+
readContexts.push(context);
|
|
800
|
+
return Promise.resolve(response);
|
|
801
|
+
},
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
await session.call('Ping', { message: 'ping' }, { timeoutMs: 123 });
|
|
805
|
+
await session.call('FileWrite', {}, { timeoutMs: 456 });
|
|
806
|
+
|
|
807
|
+
expect(writeContexts).toEqual([
|
|
808
|
+
{ messageName: 'Ping', timeoutMs: 123, highVolume: false, generation: 7 },
|
|
809
|
+
{ messageName: 'FileWrite', timeoutMs: 456, highVolume: true, generation: 7 },
|
|
810
|
+
]);
|
|
811
|
+
expect(readContexts).toEqual(writeContexts);
|
|
812
|
+
});
|
|
813
|
+
|
|
664
814
|
test('assembler throws and resets on frames with an impossible length field', () => {
|
|
665
815
|
const assembler = new ProtocolV2FrameAssembler();
|
|
666
816
|
// expectedLen = 0 < 8-byte minimum: without the guard this poisons the
|
|
@@ -687,10 +837,9 @@ describe('Protocol V2 framing and session', () => {
|
|
|
687
837
|
});
|
|
688
838
|
|
|
689
839
|
test('assembler drain returns every buffered complete frame', () => {
|
|
690
|
-
const first = ProtocolV2.encodeFrame(schemas, '
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
patch_version: 0,
|
|
840
|
+
const first = ProtocolV2.encodeFrame(schemas, 'ProtocolInfo', {
|
|
841
|
+
version: 1,
|
|
842
|
+
supported_messages: [],
|
|
694
843
|
});
|
|
695
844
|
const second = ProtocolV2.encodeFrame(schemas, 'Success', { message: 'ok' });
|
|
696
845
|
const third = ProtocolV2.encodeFrame(schemas, 'Success', { message: 'last' });
|
|
@@ -714,6 +863,26 @@ describe('Protocol V2 framing and session', () => {
|
|
|
714
863
|
expect(decoded.type).toBe('ButtonRequest');
|
|
715
864
|
});
|
|
716
865
|
|
|
866
|
+
test('decodes legacy V1 Failure as a Protocol V2 fallback', () => {
|
|
867
|
+
// Some device-side rejection paths still return legacy Failure(type=3)
|
|
868
|
+
// inside a Protocol V2 frame. It must surface as a device Failure, not as
|
|
869
|
+
// a protobuf catalog TypeError.
|
|
870
|
+
const frame = ProtocolV2.encodeFrame(
|
|
871
|
+
{ ...schemas, protocolV2: schemas.protocolV1 },
|
|
872
|
+
'Failure',
|
|
873
|
+
{
|
|
874
|
+
code: 1,
|
|
875
|
+
message: 'Action cancelled',
|
|
876
|
+
}
|
|
877
|
+
);
|
|
878
|
+
const decoded = ProtocolV2.decodeFrame(schemas, frame);
|
|
879
|
+
expect(decoded.type).toBe('Failure');
|
|
880
|
+
expect(decoded.message).toEqual({
|
|
881
|
+
code: 1,
|
|
882
|
+
message: 'Action cancelled',
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
|
|
717
886
|
test('does not fall back to legacy V1 messages outside the allowlist', () => {
|
|
718
887
|
// OnekeyFeatures exists only in the V1 schema and is not allowlisted.
|
|
719
888
|
const frame = protocolV2.encodeProtobufFrame(10026, new Uint8Array(0));
|
|
@@ -721,7 +890,6 @@ describe('Protocol V2 framing and session', () => {
|
|
|
721
890
|
});
|
|
722
891
|
|
|
723
892
|
test('hexToBytes converts valid hex and rejects malformed input', () => {
|
|
724
|
-
const { hexToBytes } = sessionModule;
|
|
725
893
|
expect(hexToBytes('5a0102')).toEqual(new Uint8Array([0x5a, 0x01, 0x02]));
|
|
726
894
|
expect(hexToBytes('')).toEqual(new Uint8Array(0));
|
|
727
895
|
expect(() => hexToBytes('abc')).toThrow('Invalid hex string: odd length');
|
|
@@ -729,7 +897,7 @@ describe('Protocol V2 framing and session', () => {
|
|
|
729
897
|
});
|
|
730
898
|
|
|
731
899
|
test('probeProtocolV2 only uses Ping for acquire probing', async () => {
|
|
732
|
-
const call = jest.fn().mockRejectedValue(new Error('
|
|
900
|
+
const call = jest.fn().mockRejectedValue(new Error('Ping timeout'));
|
|
733
901
|
const onProbeFailed = jest.fn();
|
|
734
902
|
|
|
735
903
|
await expect(
|
|
@@ -742,7 +910,7 @@ describe('Protocol V2 framing and session', () => {
|
|
|
742
910
|
expect(call).toHaveBeenNthCalledWith(
|
|
743
911
|
1,
|
|
744
912
|
'Ping',
|
|
745
|
-
{ message: 'probe' },
|
|
913
|
+
{ message: 'protocol-v2-probe' },
|
|
746
914
|
{
|
|
747
915
|
timeoutMs: 1,
|
|
748
916
|
expectedTypes: ['Success'],
|
package/dist/constants.d.ts
CHANGED
|
@@ -5,9 +5,11 @@ export declare const PROTOCOL_V1_USB_PACKET_SIZE: number;
|
|
|
5
5
|
export declare const PROTOCOL_V1_MESSAGE_HEADER_SIZE: number;
|
|
6
6
|
export declare const PROTOCOL_V1_ENVELOPE_HEADER_SIZE: number;
|
|
7
7
|
export declare const PROTOCOL_V2_FRAME_MAX_BYTES = 4608;
|
|
8
|
-
export declare const PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE =
|
|
8
|
+
export declare const PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE = 4000;
|
|
9
9
|
export declare const PROTOCOL_V2_BLE_FILE_CHUNK_SIZE = 1800;
|
|
10
|
-
export declare const
|
|
10
|
+
export declare const PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE = 900;
|
|
11
|
+
export declare const PROTOCOL_V2_BLE_FRAME_MAX_BYTES = 2048;
|
|
12
|
+
export declare const PROTOCOL_V2_FILE_CHUNK_SIZE = 4000;
|
|
11
13
|
export declare const PROTOCOL_V2_CHANNEL_USB = 0;
|
|
12
14
|
export declare const PROTOCOL_V2_CHANNEL_BLE_UART = 1;
|
|
13
15
|
export declare const PROTOCOL_V2_CHANNEL_SOCKET = 2;
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,KAAO,CAAC;AAG1C,eAAO,MAAM,uBAAuB,KAAO,CAAC;AAG5C,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAGjD,eAAO,MAAM,2BAA2B,QAAqC,CAAC;AAG9E,eAAO,MAAM,+BAA+B,QAAQ,CAAC;AAGrD,eAAO,MAAM,gCAAgC,QAA0C,CAAC;AAKxF,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAGhD,eAAO,MAAM,kCAAkC,OAAO,CAAC;AAGvD,eAAO,MAAM,+BAA+B,OAAO,CAAC;AAGpD,eAAO,MAAM,2BAA2B,OAAqC,CAAC;AAM9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AACzC,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAG5C,eAAO,MAAM,8BAA8B,IAAI,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,KAAO,CAAC;AAG1C,eAAO,MAAM,uBAAuB,KAAO,CAAC;AAG5C,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAGjD,eAAO,MAAM,2BAA2B,QAAqC,CAAC;AAG9E,eAAO,MAAM,+BAA+B,QAAQ,CAAC;AAGrD,eAAO,MAAM,gCAAgC,QAA0C,CAAC;AAKxF,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAGhD,eAAO,MAAM,kCAAkC,OAAO,CAAC;AAGvD,eAAO,MAAM,+BAA+B,OAAO,CAAC;AAGpD,eAAO,MAAM,oCAAoC,MAAM,CAAC;AAGxD,eAAO,MAAM,+BAA+B,OAAO,CAAC;AAGpD,eAAO,MAAM,2BAA2B,OAAqC,CAAC;AAM9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AACzC,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAG5C,eAAO,MAAM,8BAA8B,IAAI,CAAC"}
|