@onekeyfe/hd-transport-react-native 1.2.2-alpha.110 → 1.2.2-alpha.111
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 +20 -7
- package/package.json +5 -5
- package/src/__tests__/protocolV2Link.test.ts +184 -7
- package/src/index.ts +25 -5
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -529,11 +529,20 @@ class ReactNativeBleTransport {
|
|
|
529
529
|
},
|
|
530
530
|
classifyError: () => 'link-fatal',
|
|
531
531
|
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
532
|
-
var _b;
|
|
532
|
+
var _b, _c;
|
|
533
533
|
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
534
534
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
535
535
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
536
536
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
537
|
+
if (this.probingProtocols.get(uuid) !== 'V2') {
|
|
538
|
+
const transport = transportCache[uuid];
|
|
539
|
+
try {
|
|
540
|
+
this.emitDeviceDisconnect(uuid, (_c = transport === null || transport === void 0 ? void 0 : transport.device) === null || _c === void 0 ? void 0 : _c.name, transport === null || transport === void 0 ? void 0 : transport.monitorToken);
|
|
541
|
+
}
|
|
542
|
+
catch (_d) {
|
|
543
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 disconnect listener failed');
|
|
544
|
+
}
|
|
545
|
+
}
|
|
537
546
|
yield this.releaseNative(uuid, true);
|
|
538
547
|
}
|
|
539
548
|
}),
|
|
@@ -1195,12 +1204,7 @@ class ReactNativeBleTransport {
|
|
|
1195
1204
|
return { uuid, protocolType };
|
|
1196
1205
|
}
|
|
1197
1206
|
catch (error) {
|
|
1198
|
-
|
|
1199
|
-
yield this.disconnectUnlocked(uuid);
|
|
1200
|
-
}
|
|
1201
|
-
else {
|
|
1202
|
-
yield this.releaseUnlocked(uuid, true);
|
|
1203
|
-
}
|
|
1207
|
+
yield this.disconnectUnlocked(uuid);
|
|
1204
1208
|
throw error;
|
|
1205
1209
|
}
|
|
1206
1210
|
finally {
|
|
@@ -2378,6 +2382,7 @@ class ReactNativeBleTransport {
|
|
|
2378
2382
|
if (!this._messages || !this._messagesV2) {
|
|
2379
2383
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
2380
2384
|
}
|
|
2385
|
+
const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
|
|
2381
2386
|
const callOptions = options;
|
|
2382
2387
|
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
2383
2388
|
if (highThroughputWrite) {
|
|
@@ -2418,6 +2423,14 @@ class ReactNativeBleTransport {
|
|
|
2418
2423
|
}
|
|
2419
2424
|
catch (e) {
|
|
2420
2425
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
2426
|
+
if (!isProtocolProbe &&
|
|
2427
|
+
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError &&
|
|
2428
|
+
!this.monitorTokens.has(uuid)) {
|
|
2429
|
+
yield this.runLifecycleOperation(uuid, () => __awaiter(this, void 0, void 0, function* () {
|
|
2430
|
+
if (!this.monitorTokens.has(uuid))
|
|
2431
|
+
yield this.disconnectUnlocked(uuid);
|
|
2432
|
+
}));
|
|
2433
|
+
}
|
|
2421
2434
|
throw e;
|
|
2422
2435
|
}
|
|
2423
2436
|
finally {
|
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.111",
|
|
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.111",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.111",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.111",
|
|
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": "a87be5a4ae4b59f91f853a9873a9e8e924bbdfd6"
|
|
30
30
|
}
|
|
@@ -714,7 +714,72 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
714
714
|
});
|
|
715
715
|
|
|
716
716
|
test.each(['ios', 'android'] as const)(
|
|
717
|
-
'
|
|
717
|
+
'waits for native disconnect after failed protocol detection before reconnecting on %s',
|
|
718
|
+
async platform => {
|
|
719
|
+
setPlatformOS(platform);
|
|
720
|
+
const { transport, uuid, device, bleManager } = createHarness();
|
|
721
|
+
const probes = transport as unknown as {
|
|
722
|
+
probeProtocolV1(uuid: string): Promise<boolean>;
|
|
723
|
+
probeProtocolV2(uuid: string): Promise<boolean>;
|
|
724
|
+
releaseNative(uuid: string, onclose: boolean): Promise<void>;
|
|
725
|
+
};
|
|
726
|
+
jest.spyOn(probes, 'probeProtocolV1').mockResolvedValueOnce(false);
|
|
727
|
+
const probesFinished = createDeferred<void>();
|
|
728
|
+
const probeProtocolV2 = jest
|
|
729
|
+
.spyOn(probes, 'probeProtocolV2')
|
|
730
|
+
.mockImplementationOnce(async () => {
|
|
731
|
+
// A link-fatal V2 timeout removes the cached transport before acquire fails.
|
|
732
|
+
await probes.releaseNative(uuid, true);
|
|
733
|
+
probesFinished.resolve();
|
|
734
|
+
return false;
|
|
735
|
+
});
|
|
736
|
+
let connected = true;
|
|
737
|
+
device.isConnected.mockImplementation(() => Promise.resolve(connected));
|
|
738
|
+
device.connect = jest.fn(() => {
|
|
739
|
+
connected = true;
|
|
740
|
+
return Promise.resolve(device);
|
|
741
|
+
});
|
|
742
|
+
const disconnectGate = createDeferred<void>();
|
|
743
|
+
bleManager.cancelDeviceConnection.mockImplementation(async () => {
|
|
744
|
+
await disconnectGate.promise;
|
|
745
|
+
connected = false;
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
const acquiring = transport.acquire({ uuid });
|
|
749
|
+
const failure = expect(acquiring).rejects.toMatchObject({
|
|
750
|
+
errorCode: HardwareErrorCode.BleTimeoutError,
|
|
751
|
+
});
|
|
752
|
+
const reconnecting = transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
753
|
+
|
|
754
|
+
try {
|
|
755
|
+
await probesFinished.promise;
|
|
756
|
+
await new Promise(resolve => {
|
|
757
|
+
setImmediate(resolve);
|
|
758
|
+
});
|
|
759
|
+
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(uuid);
|
|
760
|
+
expect(device.connect).not.toHaveBeenCalled();
|
|
761
|
+
expect(probeProtocolV2).toHaveBeenCalledTimes(1);
|
|
762
|
+
|
|
763
|
+
disconnectGate.resolve();
|
|
764
|
+
await failure;
|
|
765
|
+
await expect(reconnecting).resolves.toEqual({ uuid, protocolType: 'V2' });
|
|
766
|
+
expect(device.connect).toHaveBeenCalledTimes(1);
|
|
767
|
+
await expect(
|
|
768
|
+
transport.call(uuid, 'Ping', { message: 'after-reconnect' })
|
|
769
|
+
).resolves.toMatchObject({
|
|
770
|
+
type: 'Success',
|
|
771
|
+
message: { message: 'ok' },
|
|
772
|
+
});
|
|
773
|
+
} finally {
|
|
774
|
+
disconnectGate.resolve();
|
|
775
|
+
await Promise.allSettled([failure, reconnecting]);
|
|
776
|
+
await transport.release(uuid, true);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
test.each(['ios', 'android'] as const)(
|
|
782
|
+
'disconnects after a first expected Protocol V2 probe miss while keeping it retryable on %s',
|
|
718
783
|
async platform => {
|
|
719
784
|
setPlatformOS(platform);
|
|
720
785
|
const { transport, uuid, device } = createHarness();
|
|
@@ -724,13 +789,13 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
724
789
|
errorCode: HardwareErrorCode.RuntimeError,
|
|
725
790
|
});
|
|
726
791
|
|
|
727
|
-
expect(device.cancelConnection).
|
|
792
|
+
expect(device.cancelConnection).toHaveBeenCalledTimes(1);
|
|
728
793
|
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
729
794
|
}
|
|
730
795
|
);
|
|
731
796
|
|
|
732
797
|
test.each(['ios', 'android'] as const)(
|
|
733
|
-
'
|
|
798
|
+
'disconnects after each expected Protocol V2 probe miss while keeping it retryable on %s',
|
|
734
799
|
async platform => {
|
|
735
800
|
setPlatformOS(platform);
|
|
736
801
|
const { transport, uuid, device } = createHarness();
|
|
@@ -743,7 +808,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
743
808
|
errorCode: HardwareErrorCode.RuntimeError,
|
|
744
809
|
});
|
|
745
810
|
|
|
746
|
-
expect(device.cancelConnection).
|
|
811
|
+
expect(device.cancelConnection).toHaveBeenCalledTimes(2);
|
|
747
812
|
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
748
813
|
}
|
|
749
814
|
);
|
|
@@ -778,7 +843,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
778
843
|
);
|
|
779
844
|
|
|
780
845
|
test.each(['ios', 'android'] as const)(
|
|
781
|
-
'
|
|
846
|
+
'disconnects after a confirmed Protocol V2 probe miss on %s without reporting a bond error',
|
|
782
847
|
async platform => {
|
|
783
848
|
setPlatformOS(platform);
|
|
784
849
|
const { transport, uuid, device } = createHarness();
|
|
@@ -790,7 +855,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
790
855
|
errorCode: HardwareErrorCode.RuntimeError,
|
|
791
856
|
});
|
|
792
857
|
|
|
793
|
-
expect(device.cancelConnection).
|
|
858
|
+
expect(device.cancelConnection).toHaveBeenCalledTimes(1);
|
|
794
859
|
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
795
860
|
}
|
|
796
861
|
);
|
|
@@ -974,7 +1039,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
974
1039
|
test.each(['V1', 'V2'] as const)(
|
|
975
1040
|
'still falls back after a silent %s probe timeout',
|
|
976
1041
|
async protocol => {
|
|
977
|
-
const { transport, uuid } = createHarness();
|
|
1042
|
+
const { transport, uuid, device, bleManager } = createHarness();
|
|
978
1043
|
jest
|
|
979
1044
|
.spyOn(transport as any, protocol === 'V1' ? 'callProtocolV1' : 'callProtocolV2')
|
|
980
1045
|
.mockRejectedValue(ERRORS.TypedError(HardwareErrorCode.BleTimeoutError));
|
|
@@ -988,6 +1053,8 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
988
1053
|
});
|
|
989
1054
|
|
|
990
1055
|
expect(otherProbe).toHaveBeenCalledTimes(1);
|
|
1056
|
+
expect(bleManager.cancelDeviceConnection).not.toHaveBeenCalled();
|
|
1057
|
+
expect(device.cancelConnection).not.toHaveBeenCalled();
|
|
991
1058
|
await transport.release(uuid, true);
|
|
992
1059
|
}
|
|
993
1060
|
);
|
|
@@ -1173,6 +1240,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1173
1240
|
expect(notifySubscriptionRemovers[0]).toHaveBeenCalledTimes(1);
|
|
1174
1241
|
expect(notifySubscriptionRemovers[1]).toHaveBeenCalledTimes(1);
|
|
1175
1242
|
expect(bleManager.cancelTransaction).toHaveBeenCalled();
|
|
1243
|
+
expect(device.cancelConnection).toHaveBeenCalledTimes(1);
|
|
1176
1244
|
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
1177
1245
|
});
|
|
1178
1246
|
|
|
@@ -1227,6 +1295,115 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
1227
1295
|
});
|
|
1228
1296
|
});
|
|
1229
1297
|
|
|
1298
|
+
test.each(['ios', 'android'] as const)(
|
|
1299
|
+
'disconnects after an active V2 timeout and reconnects even if a listener fails on %s',
|
|
1300
|
+
async platform => {
|
|
1301
|
+
setPlatformOS(platform);
|
|
1302
|
+
const harness = createHarness();
|
|
1303
|
+
const { transport, uuid, device, bleManager, sentSeqs, emitter } = harness;
|
|
1304
|
+
const disconnected = jest.fn(() => {
|
|
1305
|
+
throw new Error('Disconnect listener failed');
|
|
1306
|
+
});
|
|
1307
|
+
emitter.on(TRANSPORT_EVENT.DEVICE_DISCONNECT, disconnected);
|
|
1308
|
+
let connected = true;
|
|
1309
|
+
device.isConnected.mockImplementation(() => Promise.resolve(connected));
|
|
1310
|
+
device.connect = jest.fn(() => {
|
|
1311
|
+
connected = true;
|
|
1312
|
+
return Promise.resolve(device);
|
|
1313
|
+
});
|
|
1314
|
+
bleManager.cancelDeviceConnection.mockImplementation(() => {
|
|
1315
|
+
connected = false;
|
|
1316
|
+
return Promise.resolve();
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
1320
|
+
harness.setShouldRespond(false);
|
|
1321
|
+
await expect(transport.call(uuid, 'Ping', {}, { timeoutMs: 10 })).rejects.toMatchObject({
|
|
1322
|
+
errorCode: HardwareErrorCode.BleTimeoutError,
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(uuid);
|
|
1326
|
+
expect(connected).toBe(false);
|
|
1327
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
1328
|
+
expect(disconnected).toHaveBeenCalledTimes(1);
|
|
1329
|
+
expect(disconnected).toHaveBeenCalledWith({
|
|
1330
|
+
id: uuid,
|
|
1331
|
+
connectId: uuid,
|
|
1332
|
+
name: device.name,
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
harness.setShouldRespond(true);
|
|
1336
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
1337
|
+
await expect(transport.call(uuid, 'Ping', {})).resolves.toMatchObject({ type: 'Success' });
|
|
1338
|
+
expect(device.connect).toHaveBeenCalledTimes(1);
|
|
1339
|
+
expect(sentSeqs).toEqual([1, 2, 3, 4]);
|
|
1340
|
+
await transport.release(uuid, true);
|
|
1341
|
+
}
|
|
1342
|
+
);
|
|
1343
|
+
|
|
1344
|
+
test('does not disconnect an active Protocol V2 call when a queued call times out', async () => {
|
|
1345
|
+
const harness = createHarness();
|
|
1346
|
+
const { transport, uuid, bleManager } = harness;
|
|
1347
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
1348
|
+
harness.setShouldRespond(false);
|
|
1349
|
+
const active = transport.call(uuid, 'Ping', {}, { timeoutMs: 1000 }).catch(error => error);
|
|
1350
|
+
await new Promise(resolve => {
|
|
1351
|
+
setImmediate(resolve);
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
try {
|
|
1355
|
+
await expect(transport.call(uuid, 'Ping', {}, { timeoutMs: 10 })).rejects.toMatchObject({
|
|
1356
|
+
errorCode: HardwareErrorCode.BleTimeoutError,
|
|
1357
|
+
});
|
|
1358
|
+
expect(bleManager.cancelDeviceConnection).not.toHaveBeenCalled();
|
|
1359
|
+
expect(transport.getProtocolType(uuid)).toBe('V2');
|
|
1360
|
+
} finally {
|
|
1361
|
+
await transport.disconnect(uuid);
|
|
1362
|
+
await active;
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
test('does not disconnect a newer acquire when V2 timeout cleanup waits for the lifecycle lock', async () => {
|
|
1367
|
+
const harness = createHarness();
|
|
1368
|
+
const { transport, uuid, bleManager } = harness;
|
|
1369
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
1370
|
+
const lifecycle = transport as unknown as {
|
|
1371
|
+
runLifecycleOperation(id: string, operation: () => Promise<void>): Promise<void>;
|
|
1372
|
+
releaseNative(id: string, onclose: boolean): Promise<boolean>;
|
|
1373
|
+
};
|
|
1374
|
+
const gate = createDeferred<void>();
|
|
1375
|
+
const holding = lifecycle.runLifecycleOperation(uuid, () => gate.promise);
|
|
1376
|
+
const reacquiring = transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
1377
|
+
const invalidated = createDeferred<void>();
|
|
1378
|
+
const releaseNative = lifecycle.releaseNative.bind(lifecycle);
|
|
1379
|
+
jest.spyOn(lifecycle, 'releaseNative').mockImplementationOnce(async (id, onclose) => {
|
|
1380
|
+
const result = await releaseNative(id, onclose);
|
|
1381
|
+
invalidated.resolve();
|
|
1382
|
+
return result;
|
|
1383
|
+
});
|
|
1384
|
+
harness.setShouldRespond(false);
|
|
1385
|
+
const failure = expect(
|
|
1386
|
+
transport.call(uuid, 'Ping', {}, { timeoutMs: 10 })
|
|
1387
|
+
).rejects.toMatchObject({
|
|
1388
|
+
errorCode: HardwareErrorCode.BleTimeoutError,
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1391
|
+
try {
|
|
1392
|
+
await invalidated.promise;
|
|
1393
|
+
harness.setShouldRespond(true);
|
|
1394
|
+
gate.resolve();
|
|
1395
|
+
await holding;
|
|
1396
|
+
await reacquiring;
|
|
1397
|
+
await failure;
|
|
1398
|
+
expect(bleManager.cancelDeviceConnection).not.toHaveBeenCalled();
|
|
1399
|
+
await expect(transport.call(uuid, 'Ping', {})).resolves.toMatchObject({ type: 'Success' });
|
|
1400
|
+
} finally {
|
|
1401
|
+
gate.resolve();
|
|
1402
|
+
await Promise.allSettled([holding, reacquiring, failure]);
|
|
1403
|
+
await transport.release(uuid, true);
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1230
1407
|
test('retains the sequence cursor when a new monitor generation is acquired', async () => {
|
|
1231
1408
|
const { transport, uuid, sentSeqs } = createHarness();
|
|
1232
1409
|
|
package/src/index.ts
CHANGED
|
@@ -452,6 +452,14 @@ export default class ReactNativeBleTransport {
|
|
|
452
452
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
453
453
|
Log?.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
454
454
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
455
|
+
if (this.probingProtocols.get(uuid) !== 'V2') {
|
|
456
|
+
const transport = transportCache[uuid];
|
|
457
|
+
try {
|
|
458
|
+
this.emitDeviceDisconnect(uuid, transport?.device?.name, transport?.monitorToken);
|
|
459
|
+
} catch {
|
|
460
|
+
Log?.error('[ReactNativeBleTransport] Protocol V2 disconnect listener failed');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
455
463
|
await this.releaseNative(uuid, true);
|
|
456
464
|
}
|
|
457
465
|
},
|
|
@@ -1255,11 +1263,9 @@ export default class ReactNativeBleTransport {
|
|
|
1255
1263
|
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
1256
1264
|
return { uuid, protocolType };
|
|
1257
1265
|
} catch (error) {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
await this.releaseUnlocked(uuid, true);
|
|
1262
|
-
}
|
|
1266
|
+
// A failed acquire must retire the physical link before Core retries. Logical
|
|
1267
|
+
// release leaves GATT connected even when neither protocol receives a response.
|
|
1268
|
+
await this.disconnectUnlocked(uuid);
|
|
1263
1269
|
throw error;
|
|
1264
1270
|
} finally {
|
|
1265
1271
|
this.acquiringProtocolV2.delete(uuid);
|
|
@@ -2738,6 +2744,7 @@ export default class ReactNativeBleTransport {
|
|
|
2738
2744
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
2739
2745
|
}
|
|
2740
2746
|
|
|
2747
|
+
const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
|
|
2741
2748
|
const callOptions = options;
|
|
2742
2749
|
const highThroughputWrite = isProtocolV2HighThroughputCall(name);
|
|
2743
2750
|
|
|
@@ -2789,6 +2796,19 @@ export default class ReactNativeBleTransport {
|
|
|
2789
2796
|
);
|
|
2790
2797
|
} catch (e) {
|
|
2791
2798
|
Log?.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
2799
|
+
if (
|
|
2800
|
+
!isProtocolProbe &&
|
|
2801
|
+
e?.errorCode === HardwareErrorCode.BleTimeoutError &&
|
|
2802
|
+
!this.monitorTokens.has(uuid)
|
|
2803
|
+
) {
|
|
2804
|
+
// The failed link has finished invalidating. Disconnect outside that
|
|
2805
|
+
// callback to avoid waiting on its own invalidation or acquire lock.
|
|
2806
|
+
await this.runLifecycleOperation(uuid, async () => {
|
|
2807
|
+
// A queued timeout leaves its active monitor intact; a newer acquire
|
|
2808
|
+
// may also have installed one while cleanup waited for the lifecycle lock.
|
|
2809
|
+
if (!this.monitorTokens.has(uuid)) await this.disconnectUnlocked(uuid);
|
|
2810
|
+
});
|
|
2811
|
+
}
|
|
2792
2812
|
throw e;
|
|
2793
2813
|
} finally {
|
|
2794
2814
|
if (highThroughputWrite) {
|