@onekeyfe/hd-transport-react-native 1.2.0-alpha.68 → 1.2.0-alpha.69
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/dist/BleTransport.d.ts +1 -1
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +6 -0
- package/dist/bleStrategy.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +9 -80
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +210 -341
- package/jest.config.js +0 -5
- package/package.json +5 -5
- package/src/BleTransport.ts +1 -1
- package/src/__tests__/bleStrategy.test.ts +77 -7
- package/src/__tests__/protocolV2Link.test.ts +121 -28
- package/src/bleStrategy.ts +23 -10
- package/src/constants.ts +2 -1
- package/src/index.ts +229 -486
- package/src/__tests__/connectTimeout.test.ts +0 -281
- package/src/__tests__/protocolReprobe.test.ts +0 -132
- package/src/__tests__/protocolV1SchemaFixture.ts +0 -39
- package/src/__tests__/staleCallTimeout.test.ts +0 -210
- package/src/__tests__/writePacketTimeout.test.ts +0 -305
package/jest.config.js
CHANGED
|
@@ -2,9 +2,4 @@ module.exports = {
|
|
|
2
2
|
preset: '../../jest.config.js',
|
|
3
3
|
testEnvironment: 'node',
|
|
4
4
|
modulePathIgnorePatterns: ['node_modules', '<rootDir>/dist'],
|
|
5
|
-
moduleNameMapper: {
|
|
6
|
-
// The workspace symlinks resolve to prebuilt dist outputs that can lag behind src.
|
|
7
|
-
'^@onekeyfe/hd-transport$': '<rootDir>/../hd-transport/src/index.ts',
|
|
8
|
-
'^@onekeyfe/hd-shared$': '<rootDir>/../shared/src/index.ts',
|
|
9
|
-
},
|
|
10
5
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.69",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.69",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.69",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.69",
|
|
26
26
|
"@onekeyfe/react-native-ble-utils": "^0.1.6",
|
|
27
27
|
"react-native-ble-plx": "3.5.1"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "c6baed25917e3c3f027f83dfc23cde85400de558"
|
|
30
30
|
}
|
package/src/BleTransport.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasWritableCapability,
|
|
3
|
+
resolveProtocolV2PacketCapacity,
|
|
4
|
+
shouldWriteProtocolV2WithResponse,
|
|
5
|
+
} from '../bleStrategy';
|
|
2
6
|
|
|
3
7
|
describe('React Native BLE strategy', () => {
|
|
4
8
|
test('accepts writeWithoutResponse-only characteristics', () => {
|
|
@@ -10,27 +14,35 @@ describe('React Native BLE strategy', () => {
|
|
|
10
14
|
expect(hasWritableCapability(characteristic)).toBe(true);
|
|
11
15
|
});
|
|
12
16
|
|
|
13
|
-
test('
|
|
14
|
-
expect(
|
|
17
|
+
test('rejects Protocol V2 packet sizing when MTU is unavailable', () => {
|
|
18
|
+
expect(() =>
|
|
15
19
|
resolveProtocolV2PacketCapacity({
|
|
16
20
|
platform: 'android',
|
|
17
|
-
androidPacketLength: 192,
|
|
18
21
|
mtu: null,
|
|
19
22
|
})
|
|
20
|
-
).
|
|
23
|
+
).toThrow('Protocol V2 BLE requires a negotiated MTU');
|
|
21
24
|
});
|
|
22
25
|
|
|
23
26
|
test('caps Android packet length by negotiated MTU payload', () => {
|
|
24
27
|
expect(
|
|
25
28
|
resolveProtocolV2PacketCapacity({
|
|
26
29
|
platform: 'android',
|
|
27
|
-
androidPacketLength:
|
|
30
|
+
androidPacketLength: 244,
|
|
28
31
|
mtu: 100,
|
|
29
32
|
})
|
|
30
33
|
).toBe(97);
|
|
31
34
|
});
|
|
32
35
|
|
|
33
|
-
test('
|
|
36
|
+
test('uses the Android 517 MTU payload when fully negotiated', () => {
|
|
37
|
+
expect(
|
|
38
|
+
resolveProtocolV2PacketCapacity({
|
|
39
|
+
platform: 'android',
|
|
40
|
+
mtu: 517,
|
|
41
|
+
})
|
|
42
|
+
).toBe(514);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('caps iOS packet length by the system-negotiated write payload', () => {
|
|
34
46
|
expect(
|
|
35
47
|
resolveProtocolV2PacketCapacity({
|
|
36
48
|
platform: 'ios',
|
|
@@ -39,4 +51,62 @@ describe('React Native BLE strategy', () => {
|
|
|
39
51
|
})
|
|
40
52
|
).toBe(244);
|
|
41
53
|
});
|
|
54
|
+
|
|
55
|
+
test('uses the reported iOS MTU without a compatibility fallback', () => {
|
|
56
|
+
expect(
|
|
57
|
+
resolveProtocolV2PacketCapacity({
|
|
58
|
+
platform: 'ios',
|
|
59
|
+
iosPacketLength: 128,
|
|
60
|
+
mtu: 23,
|
|
61
|
+
})
|
|
62
|
+
).toBe(20);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('uses a smaller system-negotiated iOS write payload', () => {
|
|
66
|
+
expect(
|
|
67
|
+
resolveProtocolV2PacketCapacity({
|
|
68
|
+
platform: 'ios',
|
|
69
|
+
iosPacketLength: 244,
|
|
70
|
+
mtu: 185,
|
|
71
|
+
})
|
|
72
|
+
).toBe(182);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('uses withoutResponse for a high-volume write unless explicitly overridden', () => {
|
|
76
|
+
const characteristic = {
|
|
77
|
+
isWritableWithResponse: true,
|
|
78
|
+
isWritableWithoutResponse: true,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
expect(
|
|
82
|
+
shouldWriteProtocolV2WithResponse({
|
|
83
|
+
platform: 'ios',
|
|
84
|
+
highVolume: true,
|
|
85
|
+
requestedWithResponse: false,
|
|
86
|
+
characteristic,
|
|
87
|
+
})
|
|
88
|
+
).toBe(false);
|
|
89
|
+
expect(
|
|
90
|
+
shouldWriteProtocolV2WithResponse({
|
|
91
|
+
platform: 'ios',
|
|
92
|
+
highVolume: true,
|
|
93
|
+
requestedWithResponse: true,
|
|
94
|
+
characteristic,
|
|
95
|
+
})
|
|
96
|
+
).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('falls back to withResponse when withoutResponse is unavailable', () => {
|
|
100
|
+
expect(
|
|
101
|
+
shouldWriteProtocolV2WithResponse({
|
|
102
|
+
platform: 'ios',
|
|
103
|
+
highVolume: true,
|
|
104
|
+
requestedWithResponse: false,
|
|
105
|
+
characteristic: {
|
|
106
|
+
isWritableWithResponse: true,
|
|
107
|
+
isWritableWithoutResponse: false,
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
).toBe(true);
|
|
111
|
+
});
|
|
42
112
|
});
|
|
@@ -32,6 +32,7 @@ jest.mock('react-native-ble-plx', () => ({
|
|
|
32
32
|
CharacteristicNotFound: 404,
|
|
33
33
|
},
|
|
34
34
|
BleManager: jest.fn(),
|
|
35
|
+
ConnectionPriority: { Balanced: 0, High: 1, LowPower: 2 },
|
|
35
36
|
ScanMode: { LowLatency: 2 },
|
|
36
37
|
}));
|
|
37
38
|
|
|
@@ -157,6 +158,7 @@ const createHarness = ({
|
|
|
157
158
|
id: uuid,
|
|
158
159
|
name: deviceName,
|
|
159
160
|
localName: deviceName,
|
|
161
|
+
mtu: 247,
|
|
160
162
|
serviceUUIDs: ['00000001-0000-1000-8000-00805f9b34fb'],
|
|
161
163
|
isConnected: jest.fn(() => Promise.resolve(true)),
|
|
162
164
|
cancelConnection: jest.fn(() => Promise.resolve()),
|
|
@@ -164,7 +166,9 @@ const createHarness = ({
|
|
|
164
166
|
disconnectCallback = callback;
|
|
165
167
|
return { remove: jest.fn() };
|
|
166
168
|
}),
|
|
167
|
-
};
|
|
169
|
+
} as any;
|
|
170
|
+
device.requestMTU = jest.fn(() => Promise.resolve(device));
|
|
171
|
+
device.requestConnectionPriority = jest.fn(() => Promise.resolve(device));
|
|
168
172
|
const bleManager = {
|
|
169
173
|
devices: jest.fn(() => Promise.resolve([device])),
|
|
170
174
|
connectedDevices: jest.fn(() => Promise.resolve([])),
|
|
@@ -172,18 +176,21 @@ const createHarness = ({
|
|
|
172
176
|
};
|
|
173
177
|
const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
|
|
174
178
|
const emitter = new EventEmitter();
|
|
179
|
+
const logger = { debug: jest.fn(), error: jest.fn() };
|
|
175
180
|
transport.blePlxManager = bleManager;
|
|
176
181
|
transport.resolveCharacteristics = jest.fn(() =>
|
|
177
182
|
Promise.resolve({ writeCharacteristic, notifyCharacteristic })
|
|
178
183
|
);
|
|
179
|
-
transport.init(
|
|
184
|
+
transport.init(logger, emitter);
|
|
180
185
|
transport.configure(protocolV1Schema);
|
|
181
186
|
transport.configureProtocolV2(protocolV2Schema);
|
|
182
187
|
|
|
183
188
|
return {
|
|
184
189
|
transport,
|
|
185
190
|
emitter,
|
|
191
|
+
logger,
|
|
186
192
|
uuid,
|
|
193
|
+
device,
|
|
187
194
|
sentSeqs,
|
|
188
195
|
writeCharacteristic,
|
|
189
196
|
setShouldRespond(value: boolean) {
|
|
@@ -247,6 +254,7 @@ const createV1Harness = ({
|
|
|
247
254
|
id: uuid,
|
|
248
255
|
name: 'OneKey Classic',
|
|
249
256
|
localName: 'OneKey Classic',
|
|
257
|
+
mtu: 247,
|
|
250
258
|
serviceUUIDs: ['00000001-0000-1000-8000-00805f9b34fb'],
|
|
251
259
|
isConnected: jest.fn(() => Promise.resolve(true)),
|
|
252
260
|
cancelConnection: jest.fn(() => Promise.resolve()),
|
|
@@ -255,7 +263,8 @@ const createV1Harness = ({
|
|
|
255
263
|
disconnectSubscriptionRemovers.push(remove);
|
|
256
264
|
return { remove };
|
|
257
265
|
}),
|
|
258
|
-
};
|
|
266
|
+
} as any;
|
|
267
|
+
device.requestMTU = jest.fn(() => Promise.resolve(device));
|
|
259
268
|
const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
|
|
260
269
|
const bleManager = {
|
|
261
270
|
devices: jest.fn(() => Promise.resolve([device])),
|
|
@@ -392,7 +401,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
392
401
|
});
|
|
393
402
|
|
|
394
403
|
test('actively probes Protocol V2 on iOS when only a name-derived hint is available', async () => {
|
|
395
|
-
const { transport, uuid, sentSeqs, writeCharacteristic } = createHarness({
|
|
404
|
+
const { transport, uuid, device, sentSeqs, writeCharacteristic } = createHarness({
|
|
396
405
|
deviceName: 'Pro2 6E9E',
|
|
397
406
|
});
|
|
398
407
|
|
|
@@ -400,6 +409,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
400
409
|
uuid,
|
|
401
410
|
protocolType: 'V2',
|
|
402
411
|
});
|
|
412
|
+
expect(device.requestMTU).toHaveBeenCalledWith(247);
|
|
403
413
|
expect(writeCharacteristic.writeWithResponse).toHaveBeenCalledTimes(1);
|
|
404
414
|
|
|
405
415
|
await expect(
|
|
@@ -429,6 +439,57 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
429
439
|
await transport.release(uuid, true);
|
|
430
440
|
});
|
|
431
441
|
|
|
442
|
+
test('continues with the current MTU when the connected snapshot refresh fails', async () => {
|
|
443
|
+
const { transport, uuid, device } = createHarness();
|
|
444
|
+
const mtuError = new Error('MTU refresh failed');
|
|
445
|
+
device.requestMTU.mockRejectedValueOnce(mtuError);
|
|
446
|
+
|
|
447
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
448
|
+
uuid,
|
|
449
|
+
protocolType: 'V2',
|
|
450
|
+
});
|
|
451
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(1);
|
|
452
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(247);
|
|
453
|
+
await transport.release(uuid, true);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
test('refreshes a transient bootloader MTU after notifications are ready', async () => {
|
|
457
|
+
const { transport, uuid, device } = createHarness();
|
|
458
|
+
device.mtu = 23;
|
|
459
|
+
device.requestMTU
|
|
460
|
+
.mockResolvedValueOnce(device)
|
|
461
|
+
.mockResolvedValueOnce(device)
|
|
462
|
+
.mockImplementationOnce(() => {
|
|
463
|
+
device.mtu = 247;
|
|
464
|
+
return Promise.resolve(device);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
468
|
+
uuid,
|
|
469
|
+
protocolType: 'V2',
|
|
470
|
+
});
|
|
471
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(3);
|
|
472
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(247);
|
|
473
|
+
await transport.release(uuid, true);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test('continues with a low bootloader MTU when the bounded retry fails', async () => {
|
|
477
|
+
const { transport, uuid, device } = createHarness();
|
|
478
|
+
device.mtu = 23;
|
|
479
|
+
device.requestMTU
|
|
480
|
+
.mockResolvedValueOnce(device)
|
|
481
|
+
.mockResolvedValueOnce(device)
|
|
482
|
+
.mockRejectedValueOnce(new Error('bootloader MTU retry failed'));
|
|
483
|
+
|
|
484
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
485
|
+
uuid,
|
|
486
|
+
protocolType: 'V2',
|
|
487
|
+
});
|
|
488
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(3);
|
|
489
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(23);
|
|
490
|
+
await transport.release(uuid, true);
|
|
491
|
+
});
|
|
492
|
+
|
|
432
493
|
test('reconnects before falling back to Protocol V1 after a fatal V2 probe failure', async () => {
|
|
433
494
|
setPlatformOS('android');
|
|
434
495
|
const { transport, uuid, device, notifySubscriptionRemovers, disconnectSubscriptionRemovers } =
|
|
@@ -564,14 +625,38 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
564
625
|
});
|
|
565
626
|
|
|
566
627
|
test('keeps iOS Protocol V2 high-volume calls on withoutResponse', async () => {
|
|
567
|
-
const { transport, uuid, writeCharacteristic } = createHarness();
|
|
628
|
+
const { transport, uuid, logger, writeCharacteristic } = createHarness();
|
|
568
629
|
|
|
569
630
|
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
570
631
|
|
|
571
632
|
await transport.call(uuid, 'FileWrite', {});
|
|
572
|
-
|
|
633
|
+
await transport.call(uuid, 'FileWrite', {});
|
|
634
|
+
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(2);
|
|
573
635
|
expect(writeCharacteristic.writeWithResponse).not.toHaveBeenCalled();
|
|
636
|
+
expect(
|
|
637
|
+
logger.debug.mock.calls.filter(
|
|
638
|
+
([message]) =>
|
|
639
|
+
message === '[ReactNativeBleTransport] Protocol V2 high-volume write configured'
|
|
640
|
+
)
|
|
641
|
+
).toHaveLength(1);
|
|
642
|
+
await transport.release(uuid, true);
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
test('uses Android 517 MTU and high connection priority during Protocol V2 high-volume calls', async () => {
|
|
646
|
+
setPlatformOS('android');
|
|
647
|
+
const { transport, uuid, device } = createHarness();
|
|
648
|
+
|
|
649
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
650
|
+
expect(device.requestMTU).toHaveBeenCalledWith(517);
|
|
651
|
+
|
|
652
|
+
await transport.call(uuid, 'FileWrite', {});
|
|
653
|
+
await transport.call(uuid, 'FileWrite', {});
|
|
654
|
+
|
|
655
|
+
expect(device.requestConnectionPriority).toHaveBeenCalledTimes(1);
|
|
656
|
+
expect(device.requestConnectionPriority).toHaveBeenCalledWith(1);
|
|
657
|
+
|
|
574
658
|
await transport.release(uuid, true);
|
|
659
|
+
expect(device.requestConnectionPriority).toHaveBeenLastCalledWith(0);
|
|
575
660
|
});
|
|
576
661
|
|
|
577
662
|
test('uses withResponse for an iOS Protocol V2 firmware file write when requested', async () => {
|
|
@@ -613,7 +698,6 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
613
698
|
|
|
614
699
|
await expect(
|
|
615
700
|
transport.writeProtocolV2Packet(
|
|
616
|
-
'test-device',
|
|
617
701
|
{
|
|
618
702
|
writeCharacteristic: {
|
|
619
703
|
isWritableWithResponse: true,
|
|
@@ -630,7 +714,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
630
714
|
expect(writeWithoutResponse).not.toHaveBeenCalled();
|
|
631
715
|
});
|
|
632
716
|
|
|
633
|
-
test('
|
|
717
|
+
test('does not pace a one-packet Protocol V2 control write on iOS', async () => {
|
|
634
718
|
const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
|
|
635
719
|
const writeWithoutResponse = jest.fn().mockResolvedValue(undefined);
|
|
636
720
|
const bleTransport = {
|
|
@@ -648,19 +732,9 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
648
732
|
const setTimeoutSpy = jest.spyOn(global, 'setTimeout');
|
|
649
733
|
|
|
650
734
|
try {
|
|
651
|
-
|
|
652
|
-
'test-device',
|
|
653
|
-
bleTransport,
|
|
654
|
-
new Uint8Array(10),
|
|
655
|
-
context,
|
|
656
|
-
jest.fn()
|
|
657
|
-
);
|
|
658
|
-
|
|
659
|
-
await Promise.resolve();
|
|
660
|
-
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 5);
|
|
661
|
-
expect(writeWithoutResponse).not.toHaveBeenCalled();
|
|
735
|
+
await transport.writeProtocolV2Frame(bleTransport, new Uint8Array(10), context, jest.fn());
|
|
662
736
|
|
|
663
|
-
|
|
737
|
+
expect(setTimeoutSpy).not.toHaveBeenCalled();
|
|
664
738
|
expect(writeWithoutResponse).toHaveBeenCalledTimes(1);
|
|
665
739
|
} finally {
|
|
666
740
|
setTimeoutSpy.mockRestore();
|
|
@@ -724,7 +798,6 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
724
798
|
configureProtocolV2BleTuning({ iosPacketLength: 20 });
|
|
725
799
|
|
|
726
800
|
await transport.writeProtocolV2Frame(
|
|
727
|
-
'device-uuid',
|
|
728
801
|
bleTransport,
|
|
729
802
|
new Uint8Array(30),
|
|
730
803
|
context,
|
|
@@ -756,14 +829,34 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
756
829
|
configureProtocolV2BleTuning({ iosPacketLength: 20 });
|
|
757
830
|
|
|
758
831
|
await expect(
|
|
759
|
-
transport.writeProtocolV2Frame(
|
|
760
|
-
'device-uuid',
|
|
761
|
-
bleTransport,
|
|
762
|
-
new Uint8Array(30),
|
|
763
|
-
context,
|
|
764
|
-
jest.fn()
|
|
765
|
-
)
|
|
832
|
+
transport.writeProtocolV2Frame(bleTransport, new Uint8Array(30), context, jest.fn())
|
|
766
833
|
).rejects.toMatchObject({ errorCode: 205 });
|
|
767
834
|
expect(writeWithoutResponse).toHaveBeenCalledTimes(1);
|
|
768
835
|
});
|
|
836
|
+
|
|
837
|
+
test('does not apply fixed burst or flush pauses to high-volume Protocol V2 writes', async () => {
|
|
838
|
+
const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
|
|
839
|
+
const writeWithoutResponse = jest.fn().mockResolvedValue(undefined);
|
|
840
|
+
const bleTransport = {
|
|
841
|
+
mtuSize: 247,
|
|
842
|
+
writeCharacteristic: { writeWithoutResponse },
|
|
843
|
+
};
|
|
844
|
+
const context = {
|
|
845
|
+
messageName: 'FileWrite',
|
|
846
|
+
timeoutMs: 1000,
|
|
847
|
+
highVolume: true,
|
|
848
|
+
generation: 1,
|
|
849
|
+
signal: new AbortController().signal,
|
|
850
|
+
};
|
|
851
|
+
const setTimeoutSpy = jest.spyOn(global, 'setTimeout');
|
|
852
|
+
|
|
853
|
+
try {
|
|
854
|
+
await transport.writeProtocolV2Frame(bleTransport, new Uint8Array(600), context, jest.fn());
|
|
855
|
+
|
|
856
|
+
expect(writeWithoutResponse).toHaveBeenCalledTimes(3);
|
|
857
|
+
expect(setTimeoutSpy).not.toHaveBeenCalled();
|
|
858
|
+
} finally {
|
|
859
|
+
setTimeoutSpy.mockRestore();
|
|
860
|
+
}
|
|
861
|
+
});
|
|
769
862
|
});
|
package/src/bleStrategy.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ANDROID_PROTOCOL_V2_PACKET_LENGTH, IOS_PROTOCOL_V2_PACKET_LENGTH } from './constants';
|
|
2
2
|
|
|
3
3
|
export type BlePlatform = 'ios' | 'android' | string;
|
|
4
4
|
|
|
@@ -13,8 +13,8 @@ export function hasWritableCapability(characteristic: BleWriteCapability) {
|
|
|
13
13
|
|
|
14
14
|
export function resolveProtocolV2PacketCapacity({
|
|
15
15
|
platform,
|
|
16
|
-
iosPacketLength =
|
|
17
|
-
androidPacketLength =
|
|
16
|
+
iosPacketLength = IOS_PROTOCOL_V2_PACKET_LENGTH,
|
|
17
|
+
androidPacketLength = ANDROID_PROTOCOL_V2_PACKET_LENGTH,
|
|
18
18
|
mtu,
|
|
19
19
|
}: {
|
|
20
20
|
platform: BlePlatform;
|
|
@@ -22,14 +22,27 @@ export function resolveProtocolV2PacketCapacity({
|
|
|
22
22
|
androidPacketLength?: number;
|
|
23
23
|
mtu?: number | null;
|
|
24
24
|
}) {
|
|
25
|
-
if (
|
|
26
|
-
|
|
25
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 3) {
|
|
26
|
+
throw new Error(`Protocol V2 BLE requires a negotiated MTU, received: ${String(mtu)}`);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
const payloadLength = Math.floor(mtu) - 3;
|
|
30
|
+
const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
|
|
31
|
+
return Math.min(configuredPacketLength, payloadLength);
|
|
32
|
+
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
export function shouldWriteProtocolV2WithResponse({
|
|
35
|
+
platform,
|
|
36
|
+
highVolume,
|
|
37
|
+
requestedWithResponse,
|
|
38
|
+
characteristic,
|
|
39
|
+
}: {
|
|
40
|
+
platform: BlePlatform;
|
|
41
|
+
highVolume: boolean;
|
|
42
|
+
requestedWithResponse?: boolean;
|
|
43
|
+
characteristic: BleWriteCapability;
|
|
44
|
+
}) {
|
|
45
|
+
if (!characteristic.isWritableWithResponse) return false;
|
|
46
|
+
if (!characteristic.isWritableWithoutResponse) return true;
|
|
47
|
+
return requestedWithResponse === true || (platform === 'ios' && !highVolume);
|
|
35
48
|
}
|
package/src/constants.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { createKnownBleUuidAliases, matchesKnownBleUuid } from '@onekeyfe/hd-sha
|
|
|
2
2
|
|
|
3
3
|
export const IOS_PACKET_LENGTH = 128;
|
|
4
4
|
export const ANDROID_PACKET_LENGTH = 192;
|
|
5
|
-
export const
|
|
5
|
+
export const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
6
|
+
export const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 514;
|
|
6
7
|
|
|
7
8
|
type BluetoothServices = Record<
|
|
8
9
|
string,
|