@onekeyfe/hd-transport-react-native 1.2.2-alpha.111 → 1.2.2-alpha.112
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/index.d.ts.map +1 -1
- package/dist/index.js +44 -32
- package/package.json +5 -5
- package/src/__tests__/connectTimeout.test.ts +1 -1
- package/src/__tests__/protocolV2Link.test.ts +45 -25
- package/src/index.ts +55 -38
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAGL,UAAU,IAAI,aAAa,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAChB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AAgChC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEjE,KAAK,8BAA8B,GAAG,eAAe,GAAG;IAMtD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAkBF,KAAK,4BAA4B,GAAG,WAAW,CAAC;AAChD,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkCF,eAAO,MAAM,+BAA+B,UACnC,OAAO,KACb,4BAA4B,GAAG,IAsBjC,CAAC;AAcF,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAClD,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAwBpD,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAI3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;AAkCD,eAAO,MAAM,sBAAsB,QAA2C,CAAC;AAO/E,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAQhD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,eAAO,MAAM,2CAA2C,IAAI,CAAC;AAE7D,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AActE,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -420,10 +420,10 @@ function getDeviceDisplayName(device) {
|
|
|
420
420
|
}
|
|
421
421
|
const IOS_REQUEST_MTU = 247;
|
|
422
422
|
const ANDROID_REQUEST_MTU = 517;
|
|
423
|
-
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
424
423
|
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
425
424
|
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
426
425
|
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
426
|
+
const BLE_MTU_REQUEST_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS;
|
|
427
427
|
const connectOptions = {
|
|
428
428
|
requestMTU: getRequestedBleMtu(),
|
|
429
429
|
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
@@ -457,14 +457,46 @@ const tryToGetConfiguration = (device) => {
|
|
|
457
457
|
return null;
|
|
458
458
|
return infos;
|
|
459
459
|
};
|
|
460
|
-
const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
460
|
+
const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
461
461
|
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
462
462
|
return device;
|
|
463
|
+
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
464
|
+
let timeoutId;
|
|
465
|
+
let timedOut = false;
|
|
463
466
|
try {
|
|
464
|
-
const
|
|
467
|
+
const request = device.requestMTU(getRequestedBleMtu(), transactionId);
|
|
468
|
+
const mtuDevice = yield Promise.race([
|
|
469
|
+
request,
|
|
470
|
+
new Promise((_, reject) => {
|
|
471
|
+
timeoutId = setTimeout(() => {
|
|
472
|
+
timedOut = true;
|
|
473
|
+
reject(new Error(`BLE MTU request timeout after ${BLE_MTU_REQUEST_TIMEOUT_MS}ms`));
|
|
474
|
+
}, BLE_MTU_REQUEST_TIMEOUT_MS);
|
|
475
|
+
}),
|
|
476
|
+
]);
|
|
465
477
|
return mtuDevice;
|
|
466
478
|
}
|
|
467
479
|
catch (error) {
|
|
480
|
+
if (timedOut && cancelTransaction) {
|
|
481
|
+
try {
|
|
482
|
+
Promise.resolve(cancelTransaction(transactionId)).catch(cancelError => {
|
|
483
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
|
|
484
|
+
platform: reactNative.Platform.OS,
|
|
485
|
+
stage,
|
|
486
|
+
attempt,
|
|
487
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError),
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
catch (cancelError) {
|
|
492
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
|
|
493
|
+
platform: reactNative.Platform.OS,
|
|
494
|
+
stage,
|
|
495
|
+
attempt,
|
|
496
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError),
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
468
500
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
469
501
|
platform: reactNative.Platform.OS,
|
|
470
502
|
stage,
|
|
@@ -474,8 +506,14 @@ const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void
|
|
|
474
506
|
});
|
|
475
507
|
return device;
|
|
476
508
|
}
|
|
509
|
+
finally {
|
|
510
|
+
if (timeoutId)
|
|
511
|
+
clearTimeout(timeoutId);
|
|
512
|
+
}
|
|
477
513
|
});
|
|
478
|
-
const resolveNegotiatedMtu = (device) =>
|
|
514
|
+
const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
|
|
515
|
+
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
516
|
+
: Promise.resolve(device);
|
|
479
517
|
function remapError(error) {
|
|
480
518
|
var _a;
|
|
481
519
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -930,38 +968,12 @@ class ReactNativeBleTransport {
|
|
|
930
968
|
else if (reactNative.Platform.OS === 'android') {
|
|
931
969
|
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
932
970
|
}
|
|
933
|
-
if (this.stopped)
|
|
934
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
935
|
-
const initialMtu = transport$1.mtuSize;
|
|
936
|
-
let refreshAttempts = 0;
|
|
937
|
-
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
938
|
-
shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
939
|
-
refreshAttempts += 1;
|
|
940
|
-
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
941
|
-
if (this.stopped)
|
|
942
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
943
|
-
transport$1.device = refreshedDevice;
|
|
944
|
-
transport$1.mtuSize =
|
|
945
|
-
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
946
|
-
if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
947
|
-
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
948
|
-
if (this.stopped)
|
|
949
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
950
|
-
refreshAttempts += 1;
|
|
951
|
-
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
952
|
-
transport$1.device = refreshedDevice;
|
|
953
|
-
transport$1.mtuSize =
|
|
954
|
-
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
971
|
if (this.stopped)
|
|
958
972
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
959
973
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
960
974
|
platform: reactNative.Platform.OS,
|
|
961
975
|
requested: getRequestedBleMtu(),
|
|
962
|
-
initial: initialMtu,
|
|
963
976
|
actual: transport$1.mtuSize,
|
|
964
|
-
refreshAttempts,
|
|
965
977
|
});
|
|
966
978
|
return transport$1;
|
|
967
979
|
});
|
|
@@ -1145,7 +1157,7 @@ class ReactNativeBleTransport {
|
|
|
1145
1157
|
}
|
|
1146
1158
|
if (this.stopped)
|
|
1147
1159
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1148
|
-
device = yield resolveNegotiatedMtu(device);
|
|
1160
|
+
device = yield resolveNegotiatedMtu(device, transactionId => blePlxManager.cancelTransaction(transactionId));
|
|
1149
1161
|
if (this.stopped)
|
|
1150
1162
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1151
1163
|
const acquiredDevice = device;
|
|
@@ -2445,7 +2457,7 @@ class ReactNativeBleTransport {
|
|
|
2445
2457
|
const transport = this.getCachedTransport(uuid);
|
|
2446
2458
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2447
2459
|
return;
|
|
2448
|
-
const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
|
|
2460
|
+
const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1, transactionId => { var _a; return (_a = this.blePlxManager) === null || _a === void 0 ? void 0 : _a.cancelTransaction(transactionId); });
|
|
2449
2461
|
transport.device = refreshedDevice;
|
|
2450
2462
|
transport.mtuSize =
|
|
2451
2463
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.2.2-alpha.
|
|
3
|
+
"version": "1.2.2-alpha.112",
|
|
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.2-alpha.
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.2-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.2-alpha.
|
|
23
|
+
"@onekeyfe/hd-core": "1.2.2-alpha.112",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.112",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.112",
|
|
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": "3b31cf365ea4042a5fb2e78dd7ede9a2d9d96e04"
|
|
30
30
|
}
|
|
@@ -446,7 +446,7 @@ describe('BLE connect timeout', () => {
|
|
|
446
446
|
const nativeOperation = createDeferred<typeof device>();
|
|
447
447
|
const nativeDisconnect = createDeferred<void>();
|
|
448
448
|
const requestMtu = jest.fn(() => Promise.resolve(device));
|
|
449
|
-
Object.assign(device, { mtu: 247, requestMTU: requestMtu });
|
|
449
|
+
Object.assign(device, { mtu: stage === 'mtu' ? 23 : 247, requestMTU: requestMtu });
|
|
450
450
|
device.isConnected.mockResolvedValue(true);
|
|
451
451
|
if (stage === 'connect') device.isConnected.mockResolvedValueOnce(false);
|
|
452
452
|
if (stage === 'mtu') requestMtu.mockImplementationOnce(() => nativeOperation.promise);
|
|
@@ -615,7 +615,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
615
615
|
uuid,
|
|
616
616
|
protocolType: 'V2',
|
|
617
617
|
});
|
|
618
|
-
expect(device.requestMTU).
|
|
618
|
+
expect(device.requestMTU).not.toHaveBeenCalled();
|
|
619
619
|
expect(writeCharacteristic.writeWithResponse).toHaveBeenCalledTimes(1);
|
|
620
620
|
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalled();
|
|
621
621
|
|
|
@@ -1079,57 +1079,69 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1079
1079
|
await transport.release(uuid, true);
|
|
1080
1080
|
});
|
|
1081
1081
|
|
|
1082
|
-
test('
|
|
1082
|
+
test('does not renegotiate an already usable MTU during acquire', async () => {
|
|
1083
1083
|
const { transport, uuid, device } = createHarness();
|
|
1084
|
-
const mtuError = new Error('MTU refresh failed');
|
|
1085
|
-
device.requestMTU.mockRejectedValueOnce(mtuError);
|
|
1086
1084
|
|
|
1087
1085
|
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
1088
1086
|
uuid,
|
|
1089
1087
|
protocolType: 'V2',
|
|
1090
1088
|
});
|
|
1091
|
-
expect(device.requestMTU).
|
|
1089
|
+
expect(device.requestMTU).not.toHaveBeenCalled();
|
|
1092
1090
|
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(247);
|
|
1093
1091
|
await transport.release(uuid, true);
|
|
1094
1092
|
});
|
|
1095
1093
|
|
|
1096
|
-
test('
|
|
1094
|
+
test('requests a low MTU once before protocol probing', async () => {
|
|
1097
1095
|
const { transport, uuid, device } = createHarness();
|
|
1098
1096
|
device.mtu = 23;
|
|
1099
|
-
device.requestMTU
|
|
1100
|
-
.
|
|
1101
|
-
.
|
|
1102
|
-
|
|
1103
|
-
device.mtu = 247;
|
|
1104
|
-
return Promise.resolve(device);
|
|
1105
|
-
});
|
|
1097
|
+
device.requestMTU.mockImplementationOnce(() => {
|
|
1098
|
+
device.mtu = 247;
|
|
1099
|
+
return Promise.resolve(device);
|
|
1100
|
+
});
|
|
1106
1101
|
|
|
1107
1102
|
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
1108
1103
|
uuid,
|
|
1109
1104
|
protocolType: 'V2',
|
|
1110
1105
|
});
|
|
1111
|
-
expect(device.requestMTU).toHaveBeenCalledTimes(
|
|
1106
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(1);
|
|
1107
|
+
expect(device.requestMTU).toHaveBeenCalledWith(
|
|
1108
|
+
247,
|
|
1109
|
+
expect.stringContaining(`${uuid}:mtu:connected:0:`)
|
|
1110
|
+
);
|
|
1112
1111
|
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(247);
|
|
1113
1112
|
await transport.release(uuid, true);
|
|
1114
1113
|
});
|
|
1115
1114
|
|
|
1116
|
-
test('continues with a low
|
|
1115
|
+
test('continues with a low MTU when the single negotiation fails', async () => {
|
|
1117
1116
|
const { transport, uuid, device } = createHarness();
|
|
1118
1117
|
device.mtu = 23;
|
|
1119
|
-
device.requestMTU
|
|
1120
|
-
.mockResolvedValueOnce(device)
|
|
1121
|
-
.mockResolvedValueOnce(device)
|
|
1122
|
-
.mockRejectedValueOnce(new Error('bootloader MTU retry failed'));
|
|
1118
|
+
device.requestMTU.mockRejectedValueOnce(new Error('MTU negotiation failed'));
|
|
1123
1119
|
|
|
1124
1120
|
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
1125
1121
|
uuid,
|
|
1126
1122
|
protocolType: 'V2',
|
|
1127
1123
|
});
|
|
1128
|
-
expect(device.requestMTU).toHaveBeenCalledTimes(
|
|
1124
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(1);
|
|
1129
1125
|
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(23);
|
|
1130
1126
|
await transport.release(uuid, true);
|
|
1131
1127
|
});
|
|
1132
1128
|
|
|
1129
|
+
test('bounds a stalled MTU negotiation and continues protocol probing', async () => {
|
|
1130
|
+
const { transport, uuid, device, bleManager } = createHarness();
|
|
1131
|
+
device.mtu = 23;
|
|
1132
|
+
device.requestMTU.mockImplementationOnce(() => new Promise(() => {}));
|
|
1133
|
+
|
|
1134
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
1135
|
+
uuid,
|
|
1136
|
+
protocolType: 'V2',
|
|
1137
|
+
});
|
|
1138
|
+
const transactionId = device.requestMTU.mock.calls[0]?.[1];
|
|
1139
|
+
expect(transactionId).toEqual(expect.stringContaining(`${uuid}:mtu:connected:0:`));
|
|
1140
|
+
expect(bleManager.cancelTransaction).toHaveBeenCalledWith(transactionId);
|
|
1141
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(23);
|
|
1142
|
+
await transport.release(uuid, true);
|
|
1143
|
+
}, 10_000);
|
|
1144
|
+
|
|
1133
1145
|
test('accepts a stable low MTU without the delayed refresh loop', async () => {
|
|
1134
1146
|
const { transport, uuid, device } = createHarness();
|
|
1135
1147
|
device.mtu = 185;
|
|
@@ -1138,7 +1150,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1138
1150
|
uuid,
|
|
1139
1151
|
protocolType: 'V2',
|
|
1140
1152
|
});
|
|
1141
|
-
expect(device.requestMTU).
|
|
1153
|
+
expect(device.requestMTU).not.toHaveBeenCalled();
|
|
1142
1154
|
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(185);
|
|
1143
1155
|
await transport.release(uuid, true);
|
|
1144
1156
|
});
|
|
@@ -1151,7 +1163,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1151
1163
|
uuid,
|
|
1152
1164
|
protocolType: 'V2',
|
|
1153
1165
|
});
|
|
1154
|
-
expect(device.requestMTU).toHaveBeenCalledTimes(
|
|
1166
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(1);
|
|
1155
1167
|
expect((transport as any).getCachedTransport(uuid).mtuSize).toBeUndefined();
|
|
1156
1168
|
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalled();
|
|
1157
1169
|
await transport.release(uuid, true);
|
|
@@ -1169,7 +1181,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1169
1181
|
});
|
|
1170
1182
|
|
|
1171
1183
|
await expect(transport.call(uuid, 'FileWrite', {})).resolves.toBeDefined();
|
|
1172
|
-
expect(device.requestMTU).toHaveBeenCalledTimes(
|
|
1184
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(2);
|
|
1173
1185
|
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(
|
|
1174
1186
|
writesBeforeFileWrite + 1
|
|
1175
1187
|
);
|
|
@@ -1186,7 +1198,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1186
1198
|
await expect(transport.call(uuid, 'FileWrite', {})).rejects.toMatchObject({
|
|
1187
1199
|
errorCode: HardwareErrorCode.BleConnectedError,
|
|
1188
1200
|
});
|
|
1189
|
-
expect(device.requestMTU).toHaveBeenCalledTimes(
|
|
1201
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(2);
|
|
1190
1202
|
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(writesBeforeFileWrite);
|
|
1191
1203
|
await transport.release(uuid, true);
|
|
1192
1204
|
});
|
|
@@ -1456,9 +1468,17 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1456
1468
|
test('uses Android 517 MTU and high connection priority during Protocol V2 high-volume calls', async () => {
|
|
1457
1469
|
setPlatformOS('android');
|
|
1458
1470
|
const { transport, uuid, device } = createHarness();
|
|
1471
|
+
device.mtu = 23;
|
|
1472
|
+
device.requestMTU.mockImplementationOnce(() => {
|
|
1473
|
+
device.mtu = 517;
|
|
1474
|
+
return Promise.resolve(device);
|
|
1475
|
+
});
|
|
1459
1476
|
|
|
1460
1477
|
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
1461
|
-
expect(device.requestMTU).toHaveBeenCalledWith(
|
|
1478
|
+
expect(device.requestMTU).toHaveBeenCalledWith(
|
|
1479
|
+
517,
|
|
1480
|
+
expect.stringContaining(`${uuid}:mtu:connected:0:`)
|
|
1481
|
+
);
|
|
1462
1482
|
|
|
1463
1483
|
await transport.call(uuid, 'FileWrite', {});
|
|
1464
1484
|
await transport.call(uuid, 'FileWrite', {});
|
package/src/index.ts
CHANGED
|
@@ -242,13 +242,13 @@ function getDeviceDisplayName(device?: Device | null) {
|
|
|
242
242
|
|
|
243
243
|
const IOS_REQUEST_MTU = 247;
|
|
244
244
|
const ANDROID_REQUEST_MTU = 517;
|
|
245
|
-
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
246
245
|
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
247
246
|
|
|
248
247
|
const getRequestedBleMtu = () =>
|
|
249
248
|
Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
250
249
|
|
|
251
250
|
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
251
|
+
const BLE_MTU_REQUEST_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS;
|
|
252
252
|
|
|
253
253
|
const connectOptions: Record<string, unknown> = {
|
|
254
254
|
requestMTU: getRequestedBleMtu(),
|
|
@@ -314,17 +314,50 @@ const tryToGetConfiguration = (device: Device) => {
|
|
|
314
314
|
|
|
315
315
|
const requestNegotiatedMtu = async (
|
|
316
316
|
device: Device,
|
|
317
|
-
stage: 'connected' | '
|
|
318
|
-
attempt: number
|
|
317
|
+
stage: 'connected' | 'highThroughput',
|
|
318
|
+
attempt: number,
|
|
319
|
+
cancelTransaction?: (transactionId: string) => Promise<void> | void
|
|
319
320
|
) => {
|
|
320
321
|
if (Platform.OS !== 'ios' && Platform.OS !== 'android') return device;
|
|
321
322
|
|
|
323
|
+
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
324
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
325
|
+
let timedOut = false;
|
|
326
|
+
|
|
322
327
|
try {
|
|
323
328
|
// iOS ignores the requested value but react-native-ble-plx returns a fresh
|
|
324
329
|
// Device snapshot whose MTU is derived from CoreBluetooth's maximum write length.
|
|
325
|
-
const
|
|
330
|
+
const request = device.requestMTU(getRequestedBleMtu(), transactionId);
|
|
331
|
+
const mtuDevice = await Promise.race([
|
|
332
|
+
request,
|
|
333
|
+
new Promise<never>((_, reject) => {
|
|
334
|
+
timeoutId = setTimeout(() => {
|
|
335
|
+
timedOut = true;
|
|
336
|
+
reject(new Error(`BLE MTU request timeout after ${BLE_MTU_REQUEST_TIMEOUT_MS}ms`));
|
|
337
|
+
}, BLE_MTU_REQUEST_TIMEOUT_MS);
|
|
338
|
+
}),
|
|
339
|
+
]);
|
|
326
340
|
return mtuDevice;
|
|
327
341
|
} catch (error) {
|
|
342
|
+
if (timedOut && cancelTransaction) {
|
|
343
|
+
try {
|
|
344
|
+
Promise.resolve(cancelTransaction(transactionId)).catch(cancelError => {
|
|
345
|
+
Log?.debug('[ReactNativeBleTransport] MTU cancellation failed', {
|
|
346
|
+
platform: Platform.OS,
|
|
347
|
+
stage,
|
|
348
|
+
attempt,
|
|
349
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError),
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
} catch (cancelError) {
|
|
353
|
+
Log?.debug('[ReactNativeBleTransport] MTU cancellation failed', {
|
|
354
|
+
platform: Platform.OS,
|
|
355
|
+
stage,
|
|
356
|
+
attempt,
|
|
357
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError),
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
328
361
|
Log?.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
329
362
|
platform: Platform.OS,
|
|
330
363
|
stage,
|
|
@@ -333,10 +366,18 @@ const requestNegotiatedMtu = async (
|
|
|
333
366
|
error: error instanceof Error ? error.message : String(error),
|
|
334
367
|
});
|
|
335
368
|
return device;
|
|
369
|
+
} finally {
|
|
370
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
336
371
|
}
|
|
337
372
|
};
|
|
338
373
|
|
|
339
|
-
const resolveNegotiatedMtu = (
|
|
374
|
+
const resolveNegotiatedMtu = (
|
|
375
|
+
device: Device,
|
|
376
|
+
cancelTransaction?: (transactionId: string) => Promise<void> | void
|
|
377
|
+
) =>
|
|
378
|
+
shouldRefreshNegotiatedMtu(device.mtu)
|
|
379
|
+
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
380
|
+
: Promise.resolve(device);
|
|
340
381
|
|
|
341
382
|
type IOBleErrorRemap = Error | BleError | null | undefined;
|
|
342
383
|
|
|
@@ -926,41 +967,10 @@ export default class ReactNativeBleTransport {
|
|
|
926
967
|
}
|
|
927
968
|
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
928
969
|
|
|
929
|
-
const initialMtu = transport.mtuSize;
|
|
930
|
-
let refreshAttempts = 0;
|
|
931
|
-
if (
|
|
932
|
-
(Platform.OS === 'ios' || Platform.OS === 'android') &&
|
|
933
|
-
shouldRefreshNegotiatedMtu(transport.mtuSize)
|
|
934
|
-
) {
|
|
935
|
-
refreshAttempts += 1;
|
|
936
|
-
let refreshedDevice = await requestNegotiatedMtu(
|
|
937
|
-
transport.device,
|
|
938
|
-
'servicesAndNotifyReady',
|
|
939
|
-
1
|
|
940
|
-
);
|
|
941
|
-
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
942
|
-
transport.device = refreshedDevice;
|
|
943
|
-
transport.mtuSize =
|
|
944
|
-
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
945
|
-
|
|
946
|
-
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
947
|
-
await delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
948
|
-
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
949
|
-
refreshAttempts += 1;
|
|
950
|
-
refreshedDevice = await requestNegotiatedMtu(transport.device, 'servicesAndNotifyReady', 2);
|
|
951
|
-
transport.device = refreshedDevice;
|
|
952
|
-
transport.mtuSize =
|
|
953
|
-
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
958
970
|
Log?.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
959
971
|
platform: Platform.OS,
|
|
960
972
|
requested: getRequestedBleMtu(),
|
|
961
|
-
initial: initialMtu,
|
|
962
973
|
actual: transport.mtuSize,
|
|
963
|
-
refreshAttempts,
|
|
964
974
|
});
|
|
965
975
|
|
|
966
976
|
return transport;
|
|
@@ -1188,7 +1198,9 @@ export default class ReactNativeBleTransport {
|
|
|
1188
1198
|
throw ERRORS.TypedError(HardwareErrorCode.BleConnectedError, 'device is not connected');
|
|
1189
1199
|
}
|
|
1190
1200
|
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
1191
|
-
device = await resolveNegotiatedMtu(device
|
|
1201
|
+
device = await resolveNegotiatedMtu(device, transactionId =>
|
|
1202
|
+
blePlxManager.cancelTransaction(transactionId)
|
|
1203
|
+
);
|
|
1192
1204
|
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
1193
1205
|
const acquiredDevice = device;
|
|
1194
1206
|
const { writeCharacteristic, notifyCharacteristic } =
|
|
@@ -2821,7 +2833,12 @@ export default class ReactNativeBleTransport {
|
|
|
2821
2833
|
const transport = this.getCachedTransport(uuid);
|
|
2822
2834
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize)) return;
|
|
2823
2835
|
|
|
2824
|
-
const refreshedDevice = await requestNegotiatedMtu(
|
|
2836
|
+
const refreshedDevice = await requestNegotiatedMtu(
|
|
2837
|
+
transport.device,
|
|
2838
|
+
'highThroughput',
|
|
2839
|
+
1,
|
|
2840
|
+
transactionId => this.blePlxManager?.cancelTransaction(transactionId)
|
|
2841
|
+
);
|
|
2825
2842
|
transport.device = refreshedDevice;
|
|
2826
2843
|
transport.mtuSize =
|
|
2827
2844
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|