@onekeyfe/hd-transport-web-device 1.2.0-alpha.13 → 1.2.0-alpha.131
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__/electron-ble-transport.test.ts +377 -22
- package/__tests__/webusb-protocol-v2-timeout.test.ts +357 -11
- package/dist/ble-packet-capacity.d.ts +2 -0
- package/dist/ble-packet-capacity.d.ts.map +1 -0
- package/dist/electron-ble-transport.d.ts +16 -3
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +110 -12
- package/dist/index.js +345 -255
- package/dist/transportLog.d.ts +1 -6
- package/dist/transportLog.d.ts.map +1 -1
- package/dist/webusb.d.ts +15 -10
- package/dist/webusb.d.ts.map +1 -1
- package/jest.config.js +5 -0
- package/package.json +6 -5
- package/src/ble-packet-capacity.ts +13 -0
- package/src/electron-ble-transport.ts +241 -104
- package/src/transportLog.ts +1 -11
- package/src/webusb.ts +173 -189
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import transport, {
|
|
1
|
+
import transport, {
|
|
2
|
+
PROTOCOL_V2_CHANNEL_USB,
|
|
3
|
+
ProtocolV2,
|
|
4
|
+
ProtocolV2LinkError,
|
|
5
|
+
} from '@onekeyfe/hd-transport';
|
|
6
|
+
import { HardwareErrorCode, ONEKEY_WEBUSB_FILTER } from '@onekeyfe/hd-shared';
|
|
2
7
|
|
|
3
8
|
import WebUsbTransport from '../src/webusb';
|
|
4
9
|
|
|
@@ -16,25 +21,366 @@ const schema = {
|
|
|
16
21
|
};
|
|
17
22
|
|
|
18
23
|
describe('WebUsbTransport Protocol V2 timeout recovery', () => {
|
|
24
|
+
test('only enumerates devices with real USB serial numbers', async () => {
|
|
25
|
+
const filter = ONEKEY_WEBUSB_FILTER[0];
|
|
26
|
+
const deviceWithSerial = {
|
|
27
|
+
...filter,
|
|
28
|
+
manufacturerName: 'OneKey',
|
|
29
|
+
productName: 'OneKey Pro 2',
|
|
30
|
+
serialNumber: 'PRO2-SERIAL',
|
|
31
|
+
} as USBDevice;
|
|
32
|
+
const deviceWithoutSerial = {
|
|
33
|
+
...filter,
|
|
34
|
+
manufacturerName: 'OneKey',
|
|
35
|
+
productName: 'OneKey Pro 2',
|
|
36
|
+
serialNumber: null,
|
|
37
|
+
} as USBDevice;
|
|
38
|
+
const webusb = new WebUsbTransport();
|
|
39
|
+
webusb.usb = {
|
|
40
|
+
getDevices: jest.fn().mockResolvedValue([deviceWithSerial, deviceWithoutSerial]),
|
|
41
|
+
} as unknown as USB;
|
|
42
|
+
|
|
43
|
+
await expect(webusb.getConnectedDevices()).resolves.toEqual([
|
|
44
|
+
{
|
|
45
|
+
path: 'PRO2-SERIAL',
|
|
46
|
+
device: deviceWithSerial,
|
|
47
|
+
commType: 'webusb',
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('keeps active links when the Protocol V2 schema is configured repeatedly', () => {
|
|
53
|
+
const webusb = new WebUsbTransport() as any;
|
|
54
|
+
webusb.invalidateAllProtocolV2UsbLinks = jest.fn().mockResolvedValue(undefined);
|
|
55
|
+
const schemaSource = JSON.stringify(schema);
|
|
56
|
+
|
|
57
|
+
webusb.configureProtocolV2(schemaSource);
|
|
58
|
+
webusb.configureProtocolV2(schemaSource);
|
|
59
|
+
|
|
60
|
+
expect(webusb.invalidateAllProtocolV2UsbLinks).not.toHaveBeenCalled();
|
|
61
|
+
|
|
62
|
+
webusb.configureProtocolV2(
|
|
63
|
+
JSON.stringify({
|
|
64
|
+
...schema,
|
|
65
|
+
nested: {
|
|
66
|
+
...schema.nested,
|
|
67
|
+
Failure: { fields: { message: { type: 'string', id: 1 } } },
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
expect(webusb.invalidateAllProtocolV2UsbLinks).toHaveBeenCalledWith(
|
|
72
|
+
'Protocol V2 schema reconfigured'
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('resets the connection between a failed V1 probe and the V2 probe', async () => {
|
|
77
|
+
const webusb = new WebUsbTransport() as any;
|
|
78
|
+
const path = 'pro2-webusb';
|
|
79
|
+
const events: string[] = [];
|
|
80
|
+
webusb.probeProtocolV1 = jest.fn().mockImplementation(() => {
|
|
81
|
+
events.push('probe-v1');
|
|
82
|
+
return Promise.resolve(false);
|
|
83
|
+
});
|
|
84
|
+
webusb.resetConnectionAfterProbe = jest.fn().mockImplementation(() => {
|
|
85
|
+
events.push('reset');
|
|
86
|
+
return Promise.resolve();
|
|
87
|
+
});
|
|
88
|
+
webusb.probeProtocolV2 = jest.fn().mockImplementation(() => {
|
|
89
|
+
events.push('probe-v2');
|
|
90
|
+
return Promise.resolve(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await expect(webusb.detectProtocol(path)).resolves.toBe('V2');
|
|
94
|
+
|
|
95
|
+
expect(events).toEqual(['probe-v1', 'reset', 'probe-v2']);
|
|
96
|
+
expect(webusb.deviceProtocol.get(path)).toBe('V2');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('reports DeviceNotFound when automatic protocol detection exhausts both probes', async () => {
|
|
100
|
+
const webusb = new WebUsbTransport() as any;
|
|
101
|
+
const path = 'unresponsive-webusb';
|
|
102
|
+
webusb.probeProtocolV1 = jest.fn().mockResolvedValue(false);
|
|
103
|
+
webusb.probeProtocolV2 = jest.fn().mockResolvedValue(false);
|
|
104
|
+
webusb.resetConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
105
|
+
webusb.closeConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
106
|
+
|
|
107
|
+
await expect(webusb.detectProtocol(path)).rejects.toMatchObject({
|
|
108
|
+
errorCode: HardwareErrorCode.DeviceNotFound,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(webusb.probeProtocolV1).toHaveBeenCalledTimes(1);
|
|
112
|
+
expect(webusb.probeProtocolV2).toHaveBeenCalledTimes(1);
|
|
113
|
+
expect(webusb.resetConnectionAfterProbe).toHaveBeenCalledTimes(1);
|
|
114
|
+
expect(webusb.closeConnectionAfterProbe).toHaveBeenCalledTimes(1);
|
|
115
|
+
expect(webusb.deviceProtocol.has(path)).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('allows legacy WebUSB Initialize up to the Node USB probe timeout', async () => {
|
|
119
|
+
const webusb = new WebUsbTransport() as any;
|
|
120
|
+
const path = 'pro-webusb';
|
|
121
|
+
webusb.messages = {};
|
|
122
|
+
webusb.callProtocolV1 = jest.fn().mockResolvedValue({});
|
|
123
|
+
|
|
124
|
+
await expect(webusb.probeProtocolV1(path)).resolves.toBe(true);
|
|
125
|
+
|
|
126
|
+
expect(webusb.callProtocolV1).toHaveBeenCalledWith(
|
|
127
|
+
path,
|
|
128
|
+
'Initialize',
|
|
129
|
+
{},
|
|
130
|
+
{
|
|
131
|
+
timeoutMs: 5000,
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('retries an expected Protocol V2 probe once after resetting the connection', async () => {
|
|
137
|
+
const webusb = new WebUsbTransport() as any;
|
|
138
|
+
const path = 'pro2-webusb';
|
|
139
|
+
webusb.probeProtocolV1 = jest.fn();
|
|
140
|
+
webusb.probeProtocolV2 = jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
|
141
|
+
webusb.resetConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
142
|
+
|
|
143
|
+
await expect(webusb.detectProtocol(path, 'V2')).resolves.toBe('V2');
|
|
144
|
+
|
|
145
|
+
expect(webusb.probeProtocolV2).toHaveBeenCalledTimes(2);
|
|
146
|
+
expect(webusb.probeProtocolV1).not.toHaveBeenCalled();
|
|
147
|
+
expect(webusb.resetConnectionAfterProbe).toHaveBeenCalledTimes(1);
|
|
148
|
+
expect(webusb.deviceProtocol.get(path)).toBe('V2');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('reports a device initialization failure only after the bounded retry is exhausted', async () => {
|
|
152
|
+
const webusb = new WebUsbTransport() as any;
|
|
153
|
+
const path = 'pro2-webusb';
|
|
154
|
+
webusb.probeProtocolV1 = jest.fn();
|
|
155
|
+
webusb.probeProtocolV2 = jest.fn().mockResolvedValue(false);
|
|
156
|
+
webusb.resetConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
157
|
+
webusb.closeConnectionAfterProbe = jest.fn().mockResolvedValue(undefined);
|
|
158
|
+
|
|
159
|
+
await expect(webusb.detectProtocol(path, 'V2')).rejects.toMatchObject({
|
|
160
|
+
errorCode: HardwareErrorCode.DeviceInitializeFailed,
|
|
161
|
+
message: 'Protocol V2 probe timeout after 2 attempts',
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(webusb.probeProtocolV2).toHaveBeenCalledTimes(2);
|
|
165
|
+
expect(webusb.probeProtocolV1).not.toHaveBeenCalled();
|
|
166
|
+
expect(webusb.resetConnectionAfterProbe).toHaveBeenCalledTimes(1);
|
|
167
|
+
expect(webusb.closeConnectionAfterProbe).toHaveBeenCalledTimes(1);
|
|
168
|
+
expect(webusb.deviceProtocol.has(path)).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('closes the reopened device when acquire exhausts the expected Protocol V2 probe', async () => {
|
|
172
|
+
const webusb = new WebUsbTransport() as any;
|
|
173
|
+
const path = 'pro2-webusb';
|
|
174
|
+
const device = {
|
|
175
|
+
opened: false,
|
|
176
|
+
releaseInterface: jest.fn().mockResolvedValue(undefined),
|
|
177
|
+
close: jest.fn().mockImplementation(() => {
|
|
178
|
+
device.opened = false;
|
|
179
|
+
return Promise.resolve();
|
|
180
|
+
}),
|
|
181
|
+
};
|
|
182
|
+
webusb.deviceList = [{ path, device }];
|
|
183
|
+
webusb.Log = { debug: jest.fn() };
|
|
184
|
+
webusb.rotateProtocolV2UsbGeneration = jest.fn().mockResolvedValue(undefined);
|
|
185
|
+
webusb.connect = jest.fn().mockImplementation(() => {
|
|
186
|
+
device.opened = true;
|
|
187
|
+
return Promise.resolve();
|
|
188
|
+
});
|
|
189
|
+
webusb.detectProtocol = jest.fn().mockRejectedValue(new Error('terminal probe failure'));
|
|
190
|
+
|
|
191
|
+
await expect(webusb.acquire({ path, expectedProtocol: 'V2' })).rejects.toThrow(
|
|
192
|
+
'terminal probe failure'
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
expect(device.releaseInterface).toHaveBeenCalledTimes(1);
|
|
196
|
+
expect(device.close).toHaveBeenCalledTimes(1);
|
|
197
|
+
expect(device.opened).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
|
|
19
200
|
test('invalidates and resets the cached connection before another call can start', async () => {
|
|
20
201
|
const webusb = new WebUsbTransport() as any;
|
|
21
202
|
const path = 'pro2-webusb';
|
|
22
203
|
webusb.messages = transport.parseConfigure(schema);
|
|
23
204
|
webusb.messagesV2 = transport.parseConfigure(schema);
|
|
24
|
-
webusb.
|
|
25
|
-
webusb.
|
|
26
|
-
webusb.
|
|
27
|
-
webusb.resetConnectionAfterProbe = jest.fn()
|
|
28
|
-
|
|
29
|
-
webusb.protocolV2ReadTimeouts.delete(path);
|
|
30
|
-
webusb.protocolV2Assemblers.get(path)?.reset();
|
|
31
|
-
});
|
|
205
|
+
webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
|
|
206
|
+
webusb.readProtocolV2UsbPacket = jest.fn(() => new Promise<void>(() => {}));
|
|
207
|
+
webusb.resetProtocolV2UsbNativeLink = jest.fn().mockResolvedValue(undefined);
|
|
208
|
+
webusb.resetConnectionAfterProbe = jest.fn();
|
|
209
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
|
|
32
210
|
|
|
33
211
|
await expect(
|
|
34
212
|
webusb.callProtocolV2(path, 'Ping', { message: 'timeout' }, { timeoutMs: 10 })
|
|
35
213
|
).rejects.toThrow('timeout');
|
|
36
214
|
|
|
37
|
-
expect(webusb.
|
|
38
|
-
|
|
215
|
+
expect(webusb.resetProtocolV2UsbNativeLink).toHaveBeenCalledWith(
|
|
216
|
+
path,
|
|
217
|
+
expect.stringContaining('timeout')
|
|
218
|
+
);
|
|
219
|
+
expect(webusb.resetConnectionAfterProbe).not.toHaveBeenCalled();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test('does not reconnect inside a Protocol V2 frame read after a USB I/O failure', async () => {
|
|
223
|
+
const webusb = new WebUsbTransport() as any;
|
|
224
|
+
const path = 'pro2-webusb';
|
|
225
|
+
webusb.messages = transport.parseConfigure(schema);
|
|
226
|
+
webusb.messagesV2 = transport.parseConfigure(schema);
|
|
227
|
+
webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
|
|
228
|
+
webusb.readProtocolV2UsbPacket = jest
|
|
229
|
+
.fn()
|
|
230
|
+
.mockRejectedValue(new Error('NetworkError: transferIn device disconnected'));
|
|
231
|
+
webusb.resetProtocolV2UsbNativeLink = jest.fn().mockResolvedValue(undefined);
|
|
232
|
+
webusb.resetConnectionAfterProbe = jest.fn();
|
|
233
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
|
|
234
|
+
|
|
235
|
+
await expect(webusb.callProtocolV2(path, 'Ping', { message: 'read-error' })).rejects.toThrow(
|
|
236
|
+
'NetworkError'
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
expect(webusb.readProtocolV2UsbPacket).toHaveBeenCalledTimes(1);
|
|
240
|
+
expect(webusb.resetProtocolV2UsbNativeLink).toHaveBeenCalledWith(
|
|
241
|
+
path,
|
|
242
|
+
expect.stringContaining('NetworkError')
|
|
243
|
+
);
|
|
244
|
+
expect(webusb.resetConnectionAfterProbe).not.toHaveBeenCalled();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('rejects an active Protocol V2 read without reconnecting after release', async () => {
|
|
248
|
+
const webusb = new WebUsbTransport() as any;
|
|
249
|
+
const path = 'pro2-webusb';
|
|
250
|
+
let markReadStarted: () => void = () => undefined;
|
|
251
|
+
const readStarted = new Promise<void>(resolve => {
|
|
252
|
+
markReadStarted = resolve;
|
|
253
|
+
});
|
|
254
|
+
webusb.messages = transport.parseConfigure(schema);
|
|
255
|
+
webusb.messagesV2 = transport.parseConfigure(schema);
|
|
256
|
+
webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
|
|
257
|
+
webusb.readProtocolV2UsbPacket = jest.fn().mockImplementation(() => {
|
|
258
|
+
markReadStarted();
|
|
259
|
+
return new Promise<void>(() => {});
|
|
260
|
+
});
|
|
261
|
+
webusb.closeOpenDevice = jest.fn().mockResolvedValue(undefined);
|
|
262
|
+
webusb.connect = jest.fn();
|
|
263
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
|
|
264
|
+
|
|
265
|
+
const call = webusb.callProtocolV2(path, 'Ping', { message: 'release' });
|
|
266
|
+
await readStarted;
|
|
267
|
+
await webusb.release(path);
|
|
268
|
+
|
|
269
|
+
await expect(call).rejects.toThrow('WebUSB transport released');
|
|
270
|
+
expect(webusb.connect).not.toHaveBeenCalled();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test.each(['router', 'packet-source', 'ack-sequence', 'response-sequence', 'frame'] as const)(
|
|
274
|
+
'invalidates cached state for typed Protocol V2 %s errors',
|
|
275
|
+
async code => {
|
|
276
|
+
const webusb = new WebUsbTransport() as any;
|
|
277
|
+
const path = 'pro2-webusb';
|
|
278
|
+
webusb.messages = transport.parseConfigure(schema);
|
|
279
|
+
webusb.messagesV2 = transport.parseConfigure(schema);
|
|
280
|
+
webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
|
|
281
|
+
const recoveredResponse = ProtocolV2.encodeFrame(
|
|
282
|
+
{ protocolV1: webusb.messages, protocolV2: webusb.messagesV2 },
|
|
283
|
+
'Success',
|
|
284
|
+
{ message: 'recovered' },
|
|
285
|
+
{ seq: 1 }
|
|
286
|
+
);
|
|
287
|
+
webusb.readProtocolV2UsbPacket = jest
|
|
288
|
+
.fn()
|
|
289
|
+
.mockRejectedValueOnce(
|
|
290
|
+
new ProtocolV2LinkError(code, `Protocol V2 ${code} validation failed`)
|
|
291
|
+
)
|
|
292
|
+
.mockResolvedValue(recoveredResponse);
|
|
293
|
+
webusb.resetProtocolV2UsbNativeLink = jest.fn().mockResolvedValue(undefined);
|
|
294
|
+
webusb.resetConnectionAfterProbe = jest.fn();
|
|
295
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
|
|
296
|
+
|
|
297
|
+
await expect(webusb.callProtocolV2(path, 'Ping', { message: 'mismatch' })).rejects.toThrow(
|
|
298
|
+
`${code} validation failed`
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
expect(webusb.resetProtocolV2UsbNativeLink).toHaveBeenCalledWith(
|
|
302
|
+
path,
|
|
303
|
+
expect.stringContaining(`${code} validation failed`)
|
|
304
|
+
);
|
|
305
|
+
expect(webusb.resetConnectionAfterProbe).not.toHaveBeenCalled();
|
|
306
|
+
|
|
307
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test reconnect');
|
|
308
|
+
await expect(
|
|
309
|
+
webusb.callProtocolV2(path, 'Ping', { message: 'after-reset' })
|
|
310
|
+
).resolves.toMatchObject({
|
|
311
|
+
type: 'Success',
|
|
312
|
+
message: { message: 'recovered' },
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
test('does not discard buffered Protocol V2 frames before each call', async () => {
|
|
318
|
+
const webusb = new WebUsbTransport() as any;
|
|
319
|
+
const path = 'pro2-webusb';
|
|
320
|
+
webusb.messages = transport.parseConfigure(schema);
|
|
321
|
+
webusb.messagesV2 = transport.parseConfigure(schema);
|
|
322
|
+
webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
|
|
323
|
+
const firstResponse = ProtocolV2.encodeFrame(
|
|
324
|
+
{ protocolV1: webusb.messages, protocolV2: webusb.messagesV2 },
|
|
325
|
+
'Success',
|
|
326
|
+
{ message: 'first' },
|
|
327
|
+
{ router: PROTOCOL_V2_CHANNEL_USB, seq: 1 }
|
|
328
|
+
);
|
|
329
|
+
const secondResponse = ProtocolV2.encodeFrame(
|
|
330
|
+
{ protocolV1: webusb.messages, protocolV2: webusb.messagesV2 },
|
|
331
|
+
'Success',
|
|
332
|
+
{ message: 'second' },
|
|
333
|
+
{ router: PROTOCOL_V2_CHANNEL_USB, seq: 2 }
|
|
334
|
+
);
|
|
335
|
+
const coalescedResponses = new Uint8Array(firstResponse.length + secondResponse.length);
|
|
336
|
+
coalescedResponses.set(firstResponse);
|
|
337
|
+
coalescedResponses.set(secondResponse, firstResponse.length);
|
|
338
|
+
webusb.readProtocolV2UsbPacket = jest.fn().mockResolvedValue(coalescedResponses);
|
|
339
|
+
webusb.resetProtocolV2UsbNativeLink = jest.fn().mockResolvedValue(undefined);
|
|
340
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
|
|
341
|
+
|
|
342
|
+
await expect(webusb.callProtocolV2(path, 'Ping', { message: 'first' })).resolves.toMatchObject({
|
|
343
|
+
type: 'Success',
|
|
344
|
+
message: { message: 'first' },
|
|
345
|
+
});
|
|
346
|
+
await expect(webusb.callProtocolV2(path, 'Ping', { message: 'second' })).resolves.toMatchObject(
|
|
347
|
+
{
|
|
348
|
+
type: 'Success',
|
|
349
|
+
message: { message: 'second' },
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
expect(webusb.readProtocolV2UsbPacket).toHaveBeenCalledTimes(1);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test('keeps queued Protocol V2 read timeouts scoped to each call', async () => {
|
|
357
|
+
const webusb = new WebUsbTransport() as any;
|
|
358
|
+
const path = 'pro2-webusb';
|
|
359
|
+
let responseSequence = 0;
|
|
360
|
+
const readTimeouts: number[] = [];
|
|
361
|
+
webusb.messages = transport.parseConfigure(schema);
|
|
362
|
+
webusb.messagesV2 = transport.parseConfigure(schema);
|
|
363
|
+
webusb.writeProtocolV2UsbPacket = jest.fn().mockResolvedValue(undefined);
|
|
364
|
+
webusb.readProtocolV2UsbPacket = jest.fn().mockImplementation((_path, context) => {
|
|
365
|
+
responseSequence += 1;
|
|
366
|
+
readTimeouts.push(context.timeoutMs);
|
|
367
|
+
return Promise.resolve(
|
|
368
|
+
ProtocolV2.encodeFrame(
|
|
369
|
+
{ protocolV1: webusb.messages, protocolV2: webusb.messagesV2 },
|
|
370
|
+
'Success',
|
|
371
|
+
{ message: 'ok' },
|
|
372
|
+
{ seq: responseSequence }
|
|
373
|
+
)
|
|
374
|
+
);
|
|
375
|
+
});
|
|
376
|
+
webusb.resetProtocolV2UsbNativeLink = jest.fn().mockResolvedValue(undefined);
|
|
377
|
+
await webusb.rotateProtocolV2UsbGeneration(path, 'test connection');
|
|
378
|
+
|
|
379
|
+
await Promise.all([
|
|
380
|
+
webusb.callProtocolV2(path, 'Ping', { message: 'long' }, { timeoutMs: 1_000 }),
|
|
381
|
+
webusb.callProtocolV2(path, 'Ping', { message: 'short' }, { timeoutMs: 25 }),
|
|
382
|
+
]);
|
|
383
|
+
|
|
384
|
+
expect(readTimeouts).toEqual([1_000, 25]);
|
|
39
385
|
});
|
|
40
386
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ble-packet-capacity.d.ts","sourceRoot":"","sources":["../src/ble-packet-capacity.ts"],"names":[],"mappings":"AAEA,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,qBAAqB,EAAE,MAAM,EAC7B,sBAAsB,EAAE,MAAM,GAC7B,MAAM,CAMR"}
|
|
@@ -12,24 +12,31 @@ export type BleAcquireInput = {
|
|
|
12
12
|
uuid: string;
|
|
13
13
|
forceCleanRunPromise?: boolean;
|
|
14
14
|
expectedProtocol?: ProtocolType;
|
|
15
|
+
protocolHint?: ProtocolType;
|
|
15
16
|
};
|
|
16
17
|
export default class ElectronBleTransport {
|
|
17
18
|
private _messages;
|
|
18
19
|
private _messagesV2;
|
|
20
|
+
private protocolV2SchemaConfiguration;
|
|
19
21
|
name: string;
|
|
20
22
|
configured: boolean;
|
|
21
23
|
runPromise: Deferred<Uint8Array | string> | null;
|
|
24
|
+
private runPromiseDeviceId;
|
|
22
25
|
Log?: any;
|
|
23
26
|
emitter?: EventEmitter;
|
|
24
27
|
private connectedDevices;
|
|
25
28
|
private deviceProtocol;
|
|
26
29
|
private deviceProtocolHints;
|
|
30
|
+
private deviceMtus;
|
|
31
|
+
private devicePacketCapacities;
|
|
27
32
|
private v1Buffers;
|
|
28
33
|
private v2Assemblers;
|
|
29
34
|
private v2FrameQueues;
|
|
30
35
|
private v2FramePromises;
|
|
31
36
|
private protocolV2Links;
|
|
37
|
+
private warnedMissingRelease;
|
|
32
38
|
private notificationCleanups;
|
|
39
|
+
private mtuCleanups;
|
|
33
40
|
private disconnectCleanups;
|
|
34
41
|
private notificationTokens;
|
|
35
42
|
private nextNotificationToken;
|
|
@@ -51,7 +58,10 @@ export default class ElectronBleTransport {
|
|
|
51
58
|
name: string | null;
|
|
52
59
|
protocolType?: ProtocolType | undefined;
|
|
53
60
|
}>;
|
|
54
|
-
release(id: string): Promise<void>;
|
|
61
|
+
release(id: string, _onclose?: boolean, keepSession?: boolean): Promise<void>;
|
|
62
|
+
disconnect(id: string): Promise<void>;
|
|
63
|
+
private releaseNative;
|
|
64
|
+
private releaseLogical;
|
|
55
65
|
private createProtocolMismatchError;
|
|
56
66
|
private createProtocolDetectionError;
|
|
57
67
|
private clearProbeProtocol;
|
|
@@ -60,18 +70,21 @@ export default class ElectronBleTransport {
|
|
|
60
70
|
private resetProbeStateAfterProtocolProbe;
|
|
61
71
|
private probeProtocolV1;
|
|
62
72
|
private probeProtocolV2;
|
|
63
|
-
private writeWithChunking;
|
|
64
73
|
private writeOnce;
|
|
74
|
+
private refreshBlePacketCapacity;
|
|
75
|
+
private updateBlePacketCapacity;
|
|
76
|
+
private createMtuSubscription;
|
|
77
|
+
private writeProtocolV2Frame;
|
|
65
78
|
private handleNotification;
|
|
66
79
|
private handleProtocolV2Notification;
|
|
67
80
|
private getProtocolV2FrameQueue;
|
|
68
81
|
private resolveProtocolV2Frame;
|
|
69
|
-
private rejectAllProtocolV2Frames;
|
|
70
82
|
private resetProtocolV2Frames;
|
|
71
83
|
private rejectProtocolV2Frames;
|
|
72
84
|
private readProtocolV2Frame;
|
|
73
85
|
private handleProtocolV1Notification;
|
|
74
86
|
call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<import("@onekeyfe/hd-transport").MessageFromOneKey>;
|
|
87
|
+
post(uuid: string, name: string, data: Record<string, unknown>): Promise<void>;
|
|
75
88
|
private callProtocolV1;
|
|
76
89
|
private callProtocolV2;
|
|
77
90
|
private createProtocolV2Adapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
|