@onekeyfe/hd-transport 1.1.34-alpha.1 → 1.1.34-alpha.3
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/__tests__/build-receive.test.js +6 -8
- package/__tests__/decode-features.test.js +3 -2
- package/__tests__/messages.test.js +131 -0
- package/__tests__/protocol-v2-link-manager.test.js +351 -0
- package/__tests__/protocol-v2-usb-transport-base.test.js +296 -0
- package/__tests__/protocol-v2.test.js +899 -0
- package/dist/constants.d.ts +16 -5
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +1398 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1102 -85
- package/dist/protocols/index.d.ts +50 -0
- package/dist/protocols/index.d.ts.map +1 -0
- package/dist/protocols/v1/decode.d.ts +11 -0
- package/dist/protocols/v1/decode.d.ts.map +1 -0
- package/dist/protocols/v1/encode.d.ts +11 -0
- package/dist/protocols/v1/encode.d.ts.map +1 -0
- package/dist/protocols/v1/index.d.ts +5 -0
- package/dist/protocols/v1/index.d.ts.map +1 -0
- package/dist/protocols/v1/packets.d.ts +7 -0
- package/dist/protocols/v1/packets.d.ts.map +1 -0
- package/dist/{serialization → protocols/v1}/receive.d.ts +1 -1
- package/dist/protocols/v1/receive.d.ts.map +1 -0
- package/dist/protocols/v2/constants.d.ts +8 -0
- package/dist/protocols/v2/constants.d.ts.map +1 -0
- package/dist/protocols/v2/crc8.d.ts +3 -0
- package/dist/protocols/v2/crc8.d.ts.map +1 -0
- package/dist/protocols/v2/decode.d.ts +8 -0
- package/dist/protocols/v2/decode.d.ts.map +1 -0
- package/dist/protocols/v2/encode.d.ts +4 -0
- package/dist/protocols/v2/encode.d.ts.map +1 -0
- package/dist/protocols/v2/frame-assembler.d.ts +12 -0
- package/dist/protocols/v2/frame-assembler.d.ts.map +1 -0
- package/dist/protocols/v2/index.d.ts +6 -0
- package/dist/protocols/v2/index.d.ts.map +1 -0
- package/dist/protocols/v2/link-manager.d.ts +36 -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 +63 -0
- package/dist/protocols/v2/session.d.ts.map +1 -0
- 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/index.d.ts +6 -3
- package/dist/serialization/index.d.ts.map +1 -1
- package/dist/serialization/protobuf/decode.d.ts.map +1 -1
- package/dist/serialization/protobuf/messages.d.ts +1 -1
- package/dist/serialization/protobuf/messages.d.ts.map +1 -1
- package/dist/types/messages.d.ts +707 -12
- package/dist/types/messages.d.ts.map +1 -1
- package/dist/types/transport.d.ts +19 -5
- package/dist/types/transport.d.ts.map +1 -1
- package/dist/utils/logBlockCommand.d.ts.map +1 -1
- package/messages-protocol-v2.json +13544 -0
- package/package.json +3 -3
- package/scripts/protobuf-patches/TxInputType.js +1 -0
- package/scripts/protobuf-patches/index.js +2 -0
- package/scripts/protobuf-types.js +233 -18
- package/src/constants.ts +48 -6
- package/src/index.ts +47 -11
- package/src/protocols/index.ts +124 -0
- package/src/{serialization/protocol → protocols/v1}/decode.ts +4 -4
- package/src/{serialization/protocol → protocols/v1}/encode.ts +18 -13
- package/src/protocols/v1/index.ts +4 -0
- package/src/protocols/v1/packets.ts +53 -0
- package/src/{serialization → protocols/v1}/receive.ts +5 -5
- package/src/protocols/v2/constants.ts +7 -0
- package/src/protocols/v2/crc8.ts +34 -0
- package/src/protocols/v2/decode.ts +89 -0
- package/src/protocols/v2/encode.ts +90 -0
- package/src/protocols/v2/frame-assembler.ts +98 -0
- package/src/protocols/v2/index.ts +5 -0
- package/src/protocols/v2/link-manager.ts +162 -0
- package/src/protocols/v2/sequence-cursor.ts +10 -0
- package/src/protocols/v2/session.ts +339 -0
- package/src/protocols/v2/usb-transport-base.ts +194 -0
- package/src/serialization/index.ts +6 -5
- package/src/serialization/protobuf/decode.ts +7 -0
- package/src/serialization/protobuf/messages.ts +14 -5
- package/src/types/messages.ts +903 -13
- package/src/types/transport.ts +29 -5
- package/src/utils/logBlockCommand.ts +9 -1
- package/dist/serialization/protocol/decode.d.ts +0 -11
- package/dist/serialization/protocol/decode.d.ts.map +0 -1
- package/dist/serialization/protocol/encode.d.ts +0 -11
- package/dist/serialization/protocol/encode.d.ts.map +0 -1
- package/dist/serialization/protocol/index.d.ts +0 -3
- package/dist/serialization/protocol/index.d.ts.map +0 -1
- package/dist/serialization/receive.d.ts.map +0 -1
- package/dist/serialization/send.d.ts +0 -7
- package/dist/serialization/send.d.ts.map +0 -1
- package/src/serialization/protocol/index.ts +0 -2
- package/src/serialization/send.ts +0 -58
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
const {
|
|
3
|
+
PROTOCOL_V2_CHANNEL_USB,
|
|
4
|
+
PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
5
|
+
ProtocolV2,
|
|
6
|
+
ProtocolV2UsbTransportBase,
|
|
7
|
+
} = require('../src');
|
|
8
|
+
const { parseConfigure } = require('../src/serialization/protobuf/messages');
|
|
9
|
+
|
|
10
|
+
const protocolV1Messages = parseConfigure({
|
|
11
|
+
nested: {
|
|
12
|
+
Failure: {
|
|
13
|
+
fields: {
|
|
14
|
+
code: { type: 'uint32', id: 1 },
|
|
15
|
+
message: { type: 'string', id: 2 },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
MessageType: {
|
|
19
|
+
values: {
|
|
20
|
+
MessageType_Failure: 3,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const protocolV2Messages = parseConfigure({
|
|
27
|
+
nested: {
|
|
28
|
+
Ping: {
|
|
29
|
+
fields: {
|
|
30
|
+
message: { type: 'string', id: 1 },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
Success: {
|
|
34
|
+
fields: {
|
|
35
|
+
message: { type: 'string', id: 1 },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
MessageType: {
|
|
39
|
+
values: {
|
|
40
|
+
MessageType_Ping: 60206,
|
|
41
|
+
MessageType_Success: 60207,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const schemas = {
|
|
48
|
+
protocolV1: protocolV1Messages,
|
|
49
|
+
protocolV2: protocolV2Messages,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
class FakeUsbTransport extends ProtocolV2UsbTransportBase {
|
|
53
|
+
constructor() {
|
|
54
|
+
super({
|
|
55
|
+
router: PROTOCOL_V2_CHANNEL_USB,
|
|
56
|
+
maxFrameBytes: PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
57
|
+
logPrefix: 'ProtocolV2 FakeUSB',
|
|
58
|
+
});
|
|
59
|
+
this.sentSeqs = [];
|
|
60
|
+
this.readContexts = [];
|
|
61
|
+
this.readCounts = new Map();
|
|
62
|
+
this.packetQueues = new Map();
|
|
63
|
+
this.nativeResets = [];
|
|
64
|
+
this.invalidations = [];
|
|
65
|
+
this.nextReadError = undefined;
|
|
66
|
+
this.writeBlock = undefined;
|
|
67
|
+
this.readBlock = undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
callDevice(key, message, timeoutMs) {
|
|
71
|
+
return this.callProtocolV2Usb(
|
|
72
|
+
key,
|
|
73
|
+
'Ping',
|
|
74
|
+
{ message },
|
|
75
|
+
timeoutMs === undefined ? undefined : { timeoutMs }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
rotate(key, reason = 'USB connection rotated') {
|
|
80
|
+
return this.rotateProtocolV2UsbGeneration(key, reason);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
invalidate(key, reason) {
|
|
84
|
+
return this.invalidateProtocolV2UsbLink(key, reason);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
dispose(reason) {
|
|
88
|
+
return this.disposeProtocolV2UsbLinks(reason);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
failNextRead(error) {
|
|
92
|
+
this.nextReadError = error;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
blockNextWrite() {
|
|
96
|
+
let release;
|
|
97
|
+
let markStarted;
|
|
98
|
+
const started = new Promise(resolve => {
|
|
99
|
+
markStarted = resolve;
|
|
100
|
+
});
|
|
101
|
+
const blocked = new Promise(resolve => {
|
|
102
|
+
release = resolve;
|
|
103
|
+
});
|
|
104
|
+
this.writeBlock = { blocked, markStarted };
|
|
105
|
+
return { started, release };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
blockNextRead() {
|
|
109
|
+
let release;
|
|
110
|
+
let markStarted;
|
|
111
|
+
const started = new Promise(resolve => {
|
|
112
|
+
markStarted = resolve;
|
|
113
|
+
});
|
|
114
|
+
const blocked = new Promise(resolve => {
|
|
115
|
+
release = resolve;
|
|
116
|
+
});
|
|
117
|
+
this.readBlock = { blocked, markStarted };
|
|
118
|
+
return { started, release };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getProtocolV2UsbSchemas() {
|
|
122
|
+
return schemas;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
getProtocolV2UsbLogger() {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async writeProtocolV2UsbPacket(key, frame) {
|
|
130
|
+
const seq = frame[6];
|
|
131
|
+
this.sentSeqs.push([key, seq]);
|
|
132
|
+
const response = ProtocolV2.encodeFrame(
|
|
133
|
+
schemas,
|
|
134
|
+
'Success',
|
|
135
|
+
{ message: 'ok' },
|
|
136
|
+
{ router: PROTOCOL_V2_CHANNEL_USB, seq }
|
|
137
|
+
);
|
|
138
|
+
const splitAt = Math.min(4, response.length);
|
|
139
|
+
this.packetQueues.set(key, [response.slice(0, splitAt), response.slice(splitAt)]);
|
|
140
|
+
|
|
141
|
+
const block = this.writeBlock;
|
|
142
|
+
if (block) {
|
|
143
|
+
this.writeBlock = undefined;
|
|
144
|
+
block.markStarted();
|
|
145
|
+
await block.blocked;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
readProtocolV2UsbPacket(key, context) {
|
|
150
|
+
this.readContexts.push([key, context.timeoutMs]);
|
|
151
|
+
this.readCounts.set(key, Number(this.readCounts.get(key) ?? 0) + 1);
|
|
152
|
+
if (this.nextReadError) {
|
|
153
|
+
const error = this.nextReadError;
|
|
154
|
+
this.nextReadError = undefined;
|
|
155
|
+
return Promise.reject(error);
|
|
156
|
+
}
|
|
157
|
+
const readPacket = async () => {
|
|
158
|
+
const block = this.readBlock;
|
|
159
|
+
if (block) {
|
|
160
|
+
this.readBlock = undefined;
|
|
161
|
+
block.markStarted();
|
|
162
|
+
await block.blocked;
|
|
163
|
+
}
|
|
164
|
+
const packet = this.packetQueues.get(key)?.shift();
|
|
165
|
+
if (!packet) throw new Error(`No queued USB packet for ${key}`);
|
|
166
|
+
return packet;
|
|
167
|
+
};
|
|
168
|
+
return readPacket();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
resetProtocolV2UsbNativeLink(key, reason) {
|
|
172
|
+
this.nativeResets.push([key, reason]);
|
|
173
|
+
return Promise.resolve();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
onProtocolV2UsbLinkInvalidated(key, reason) {
|
|
177
|
+
this.invalidations.push([key, reason]);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
createProtocolV2UsbTimeoutError(name, timeoutMs) {
|
|
181
|
+
return new Error(`USB timeout after ${timeoutMs}ms for ${name}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
describe('ProtocolV2UsbTransportBase', () => {
|
|
186
|
+
test('keeps seq across USB generation rotation', async () => {
|
|
187
|
+
const transport = new FakeUsbTransport();
|
|
188
|
+
|
|
189
|
+
await transport.rotate('device-a');
|
|
190
|
+
await transport.callDevice('device-a', 'first');
|
|
191
|
+
await transport.rotate('device-a', 'USB reconnected');
|
|
192
|
+
await transport.callDevice('device-a', 'second');
|
|
193
|
+
|
|
194
|
+
expect(transport.sentSeqs).toEqual([
|
|
195
|
+
['device-a', 1],
|
|
196
|
+
['device-a', 2],
|
|
197
|
+
]);
|
|
198
|
+
expect(transport.nativeResets).toEqual([['device-a', 'USB reconnected']]);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test('passes each queued call its own timeout context', async () => {
|
|
202
|
+
const transport = new FakeUsbTransport();
|
|
203
|
+
await transport.rotate('device-a');
|
|
204
|
+
|
|
205
|
+
await Promise.all([
|
|
206
|
+
transport.callDevice('device-a', 'first', 111),
|
|
207
|
+
transport.callDevice('device-a', 'second', 222),
|
|
208
|
+
]);
|
|
209
|
+
|
|
210
|
+
expect(transport.readContexts).toEqual([
|
|
211
|
+
['device-a', 111],
|
|
212
|
+
['device-a', 111],
|
|
213
|
+
['device-a', 222],
|
|
214
|
+
['device-a', 222],
|
|
215
|
+
]);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('does not block a different USB path', async () => {
|
|
219
|
+
const transport = new FakeUsbTransport();
|
|
220
|
+
await transport.rotate('device-a');
|
|
221
|
+
await transport.rotate('device-b');
|
|
222
|
+
const blockedWrite = transport.blockNextWrite();
|
|
223
|
+
|
|
224
|
+
const callA = transport.callDevice('device-a', 'blocked');
|
|
225
|
+
await blockedWrite.started;
|
|
226
|
+
await expect(transport.callDevice('device-b', 'parallel')).resolves.toMatchObject({
|
|
227
|
+
type: 'Success',
|
|
228
|
+
});
|
|
229
|
+
blockedWrite.release();
|
|
230
|
+
await expect(callA).resolves.toMatchObject({ type: 'Success' });
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test('invalidates an in-flight generation before it can read', async () => {
|
|
234
|
+
const transport = new FakeUsbTransport();
|
|
235
|
+
await transport.rotate('device-a');
|
|
236
|
+
const blockedWrite = transport.blockNextWrite();
|
|
237
|
+
|
|
238
|
+
const call = transport.callDevice('device-a', 'blocked');
|
|
239
|
+
await blockedWrite.started;
|
|
240
|
+
await transport.rotate('device-a', 'USB generation changed');
|
|
241
|
+
blockedWrite.release();
|
|
242
|
+
|
|
243
|
+
await expect(call).rejects.toThrow('USB generation changed');
|
|
244
|
+
expect(transport.readCounts.get('device-a') ?? 0).toBe(0);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('rejects an in-flight packet read without waiting for native IO to settle', async () => {
|
|
248
|
+
const transport = new FakeUsbTransport();
|
|
249
|
+
await transport.rotate('device-a');
|
|
250
|
+
const blockedRead = transport.blockNextRead();
|
|
251
|
+
|
|
252
|
+
const call = transport.callDevice('device-a', 'blocked-read', 5000);
|
|
253
|
+
const outcome = call.then(
|
|
254
|
+
() => 'resolved',
|
|
255
|
+
error => error.message
|
|
256
|
+
);
|
|
257
|
+
await blockedRead.started;
|
|
258
|
+
await transport.invalidate('device-a', 'USB transport released');
|
|
259
|
+
const settled = await Promise.race([
|
|
260
|
+
outcome,
|
|
261
|
+
new Promise(resolve => {
|
|
262
|
+
setTimeout(() => resolve('still pending'), 50);
|
|
263
|
+
}),
|
|
264
|
+
]);
|
|
265
|
+
blockedRead.release();
|
|
266
|
+
|
|
267
|
+
expect(settled).toContain('USB transport released');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('invalidates the native link after a packet read failure', async () => {
|
|
271
|
+
const transport = new FakeUsbTransport();
|
|
272
|
+
await transport.rotate('device-a');
|
|
273
|
+
transport.failNextRead(new Error('USB transfer failed'));
|
|
274
|
+
|
|
275
|
+
await expect(transport.callDevice('device-a', 'failure')).rejects.toThrow(
|
|
276
|
+
'USB transfer failed'
|
|
277
|
+
);
|
|
278
|
+
expect(transport.nativeResets).toEqual([
|
|
279
|
+
['device-a', expect.stringContaining('USB transfer failed')],
|
|
280
|
+
]);
|
|
281
|
+
expect(transport.invalidations).toEqual([
|
|
282
|
+
['device-a', expect.stringContaining('USB transfer failed')],
|
|
283
|
+
]);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test('dispose clears the cursor and restarts seq from one', async () => {
|
|
287
|
+
const transport = new FakeUsbTransport();
|
|
288
|
+
await transport.rotate('device-a');
|
|
289
|
+
await transport.callDevice('device-a', 'before-dispose');
|
|
290
|
+
await transport.dispose('transport disposed');
|
|
291
|
+
await transport.rotate('device-a');
|
|
292
|
+
await transport.callDevice('device-a', 'after-dispose');
|
|
293
|
+
|
|
294
|
+
expect(transport.sentSeqs.map(([, seq]) => seq)).toEqual([1, 1]);
|
|
295
|
+
});
|
|
296
|
+
});
|