@onekeyfe/hd-transport-react-native 1.2.2-alpha.112 → 1.2.2-alpha.114
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 +31 -10
- package/package.json +5 -5
- package/src/__tests__/protocolV2Link.test.ts +33 -0
- package/src/index.ts +49 -18
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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -446,6 +446,11 @@ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? v
|
|
|
446
446
|
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
447
447
|
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
448
448
|
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
449
|
+
const isMtuOrCancelledConnectError = (error) => {
|
|
450
|
+
const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
451
|
+
return (errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
452
|
+
errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled);
|
|
453
|
+
};
|
|
449
454
|
const tryToGetConfiguration = (device) => {
|
|
450
455
|
if (!device || !device.serviceUUIDs)
|
|
451
456
|
return null;
|
|
@@ -459,12 +464,13 @@ const tryToGetConfiguration = (device) => {
|
|
|
459
464
|
};
|
|
460
465
|
const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
461
466
|
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
462
|
-
return device;
|
|
467
|
+
return { device, timedOut: false };
|
|
463
468
|
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
464
469
|
let timeoutId;
|
|
465
470
|
let timedOut = false;
|
|
466
471
|
try {
|
|
467
472
|
const request = device.requestMTU(getRequestedBleMtu(), transactionId);
|
|
473
|
+
request.catch(() => undefined);
|
|
468
474
|
const mtuDevice = yield Promise.race([
|
|
469
475
|
request,
|
|
470
476
|
new Promise((_, reject) => {
|
|
@@ -474,7 +480,7 @@ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __aw
|
|
|
474
480
|
}, BLE_MTU_REQUEST_TIMEOUT_MS);
|
|
475
481
|
}),
|
|
476
482
|
]);
|
|
477
|
-
return mtuDevice;
|
|
483
|
+
return { device: mtuDevice, timedOut: false };
|
|
478
484
|
}
|
|
479
485
|
catch (error) {
|
|
480
486
|
if (timedOut && cancelTransaction) {
|
|
@@ -502,9 +508,10 @@ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __aw
|
|
|
502
508
|
stage,
|
|
503
509
|
attempt,
|
|
504
510
|
actual: device.mtu,
|
|
511
|
+
timedOut,
|
|
505
512
|
error: error instanceof Error ? error.message : String(error),
|
|
506
513
|
});
|
|
507
|
-
return device;
|
|
514
|
+
return { device, timedOut };
|
|
508
515
|
}
|
|
509
516
|
finally {
|
|
510
517
|
if (timeoutId)
|
|
@@ -513,7 +520,7 @@ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __aw
|
|
|
513
520
|
});
|
|
514
521
|
const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
|
|
515
522
|
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
516
|
-
: Promise.resolve(device);
|
|
523
|
+
: Promise.resolve({ device, timedOut: false });
|
|
517
524
|
function remapError(error) {
|
|
518
525
|
var _a;
|
|
519
526
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -1044,6 +1051,7 @@ class ReactNativeBleTransport {
|
|
|
1044
1051
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
1045
1052
|
}
|
|
1046
1053
|
const blePlxManager = yield this.getPlxManager();
|
|
1054
|
+
let skipPostConnectMtu = false;
|
|
1047
1055
|
try {
|
|
1048
1056
|
yield subscribeBleOn(blePlxManager);
|
|
1049
1057
|
}
|
|
@@ -1092,8 +1100,8 @@ class ReactNativeBleTransport {
|
|
|
1092
1100
|
if (shouldRethrowBleSetupError(e)) {
|
|
1093
1101
|
throw e;
|
|
1094
1102
|
}
|
|
1095
|
-
if (e
|
|
1096
|
-
|
|
1103
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1104
|
+
skipPostConnectMtu = true;
|
|
1097
1105
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
1098
1106
|
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
1099
1107
|
}
|
|
@@ -1120,8 +1128,8 @@ class ReactNativeBleTransport {
|
|
|
1120
1128
|
if (shouldRethrowBleSetupError(e)) {
|
|
1121
1129
|
throw e;
|
|
1122
1130
|
}
|
|
1123
|
-
if (e
|
|
1124
|
-
|
|
1131
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1132
|
+
skipPostConnectMtu = true;
|
|
1125
1133
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
1126
1134
|
try {
|
|
1127
1135
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
@@ -1157,7 +1165,20 @@ class ReactNativeBleTransport {
|
|
|
1157
1165
|
}
|
|
1158
1166
|
if (this.stopped)
|
|
1159
1167
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1160
|
-
|
|
1168
|
+
if (!skipPostConnectMtu) {
|
|
1169
|
+
const mtuResult = yield resolveNegotiatedMtu(device, transactionId => blePlxManager.cancelTransaction(transactionId));
|
|
1170
|
+
device = mtuResult.device;
|
|
1171
|
+
if (mtuResult.timedOut) {
|
|
1172
|
+
if (this.stopped)
|
|
1173
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1174
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] post-connect MTU timed out, reconnecting without requesting MTU');
|
|
1175
|
+
const timedOutDevice = device;
|
|
1176
|
+
yield this.runBestEffortNativeOperation('mtu timeout: cancel device connection', () => timedOutDevice.cancelConnection());
|
|
1177
|
+
if (this.stopped)
|
|
1178
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1179
|
+
device = yield this.connectWithTimeout(uuid, () => timedOutDevice.connect(fallbackConnectOptions));
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1161
1182
|
if (this.stopped)
|
|
1162
1183
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1163
1184
|
const acquiredDevice = device;
|
|
@@ -2457,7 +2478,7 @@ class ReactNativeBleTransport {
|
|
|
2457
2478
|
const transport = this.getCachedTransport(uuid);
|
|
2458
2479
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2459
2480
|
return;
|
|
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); });
|
|
2481
|
+
const { device: refreshedDevice } = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1, transactionId => { var _a; return (_a = this.blePlxManager) === null || _a === void 0 ? void 0 : _a.cancelTransaction(transactionId); });
|
|
2461
2482
|
transport.device = refreshedDevice;
|
|
2462
2483
|
transport.mtuSize =
|
|
2463
2484
|
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.114",
|
|
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.114",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.114",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.114",
|
|
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": "6490382eeeb6bda264b71c7e9bf96143840ee1cb"
|
|
30
30
|
}
|
|
@@ -169,11 +169,13 @@ const createHarness = ({
|
|
|
169
169
|
serviceUUIDs: ['00000001-0000-1000-8000-00805f9b34fb'],
|
|
170
170
|
isConnected: jest.fn(() => Promise.resolve(true)),
|
|
171
171
|
cancelConnection: jest.fn(() => Promise.resolve()),
|
|
172
|
+
connect: jest.fn(),
|
|
172
173
|
onDisconnected: jest.fn(callback => {
|
|
173
174
|
disconnectCallback = callback;
|
|
174
175
|
return { remove: jest.fn() };
|
|
175
176
|
}),
|
|
176
177
|
} as any;
|
|
178
|
+
device.connect.mockResolvedValue(device);
|
|
177
179
|
device.requestMTU = jest.fn(() => Promise.resolve(device));
|
|
178
180
|
device.requestConnectionPriority = jest.fn(() => Promise.resolve(device));
|
|
179
181
|
const bleManager = {
|
|
@@ -1138,10 +1140,41 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1138
1140
|
const transactionId = device.requestMTU.mock.calls[0]?.[1];
|
|
1139
1141
|
expect(transactionId).toEqual(expect.stringContaining(`${uuid}:mtu:connected:0:`));
|
|
1140
1142
|
expect(bleManager.cancelTransaction).toHaveBeenCalledWith(transactionId);
|
|
1143
|
+
expect(device.cancelConnection).toHaveBeenCalled();
|
|
1144
|
+
expect(device.connect).toHaveBeenCalledWith(
|
|
1145
|
+
expect.objectContaining({ timeout: expect.any(Number) })
|
|
1146
|
+
);
|
|
1147
|
+
expect(device.connect.mock.calls.at(-1)?.[0]).not.toHaveProperty('requestMTU');
|
|
1148
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(1);
|
|
1141
1149
|
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(23);
|
|
1142
1150
|
await transport.release(uuid, true);
|
|
1143
1151
|
}, 10_000);
|
|
1144
1152
|
|
|
1153
|
+
test('does not request MTU again after connect falls back without requestMTU', async () => {
|
|
1154
|
+
const { BleError: BleErrorMock, BleErrorCode } = jest.requireMock('react-native-ble-plx');
|
|
1155
|
+
const { transport, uuid, device } = createHarness();
|
|
1156
|
+
device.mtu = 23;
|
|
1157
|
+
device.isConnected.mockResolvedValueOnce(false).mockResolvedValue(true);
|
|
1158
|
+
device.connect
|
|
1159
|
+
.mockRejectedValueOnce(
|
|
1160
|
+
Object.assign(new BleErrorMock('Operation was cancelled'), {
|
|
1161
|
+
errorCode: BleErrorCode.OperationCancelled,
|
|
1162
|
+
})
|
|
1163
|
+
)
|
|
1164
|
+
.mockResolvedValue(device);
|
|
1165
|
+
|
|
1166
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
1167
|
+
uuid,
|
|
1168
|
+
protocolType: 'V2',
|
|
1169
|
+
});
|
|
1170
|
+
expect(device.connect).toHaveBeenCalledTimes(2);
|
|
1171
|
+
expect(device.connect.mock.calls[0][0]).toEqual(expect.objectContaining({ requestMTU: 247 }));
|
|
1172
|
+
expect(device.connect.mock.calls[1][0]).not.toHaveProperty('requestMTU');
|
|
1173
|
+
expect(device.requestMTU).not.toHaveBeenCalled();
|
|
1174
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(23);
|
|
1175
|
+
await transport.release(uuid, true);
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1145
1178
|
test('accepts a stable low MTU without the delayed refresh loop', async () => {
|
|
1146
1179
|
const { transport, uuid, device } = createHarness();
|
|
1147
1180
|
device.mtu = 185;
|
package/src/index.ts
CHANGED
|
@@ -300,6 +300,15 @@ const shouldRethrowBleSetupError = (error: unknown): boolean =>
|
|
|
300
300
|
isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
301
301
|
const isNativeOperationTimeoutError = (error: unknown): boolean =>
|
|
302
302
|
(error as { errorCode?: unknown })?.errorCode === BleErrorCode.OperationTimedOut;
|
|
303
|
+
const isMtuOrCancelledConnectError = (error: unknown): boolean => {
|
|
304
|
+
const errorCode = (error as { errorCode?: unknown })?.errorCode;
|
|
305
|
+
return (
|
|
306
|
+
errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
307
|
+
errorCode === BleErrorCode.OperationCancelled
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
type NegotiatedMtuResult = { device: Device; timedOut: boolean };
|
|
303
312
|
|
|
304
313
|
export type IOneKeyDevice = OneKeyDeviceInfoBase & Device;
|
|
305
314
|
|
|
@@ -317,8 +326,8 @@ const requestNegotiatedMtu = async (
|
|
|
317
326
|
stage: 'connected' | 'highThroughput',
|
|
318
327
|
attempt: number,
|
|
319
328
|
cancelTransaction?: (transactionId: string) => Promise<void> | void
|
|
320
|
-
) => {
|
|
321
|
-
if (Platform.OS !== 'ios' && Platform.OS !== 'android') return device;
|
|
329
|
+
): Promise<NegotiatedMtuResult> => {
|
|
330
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') return { device, timedOut: false };
|
|
322
331
|
|
|
323
332
|
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
324
333
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -328,6 +337,10 @@ const requestNegotiatedMtu = async (
|
|
|
328
337
|
// iOS ignores the requested value but react-native-ble-plx returns a fresh
|
|
329
338
|
// Device snapshot whose MTU is derived from CoreBluetooth's maximum write length.
|
|
330
339
|
const request = device.requestMTU(getRequestedBleMtu(), transactionId);
|
|
340
|
+
// The timeout race may settle before the native request does. Attach a
|
|
341
|
+
// rejection handler so a late native cancellation cannot become an
|
|
342
|
+
// unhandled rejection after we continue with the current MTU.
|
|
343
|
+
request.catch(() => undefined);
|
|
331
344
|
const mtuDevice = await Promise.race([
|
|
332
345
|
request,
|
|
333
346
|
new Promise<never>((_, reject) => {
|
|
@@ -337,7 +350,7 @@ const requestNegotiatedMtu = async (
|
|
|
337
350
|
}, BLE_MTU_REQUEST_TIMEOUT_MS);
|
|
338
351
|
}),
|
|
339
352
|
]);
|
|
340
|
-
return mtuDevice;
|
|
353
|
+
return { device: mtuDevice, timedOut: false };
|
|
341
354
|
} catch (error) {
|
|
342
355
|
if (timedOut && cancelTransaction) {
|
|
343
356
|
try {
|
|
@@ -363,9 +376,10 @@ const requestNegotiatedMtu = async (
|
|
|
363
376
|
stage,
|
|
364
377
|
attempt,
|
|
365
378
|
actual: device.mtu,
|
|
379
|
+
timedOut,
|
|
366
380
|
error: error instanceof Error ? error.message : String(error),
|
|
367
381
|
});
|
|
368
|
-
return device;
|
|
382
|
+
return { device, timedOut };
|
|
369
383
|
} finally {
|
|
370
384
|
if (timeoutId) clearTimeout(timeoutId);
|
|
371
385
|
}
|
|
@@ -374,10 +388,10 @@ const requestNegotiatedMtu = async (
|
|
|
374
388
|
const resolveNegotiatedMtu = (
|
|
375
389
|
device: Device,
|
|
376
390
|
cancelTransaction?: (transactionId: string) => Promise<void> | void
|
|
377
|
-
) =>
|
|
391
|
+
): Promise<NegotiatedMtuResult> =>
|
|
378
392
|
shouldRefreshNegotiatedMtu(device.mtu)
|
|
379
393
|
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
380
|
-
: Promise.resolve(device);
|
|
394
|
+
: Promise.resolve({ device, timedOut: false });
|
|
381
395
|
|
|
382
396
|
type IOBleErrorRemap = Error | BleError | null | undefined;
|
|
383
397
|
|
|
@@ -1068,6 +1082,7 @@ export default class ReactNativeBleTransport {
|
|
|
1068
1082
|
}
|
|
1069
1083
|
|
|
1070
1084
|
const blePlxManager = await this.getPlxManager();
|
|
1085
|
+
let skipPostConnectMtu = false;
|
|
1071
1086
|
try {
|
|
1072
1087
|
await subscribeBleOn(blePlxManager);
|
|
1073
1088
|
} catch (error) {
|
|
@@ -1119,10 +1134,8 @@ export default class ReactNativeBleTransport {
|
|
|
1119
1134
|
if (shouldRethrowBleSetupError(e)) {
|
|
1120
1135
|
throw e;
|
|
1121
1136
|
}
|
|
1122
|
-
if (
|
|
1123
|
-
|
|
1124
|
-
e.errorCode === BleErrorCode.OperationCancelled
|
|
1125
|
-
) {
|
|
1137
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1138
|
+
skipPostConnectMtu = true;
|
|
1126
1139
|
Log?.debug('first try to reconnect without params');
|
|
1127
1140
|
device = await this.connectWithTimeout(uuid, () =>
|
|
1128
1141
|
blePlxManager.connectToDevice(uuid, fallbackConnectOptions)
|
|
@@ -1153,10 +1166,8 @@ export default class ReactNativeBleTransport {
|
|
|
1153
1166
|
if (shouldRethrowBleSetupError(e)) {
|
|
1154
1167
|
throw e;
|
|
1155
1168
|
}
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1158
|
-
e.errorCode === BleErrorCode.OperationCancelled
|
|
1159
|
-
) {
|
|
1169
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1170
|
+
skipPostConnectMtu = true;
|
|
1160
1171
|
Log?.debug('second try to reconnect without params');
|
|
1161
1172
|
try {
|
|
1162
1173
|
device = await this.connectWithTimeout(uuid, () =>
|
|
@@ -1198,9 +1209,29 @@ export default class ReactNativeBleTransport {
|
|
|
1198
1209
|
throw ERRORS.TypedError(HardwareErrorCode.BleConnectedError, 'device is not connected');
|
|
1199
1210
|
}
|
|
1200
1211
|
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1212
|
+
// Match 1.1.31: MTU is a connect() best-effort. If connect already fell back
|
|
1213
|
+
// without requestMTU, do not put another requestMTU on the native serial
|
|
1214
|
+
// queue — that is what wedges GATT after Account#2 reconnect.
|
|
1215
|
+
if (!skipPostConnectMtu) {
|
|
1216
|
+
const mtuResult = await resolveNegotiatedMtu(device, transactionId =>
|
|
1217
|
+
blePlxManager.cancelTransaction(transactionId)
|
|
1218
|
+
);
|
|
1219
|
+
device = mtuResult.device;
|
|
1220
|
+
if (mtuResult.timedOut) {
|
|
1221
|
+
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
1222
|
+
Log?.debug(
|
|
1223
|
+
'[ReactNativeBleTransport] post-connect MTU timed out, reconnecting without requesting MTU'
|
|
1224
|
+
);
|
|
1225
|
+
const timedOutDevice = device;
|
|
1226
|
+
await this.runBestEffortNativeOperation('mtu timeout: cancel device connection', () =>
|
|
1227
|
+
timedOutDevice.cancelConnection()
|
|
1228
|
+
);
|
|
1229
|
+
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
1230
|
+
device = await this.connectWithTimeout(uuid, () =>
|
|
1231
|
+
timedOutDevice.connect(fallbackConnectOptions)
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1204
1235
|
if (this.stopped) throw ERRORS.TypedError(HardwareErrorCode.BleDeviceDisconnected);
|
|
1205
1236
|
const acquiredDevice = device;
|
|
1206
1237
|
const { writeCharacteristic, notifyCharacteristic } =
|
|
@@ -2833,7 +2864,7 @@ export default class ReactNativeBleTransport {
|
|
|
2833
2864
|
const transport = this.getCachedTransport(uuid);
|
|
2834
2865
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize)) return;
|
|
2835
2866
|
|
|
2836
|
-
const refreshedDevice = await requestNegotiatedMtu(
|
|
2867
|
+
const { device: refreshedDevice } = await requestNegotiatedMtu(
|
|
2837
2868
|
transport.device,
|
|
2838
2869
|
'highThroughput',
|
|
2839
2870
|
1,
|