@onekeyfe/hd-transport-react-native 1.2.0-alpha.73 → 1.2.0-alpha.75
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.map +1 -1
- package/dist/index.d.ts +1 -88
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -298
- package/jest.config.js +0 -5
- package/package.json +5 -5
- package/src/BleTransport.ts +6 -9
- package/src/__tests__/BleTransport.test.ts +3 -24
- package/src/__tests__/protocolV2Link.test.ts +5 -35
- package/src/index.ts +39 -449
- 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/src/index.ts
CHANGED
|
@@ -142,22 +142,6 @@ const resolveFirmwareUploadRetryDelay = (attempt: number, baseDelayMs = 200, max
|
|
|
142
142
|
Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
|
|
143
143
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
144
144
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10_000;
|
|
145
|
-
/**
|
|
146
|
-
* Per-packet write budget. iOS only resolves writeWithoutResponse once CoreBluetooth
|
|
147
|
-
* reports the peripheral ready again; a peripheral wedged by its own firmware reboot
|
|
148
|
-
* stops reporting ready while staying connected, so the write promise never settles.
|
|
149
|
-
* Response timeouts cannot cover that — they are armed after the writes complete —
|
|
150
|
-
* and an unbounded write leaves the whole transport unusable until the process dies.
|
|
151
|
-
* A healthy packet completes in milliseconds, so this only fires on a dead link.
|
|
152
|
-
*/
|
|
153
|
-
export const BLE_WRITE_PACKET_TIMEOUT_MS = 10_000;
|
|
154
|
-
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
155
|
-
const isWedgedWriteError = (error: unknown): boolean =>
|
|
156
|
-
(error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleWriteCharacteristicError &&
|
|
157
|
-
typeof (error as { message?: unknown })?.message === 'string' &&
|
|
158
|
-
(error as { message: string }).message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
159
|
-
/** Consecutive wedged writes on one device before the BLE manager itself is recreated. */
|
|
160
|
-
export const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
161
145
|
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
162
146
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
163
147
|
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
@@ -220,52 +204,12 @@ const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
|
220
204
|
const getRequestedBleMtu = () =>
|
|
221
205
|
Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
222
206
|
|
|
223
|
-
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
224
|
-
|
|
225
207
|
const connectOptions: Record<string, unknown> = {
|
|
226
208
|
requestMTU: getRequestedBleMtu(),
|
|
227
|
-
timeout:
|
|
209
|
+
timeout: 3000,
|
|
228
210
|
refreshGatt: 'OnConnected',
|
|
229
211
|
};
|
|
230
212
|
|
|
231
|
-
/** Fallback connect options: drops requestMTU (the thing being worked around) but keeps the native budget. */
|
|
232
|
-
const fallbackConnectOptions: Record<string, unknown> = {
|
|
233
|
-
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* JS backstop for connect. The native adapter applies its own 3s budget, but it
|
|
238
|
-
* schedules that timeout on its serial queue, so a busy queue (e.g. right after a
|
|
239
|
-
* firmware install tears the link down) can leave the promise unsettled — observed
|
|
240
|
-
* blocking a reconnect for 61s until the app-level timeout. Healthy connects finish
|
|
241
|
-
* inside the native budget, so this only fires when the native timeout did not.
|
|
242
|
-
*/
|
|
243
|
-
export const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
244
|
-
/**
|
|
245
|
-
* Service discovery and characteristic resolution run after connect() succeeds, but
|
|
246
|
-
* CoreBluetooth schedules them on the same serial queue. If that queue is wedged by a
|
|
247
|
-
* device reboot, these calls can remain pending forever unless they have their own
|
|
248
|
-
* budget.
|
|
249
|
-
*/
|
|
250
|
-
export const BLE_GATT_SETUP_TIMEOUT_MS = 10_000;
|
|
251
|
-
/**
|
|
252
|
-
* How many times a known device may fail its own protocol before we probe the others
|
|
253
|
-
* again. Reconnect polling during a device reboot repeats this every few seconds, and
|
|
254
|
-
* probing Protocol V2 costs a 10s Ping timeout, so paying it on every attempt for a
|
|
255
|
-
* device we just spoke V1 to dominates the wait. A firmware update can legitimately
|
|
256
|
-
* change a device's protocol, so the shortcut has to expire rather than stick.
|
|
257
|
-
*/
|
|
258
|
-
export const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
259
|
-
/** BLE setup timeouts since the last successful setup before the manager is recreated. */
|
|
260
|
-
export const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
261
|
-
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
262
|
-
const isConnectTimeoutError = (error: unknown): boolean =>
|
|
263
|
-
(error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleConnectedError &&
|
|
264
|
-
typeof (error as { message?: unknown })?.message === 'string' &&
|
|
265
|
-
(error as { message: string }).message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
266
|
-
const isNativeOperationTimeoutError = (error: unknown): boolean =>
|
|
267
|
-
(error as { errorCode?: unknown })?.errorCode === BleErrorCode.OperationTimedOut;
|
|
268
|
-
|
|
269
213
|
export type IOneKeyDevice = OneKeyDeviceInfoBase & Device;
|
|
270
214
|
|
|
271
215
|
const tryToGetConfiguration = (device: Device) => {
|
|
@@ -363,28 +307,8 @@ export default class ReactNativeBleTransport {
|
|
|
363
307
|
/** Per-device protocol type detected by active wire-level probe after connect. */
|
|
364
308
|
private deviceProtocol: Map<string, ProtocolType> = new Map();
|
|
365
309
|
|
|
366
|
-
/**
|
|
367
|
-
* Protocol a probe is currently trying, before the device has confirmed it. Calls
|
|
368
|
-
* must route with it, but acquire() must not treat it as a detected protocol: a
|
|
369
|
-
* probe that never answers would otherwise leave the reuse fast path handing out a
|
|
370
|
-
* transport that was never validated.
|
|
371
|
-
*/
|
|
372
|
-
private probingProtocols: Map<string, ProtocolType> = new Map();
|
|
373
|
-
|
|
374
|
-
/** Consecutive write timeouts per device; reset by any write that completes. */
|
|
375
|
-
private writeTimeoutCounts: Map<string, number> = new Map();
|
|
376
|
-
|
|
377
|
-
/** BLE setup timeouts per device since the last complete characteristic resolution. */
|
|
378
|
-
private connectionSetupTimeoutCounts: Map<string, number> = new Map();
|
|
379
|
-
|
|
380
310
|
private deviceProtocolHints: Map<string, ProtocolType> = new Map();
|
|
381
311
|
|
|
382
|
-
/** Protocol this device actually answered on, kept across reconnects of one session. */
|
|
383
|
-
private sessionProtocols: Map<string, ProtocolType> = new Map();
|
|
384
|
-
|
|
385
|
-
/** Consecutive detections that failed while trusting sessionProtocols. */
|
|
386
|
-
private protocolReprobeFailures: Map<string, number> = new Map();
|
|
387
|
-
|
|
388
312
|
private protocolV2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
|
|
389
313
|
|
|
390
314
|
private protocolV2FrameQueues: Map<string, Uint8Array[]> = new Map();
|
|
@@ -608,21 +532,22 @@ export default class ReactNativeBleTransport {
|
|
|
608
532
|
const isConnected = await device.isConnected().catch(() => false);
|
|
609
533
|
if (!isConnected) {
|
|
610
534
|
try {
|
|
611
|
-
device = await
|
|
535
|
+
device = await device.connect(connectOptions);
|
|
612
536
|
} catch (e) {
|
|
613
537
|
if (
|
|
614
538
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
615
539
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
616
540
|
) {
|
|
617
|
-
device = await
|
|
541
|
+
device = await device.connect();
|
|
618
542
|
} else if (e.errorCode !== BleErrorCode.DeviceAlreadyConnected) {
|
|
619
543
|
throw e;
|
|
620
544
|
}
|
|
621
545
|
}
|
|
622
546
|
}
|
|
623
547
|
|
|
624
|
-
const { writeCharacteristic, notifyCharacteristic } =
|
|
625
|
-
|
|
548
|
+
const { writeCharacteristic, notifyCharacteristic } = await this.resolveCharacteristics(
|
|
549
|
+
device
|
|
550
|
+
);
|
|
626
551
|
|
|
627
552
|
transport.device = device;
|
|
628
553
|
transport.writeCharacteristic = writeCharacteristic;
|
|
@@ -801,7 +726,7 @@ export default class ReactNativeBleTransport {
|
|
|
801
726
|
characteristics?: ResolvedBleCharacteristics
|
|
802
727
|
) {
|
|
803
728
|
const { writeCharacteristic, notifyCharacteristic } =
|
|
804
|
-
characteristics ?? (await this.
|
|
729
|
+
characteristics ?? (await this.resolveCharacteristics(device));
|
|
805
730
|
const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
806
731
|
transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
807
732
|
const monitorToken = this.nextMonitorToken;
|
|
@@ -938,22 +863,15 @@ export default class ReactNativeBleTransport {
|
|
|
938
863
|
if (!device) {
|
|
939
864
|
Log?.debug('try to connect to device: ', uuid);
|
|
940
865
|
try {
|
|
941
|
-
device = await
|
|
942
|
-
blePlxManager.connectToDevice(uuid, connectOptions)
|
|
943
|
-
);
|
|
866
|
+
device = await blePlxManager.connectToDevice(uuid, connectOptions);
|
|
944
867
|
} catch (e) {
|
|
945
868
|
Log?.debug('try to connect to device has error: ', e);
|
|
946
|
-
if (isConnectTimeoutError(e)) {
|
|
947
|
-
throw e;
|
|
948
|
-
}
|
|
949
869
|
if (
|
|
950
870
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
951
871
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
952
872
|
) {
|
|
953
873
|
Log?.debug('first try to reconnect without params');
|
|
954
|
-
device = await
|
|
955
|
-
blePlxManager.connectToDevice(uuid, fallbackConnectOptions)
|
|
956
|
-
);
|
|
874
|
+
device = await blePlxManager.connectToDevice(uuid);
|
|
957
875
|
} else if (e.errorCode === BleErrorCode.DeviceAlreadyConnected) {
|
|
958
876
|
Log?.debug('device already connected');
|
|
959
877
|
throw ERRORS.TypedError(HardwareErrorCode.BleAlreadyConnected);
|
|
@@ -969,36 +887,26 @@ export default class ReactNativeBleTransport {
|
|
|
969
887
|
|
|
970
888
|
if (!(await device.isConnected())) {
|
|
971
889
|
Log?.debug('not connected, try to connect to device: ', uuid);
|
|
972
|
-
const disconnectedDevice = device;
|
|
973
890
|
|
|
974
891
|
try {
|
|
975
|
-
device = await
|
|
976
|
-
disconnectedDevice.connect(connectOptions)
|
|
977
|
-
);
|
|
892
|
+
device = await device.connect(connectOptions);
|
|
978
893
|
} catch (e) {
|
|
979
894
|
Log?.debug('not connected, try to connect to device has error: ', e);
|
|
980
|
-
if (isConnectTimeoutError(e)) {
|
|
981
|
-
throw e;
|
|
982
|
-
}
|
|
983
895
|
if (
|
|
984
896
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
985
897
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
986
898
|
) {
|
|
987
899
|
Log?.debug('second try to reconnect without params');
|
|
988
900
|
try {
|
|
989
|
-
device = await
|
|
990
|
-
disconnectedDevice.connect(fallbackConnectOptions)
|
|
991
|
-
);
|
|
901
|
+
device = await device.connect();
|
|
992
902
|
} catch (e) {
|
|
993
903
|
Log?.debug('last try to reconnect error: ', e);
|
|
994
904
|
// last try to reconnect device if this issue exists
|
|
995
905
|
// https://github.com/dotintent/react-native-ble-plx/issues/426
|
|
996
906
|
if (e.errorCode === BleErrorCode.OperationCancelled) {
|
|
997
907
|
Log?.debug('last try to reconnect');
|
|
998
|
-
await
|
|
999
|
-
device = await
|
|
1000
|
-
disconnectedDevice.connect(fallbackConnectOptions)
|
|
1001
|
-
);
|
|
908
|
+
await device.cancelConnection();
|
|
909
|
+
device = await device.connect();
|
|
1002
910
|
}
|
|
1003
911
|
}
|
|
1004
912
|
} else {
|
|
@@ -1009,8 +917,9 @@ export default class ReactNativeBleTransport {
|
|
|
1009
917
|
|
|
1010
918
|
device = await resolveNegotiatedMtu(device);
|
|
1011
919
|
const acquiredDevice = device;
|
|
1012
|
-
const { writeCharacteristic, notifyCharacteristic } =
|
|
1013
|
-
|
|
920
|
+
const { writeCharacteristic, notifyCharacteristic } = await this.resolveCharacteristics(
|
|
921
|
+
acquiredDevice
|
|
922
|
+
);
|
|
1014
923
|
|
|
1015
924
|
const protocolHint = expectedProtocol
|
|
1016
925
|
? undefined
|
|
@@ -1074,7 +983,7 @@ export default class ReactNativeBleTransport {
|
|
|
1074
983
|
Log?.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
1075
984
|
return;
|
|
1076
985
|
}
|
|
1077
|
-
if (this.
|
|
986
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
1078
987
|
let errorCode:
|
|
1079
988
|
| typeof HardwareErrorCode.BleDeviceBondError
|
|
1080
989
|
| typeof HardwareErrorCode.BleCharacteristicNotifyError
|
|
@@ -1144,7 +1053,7 @@ export default class ReactNativeBleTransport {
|
|
|
1144
1053
|
|
|
1145
1054
|
try {
|
|
1146
1055
|
const data = Buffer.from(c.value as string, 'base64');
|
|
1147
|
-
const protocol = this.
|
|
1056
|
+
const protocol = this.deviceProtocol.get(uuid);
|
|
1148
1057
|
if (!protocol) {
|
|
1149
1058
|
Log?.debug('monitor data ignored before protocol detection: ', uuid);
|
|
1150
1059
|
return;
|
|
@@ -1178,7 +1087,7 @@ export default class ReactNativeBleTransport {
|
|
|
1178
1087
|
} catch (error) {
|
|
1179
1088
|
Log?.debug('monitor data error: ', error);
|
|
1180
1089
|
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
1181
|
-
if (this.
|
|
1090
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
1182
1091
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1183
1092
|
} else if (this.runPromiseDeviceId === uuid) {
|
|
1184
1093
|
this.runPromise?.reject(notifyError);
|
|
@@ -1246,7 +1155,6 @@ export default class ReactNativeBleTransport {
|
|
|
1246
1155
|
this.protocolV2HighVolumeLogSignatures.delete(uuid);
|
|
1247
1156
|
|
|
1248
1157
|
this.deviceProtocol.delete(uuid);
|
|
1249
|
-
this.probingProtocols.delete(uuid);
|
|
1250
1158
|
// Preserve a name-derived hint across disconnects so reconnect can probe V2 first.
|
|
1251
1159
|
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1252
1160
|
this.protocolV2Assemblers.delete(uuid);
|
|
@@ -1313,25 +1221,8 @@ export default class ReactNativeBleTransport {
|
|
|
1313
1221
|
const transport = this.getCachedTransport(uuid);
|
|
1314
1222
|
const runPromise = createDeferred<string>();
|
|
1315
1223
|
runPromise.promise.catch(() => undefined);
|
|
1316
|
-
const supersededRunPromise = this.runPromise;
|
|
1317
|
-
if (supersededRunPromise) {
|
|
1318
|
-
// Only forceRun calls (Initialize/Cancel) reach here with a pending call. Settle
|
|
1319
|
-
// the superseded deferred now so its response race resolves and its finally block
|
|
1320
|
-
// clears its timeout timer; an orphaned timer would otherwise fire much later and
|
|
1321
|
-
// tear down the shared connection while another call is using it.
|
|
1322
|
-
supersededRunPromise.reject(ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise));
|
|
1323
|
-
}
|
|
1324
1224
|
this.runPromise = runPromise;
|
|
1325
1225
|
this.runPromiseDeviceId = uuid;
|
|
1326
|
-
// A superseded call's late write failure must not clear the successor's ownership;
|
|
1327
|
-
// only the call that still owns the slot may release it.
|
|
1328
|
-
const releaseOwnershipIfCurrent = () => {
|
|
1329
|
-
if (this.runPromise === runPromise) {
|
|
1330
|
-
this.runPromise = null;
|
|
1331
|
-
this.runPromiseDeviceId = null;
|
|
1332
|
-
}
|
|
1333
|
-
};
|
|
1334
|
-
const isCurrentOwner = () => this.runPromise === runPromise;
|
|
1335
1226
|
const messages = this._messages;
|
|
1336
1227
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1337
1228
|
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -1357,9 +1248,6 @@ export default class ReactNativeBleTransport {
|
|
|
1357
1248
|
chunk = ByteBuffer.allocate(packetCapacity);
|
|
1358
1249
|
} catch (e) {
|
|
1359
1250
|
onError(e);
|
|
1360
|
-
if (isWedgedWriteError(e)) {
|
|
1361
|
-
throw e;
|
|
1362
|
-
}
|
|
1363
1251
|
throw ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
1364
1252
|
}
|
|
1365
1253
|
}
|
|
@@ -1391,9 +1279,6 @@ export default class ReactNativeBleTransport {
|
|
|
1391
1279
|
}
|
|
1392
1280
|
} catch (e) {
|
|
1393
1281
|
onError(e);
|
|
1394
|
-
if (isWedgedWriteError(e)) {
|
|
1395
|
-
throw e;
|
|
1396
|
-
}
|
|
1397
1282
|
throw ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
1398
1283
|
}
|
|
1399
1284
|
}
|
|
@@ -1407,15 +1292,9 @@ export default class ReactNativeBleTransport {
|
|
|
1407
1292
|
if (name === 'EmmcFileWrite') {
|
|
1408
1293
|
await writeChunkedData(
|
|
1409
1294
|
buffers,
|
|
1410
|
-
data =>
|
|
1411
|
-
this.writeBlePacket(
|
|
1412
|
-
uuid,
|
|
1413
|
-
data,
|
|
1414
|
-
payload => transport.writeWithRetry(payload),
|
|
1415
|
-
isCurrentOwner
|
|
1416
|
-
),
|
|
1295
|
+
data => transport.writeWithRetry(data),
|
|
1417
1296
|
e => {
|
|
1418
|
-
|
|
1297
|
+
this.runPromise = null;
|
|
1419
1298
|
Log?.error('writeCharacteristic write error: ', e);
|
|
1420
1299
|
}
|
|
1421
1300
|
);
|
|
@@ -1436,12 +1315,7 @@ export default class ReactNativeBleTransport {
|
|
|
1436
1315
|
// eslint-disable-next-line no-constant-condition
|
|
1437
1316
|
while (true) {
|
|
1438
1317
|
try {
|
|
1439
|
-
await
|
|
1440
|
-
uuid,
|
|
1441
|
-
data,
|
|
1442
|
-
payload => transport.writeWithRetry(payload),
|
|
1443
|
-
isCurrentOwner
|
|
1444
|
-
);
|
|
1318
|
+
await transport.writeWithRetry(data);
|
|
1445
1319
|
return;
|
|
1446
1320
|
} catch (error) {
|
|
1447
1321
|
const retryType = getFirmwareUploadWriteRetryType(error);
|
|
@@ -1460,7 +1334,7 @@ export default class ReactNativeBleTransport {
|
|
|
1460
1334
|
}
|
|
1461
1335
|
},
|
|
1462
1336
|
e => {
|
|
1463
|
-
|
|
1337
|
+
this.runPromise = null;
|
|
1464
1338
|
Log?.error('writeCharacteristic write error: ', e);
|
|
1465
1339
|
}
|
|
1466
1340
|
);
|
|
@@ -1471,21 +1345,14 @@ export default class ReactNativeBleTransport {
|
|
|
1471
1345
|
try {
|
|
1472
1346
|
const shouldUseWriteWithResponse =
|
|
1473
1347
|
Platform.OS === 'ios' && transport.writeCharacteristic.isWritableWithResponse;
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
1480
|
-
: transport.writeCharacteristic.writeWithoutResponse(payload),
|
|
1481
|
-
isCurrentOwner
|
|
1482
|
-
);
|
|
1348
|
+
if (shouldUseWriteWithResponse) {
|
|
1349
|
+
await transport.writeCharacteristic.writeWithResponse(outData);
|
|
1350
|
+
} else {
|
|
1351
|
+
await transport.writeCharacteristic.writeWithoutResponse(outData);
|
|
1352
|
+
}
|
|
1483
1353
|
} catch (e) {
|
|
1484
1354
|
Log?.debug('writeCharacteristic write error: ', e);
|
|
1485
|
-
|
|
1486
|
-
if (isWedgedWriteError(e)) {
|
|
1487
|
-
throw e;
|
|
1488
|
-
}
|
|
1355
|
+
this.runPromise = null;
|
|
1489
1356
|
if (e.errorCode === BleErrorCode.DeviceDisconnected) {
|
|
1490
1357
|
throw ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded);
|
|
1491
1358
|
} else if (e.errorCode === BleErrorCode.OperationStartFailed) {
|
|
@@ -1528,13 +1395,8 @@ export default class ReactNativeBleTransport {
|
|
|
1528
1395
|
}
|
|
1529
1396
|
const isProbeTimeout =
|
|
1530
1397
|
name === 'GetFeatures' && options?.timeoutMs === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1531
|
-
// A call that has been superseded (forceRun) or cleaned up no longer owns the
|
|
1532
|
-
// transport; its late timeout must not tear down the connection the current
|
|
1533
|
-
// call is actively using.
|
|
1534
|
-
const isStaleCall = this.runPromise !== runPromise;
|
|
1535
1398
|
if (
|
|
1536
1399
|
!isProbeTimeout &&
|
|
1537
|
-
!isStaleCall &&
|
|
1538
1400
|
(e as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleTimeoutError
|
|
1539
1401
|
) {
|
|
1540
1402
|
await this.disconnect(uuid);
|
|
@@ -1614,10 +1476,7 @@ export default class ReactNativeBleTransport {
|
|
|
1614
1476
|
delete transportCache[session];
|
|
1615
1477
|
}
|
|
1616
1478
|
this.deviceProtocol.delete(session);
|
|
1617
|
-
this.probingProtocols.delete(session);
|
|
1618
1479
|
this.deviceProtocolHints.delete(session);
|
|
1619
|
-
this.sessionProtocols.delete(session);
|
|
1620
|
-
this.protocolReprobeFailures.delete(session);
|
|
1621
1480
|
this.protocolV2Assemblers.delete(session);
|
|
1622
1481
|
this.resetProtocolV2Frames(session);
|
|
1623
1482
|
|
|
@@ -1643,113 +1502,6 @@ export default class ReactNativeBleTransport {
|
|
|
1643
1502
|
this.runPromiseDeviceId = null;
|
|
1644
1503
|
}
|
|
1645
1504
|
|
|
1646
|
-
/** Run a native connect under the JS backstop budget. */
|
|
1647
|
-
private async connectWithTimeout<T>(uuid: string, connect: () => Promise<T>): Promise<T> {
|
|
1648
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1649
|
-
let timedOut = false;
|
|
1650
|
-
const pending = connect();
|
|
1651
|
-
// The abandoned attempt keeps running; swallow its late outcome so it cannot
|
|
1652
|
-
// surface as an unhandled rejection after we have already given up on it.
|
|
1653
|
-
pending.catch(() => undefined);
|
|
1654
|
-
try {
|
|
1655
|
-
const result = await Promise.race([
|
|
1656
|
-
pending,
|
|
1657
|
-
new Promise<never>((_, reject) => {
|
|
1658
|
-
timer = setTimeout(() => {
|
|
1659
|
-
timedOut = true;
|
|
1660
|
-
reject(
|
|
1661
|
-
ERRORS.TypedError(
|
|
1662
|
-
HardwareErrorCode.BleConnectedError,
|
|
1663
|
-
`BLE connect timeout after ${BLE_CONNECT_TIMEOUT_MS}ms for ${uuid}`
|
|
1664
|
-
)
|
|
1665
|
-
);
|
|
1666
|
-
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1667
|
-
}),
|
|
1668
|
-
]);
|
|
1669
|
-
return result;
|
|
1670
|
-
} catch (error) {
|
|
1671
|
-
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1672
|
-
this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1673
|
-
}
|
|
1674
|
-
throw error;
|
|
1675
|
-
} finally {
|
|
1676
|
-
if (timer) clearTimeout(timer);
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
/** Resolve the complete GATT shape under a budget so acquire() always settles. */
|
|
1681
|
-
private async resolveCharacteristicsWithTimeout(
|
|
1682
|
-
uuid: string,
|
|
1683
|
-
device: Device
|
|
1684
|
-
): Promise<ResolvedBleCharacteristics> {
|
|
1685
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1686
|
-
let timedOut = false;
|
|
1687
|
-
const pending = this.resolveCharacteristics(device);
|
|
1688
|
-
pending.catch(() => undefined);
|
|
1689
|
-
try {
|
|
1690
|
-
const result = await Promise.race([
|
|
1691
|
-
pending,
|
|
1692
|
-
new Promise<never>((_, reject) => {
|
|
1693
|
-
timer = setTimeout(() => {
|
|
1694
|
-
timedOut = true;
|
|
1695
|
-
reject(
|
|
1696
|
-
ERRORS.TypedError(
|
|
1697
|
-
HardwareErrorCode.BleConnectedError,
|
|
1698
|
-
`BLE GATT setup timeout after ${BLE_GATT_SETUP_TIMEOUT_MS}ms for ${uuid}`
|
|
1699
|
-
)
|
|
1700
|
-
);
|
|
1701
|
-
}, BLE_GATT_SETUP_TIMEOUT_MS);
|
|
1702
|
-
}),
|
|
1703
|
-
]);
|
|
1704
|
-
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1705
|
-
return result;
|
|
1706
|
-
} catch (error) {
|
|
1707
|
-
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1708
|
-
this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1709
|
-
}
|
|
1710
|
-
throw error;
|
|
1711
|
-
} finally {
|
|
1712
|
-
if (timer) clearTimeout(timer);
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
/**
|
|
1717
|
-
* Give up on a BLE setup operation the native layer did not settle. The abandoned
|
|
1718
|
-
* operation still owns native connection/GATT state that can poison the next attempt,
|
|
1719
|
-
* so it is cleared here without awaiting the same queue that stopped responding.
|
|
1720
|
-
*/
|
|
1721
|
-
private abandonStalledConnection(
|
|
1722
|
-
uuid: string,
|
|
1723
|
-
stage: 'connect-backstop' | 'connect-native' | 'gatt-backstop' | 'gatt-native'
|
|
1724
|
-
) {
|
|
1725
|
-
const timeouts = (this.connectionSetupTimeoutCounts.get(uuid) ?? 0) + 1;
|
|
1726
|
-
this.connectionSetupTimeoutCounts.set(uuid, timeouts);
|
|
1727
|
-
Log?.error('[ReactNativeBleTransport] BLE setup timed out:', uuid, {
|
|
1728
|
-
stage,
|
|
1729
|
-
setupTimeoutsSinceSuccess: timeouts,
|
|
1730
|
-
});
|
|
1731
|
-
|
|
1732
|
-
this.blePlxManager?.cancelDeviceConnection(uuid).catch(() => {
|
|
1733
|
-
// Rejects with "Operation was cancelled" while merely connecting — expected.
|
|
1734
|
-
});
|
|
1735
|
-
const stalled = transportCache[uuid];
|
|
1736
|
-
if (stalled) {
|
|
1737
|
-
delete transportCache[uuid];
|
|
1738
|
-
}
|
|
1739
|
-
this.deviceProtocol.delete(uuid);
|
|
1740
|
-
this.probingProtocols.delete(uuid);
|
|
1741
|
-
this.protocolV2Assemblers.delete(uuid);
|
|
1742
|
-
this.resetProtocolV2Frames(uuid);
|
|
1743
|
-
|
|
1744
|
-
if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1745
|
-
// BleManager.destroy() force-rejects every promise the native queue abandoned —
|
|
1746
|
-
// the only JS-reachable way to settle them — and drops all cached peripherals.
|
|
1747
|
-
Log?.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1748
|
-
this.resetPlxManager();
|
|
1749
|
-
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
1505
|
private getCachedTransport(uuid: string) {
|
|
1754
1506
|
const transport = transportCache[uuid];
|
|
1755
1507
|
if (!transport) {
|
|
@@ -1758,107 +1510,6 @@ export default class ReactNativeBleTransport {
|
|
|
1758
1510
|
return transport;
|
|
1759
1511
|
}
|
|
1760
1512
|
|
|
1761
|
-
/**
|
|
1762
|
-
* Write one packet under a bounded budget. A write that never settles means the
|
|
1763
|
-
* peripheral is wedged even though the GATT link still reports connected, so the
|
|
1764
|
-
* link is torn down: releasing JS state alone would leave the poisoned peripheral
|
|
1765
|
-
* cached and every later call would hang on it again.
|
|
1766
|
-
*/
|
|
1767
|
-
private async writeBlePacket(
|
|
1768
|
-
uuid: string,
|
|
1769
|
-
data: string,
|
|
1770
|
-
write: (payload: string) => Promise<unknown>,
|
|
1771
|
-
isCurrentOwner?: () => boolean
|
|
1772
|
-
) {
|
|
1773
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1774
|
-
let timedOut = false;
|
|
1775
|
-
try {
|
|
1776
|
-
await Promise.race([
|
|
1777
|
-
write(data),
|
|
1778
|
-
new Promise<never>((_, reject) => {
|
|
1779
|
-
timer = setTimeout(() => {
|
|
1780
|
-
timedOut = true;
|
|
1781
|
-
reject(
|
|
1782
|
-
ERRORS.TypedError(
|
|
1783
|
-
HardwareErrorCode.BleWriteCharacteristicError,
|
|
1784
|
-
`BLE write timeout after ${BLE_WRITE_PACKET_TIMEOUT_MS}ms`
|
|
1785
|
-
)
|
|
1786
|
-
);
|
|
1787
|
-
}, BLE_WRITE_PACKET_TIMEOUT_MS);
|
|
1788
|
-
}),
|
|
1789
|
-
]);
|
|
1790
|
-
this.writeTimeoutCounts.delete(uuid);
|
|
1791
|
-
} catch (error) {
|
|
1792
|
-
if (timedOut) {
|
|
1793
|
-
// A superseded call's late write must not tear down the link the current
|
|
1794
|
-
// call is using; only the owner of the transport may declare it dead.
|
|
1795
|
-
if (isCurrentOwner && !isCurrentOwner()) {
|
|
1796
|
-
Log?.debug('[ReactNativeBleTransport] stale BLE write timed out, link kept:', uuid);
|
|
1797
|
-
} else {
|
|
1798
|
-
this.tearDownWedgedLink(uuid);
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
throw error;
|
|
1802
|
-
} finally {
|
|
1803
|
-
if (timer) clearTimeout(timer);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
/**
|
|
1808
|
-
* Drop a link whose writes stopped completing. The JS state is purged synchronously
|
|
1809
|
-
* so the next acquire() cannot reuse the dead transport, while the native teardown is
|
|
1810
|
-
* intentionally NOT awaited: it talks to the very layer that just stopped settling
|
|
1811
|
-
* promises, so awaiting it could hang exactly like the write it is recovering from.
|
|
1812
|
-
*/
|
|
1813
|
-
private tearDownWedgedLink(uuid: string) {
|
|
1814
|
-
const timeouts = (this.writeTimeoutCounts.get(uuid) ?? 0) + 1;
|
|
1815
|
-
this.writeTimeoutCounts.set(uuid, timeouts);
|
|
1816
|
-
Log?.error('[ReactNativeBleTransport] BLE write timed out, tearing down link:', uuid, {
|
|
1817
|
-
consecutiveWriteTimeouts: timeouts,
|
|
1818
|
-
});
|
|
1819
|
-
|
|
1820
|
-
const wedged = transportCache[uuid];
|
|
1821
|
-
this.disconnect(uuid).catch(error => {
|
|
1822
|
-
Log?.debug('[ReactNativeBleTransport] wedged link teardown failed (ignored):', error);
|
|
1823
|
-
});
|
|
1824
|
-
if (wedged && transportCache[uuid] === wedged) {
|
|
1825
|
-
delete transportCache[uuid];
|
|
1826
|
-
}
|
|
1827
|
-
this.deviceProtocol.delete(uuid);
|
|
1828
|
-
this.probingProtocols.delete(uuid);
|
|
1829
|
-
this.protocolV2Assemblers.delete(uuid);
|
|
1830
|
-
this.resetProtocolV2Frames(uuid);
|
|
1831
|
-
|
|
1832
|
-
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1833
|
-
// Reconnecting reuses the same native peripheral object. When it stays wedged
|
|
1834
|
-
// across attempts the poison lives in the BLE manager itself, and only a fresh
|
|
1835
|
-
// manager drops every cached peripheral — the JS equivalent of restarting the app.
|
|
1836
|
-
Log?.error('[ReactNativeBleTransport] BLE writes wedged repeatedly, resetting BLE manager');
|
|
1837
|
-
this.resetPlxManager();
|
|
1838
|
-
this.writeTimeoutCounts.delete(uuid);
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
|
|
1842
|
-
private resetPlxManager() {
|
|
1843
|
-
const manager = this.blePlxManager;
|
|
1844
|
-
this.blePlxManager = undefined;
|
|
1845
|
-
// Every cached transport belongs to the destroyed manager's peripherals.
|
|
1846
|
-
Object.keys(transportCache).forEach(key => {
|
|
1847
|
-
delete transportCache[key];
|
|
1848
|
-
});
|
|
1849
|
-
this.deviceProtocol.clear();
|
|
1850
|
-
this.probingProtocols.clear();
|
|
1851
|
-
this.sessionProtocols.clear();
|
|
1852
|
-
this.protocolReprobeFailures.clear();
|
|
1853
|
-
this.monitorTokens.clear();
|
|
1854
|
-
this.protocolV2Assemblers.clear();
|
|
1855
|
-
try {
|
|
1856
|
-
manager?.destroy();
|
|
1857
|
-
} catch (error) {
|
|
1858
|
-
Log?.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
|
|
1862
1513
|
private createProtocolMismatchError(expected: ProtocolType) {
|
|
1863
1514
|
return ERRORS.TypedError(
|
|
1864
1515
|
HardwareErrorCode.RuntimeError,
|
|
@@ -1874,19 +1525,11 @@ export default class ReactNativeBleTransport {
|
|
|
1874
1525
|
}
|
|
1875
1526
|
|
|
1876
1527
|
private clearProbeProtocol(uuid: string, protocol: ProtocolType) {
|
|
1877
|
-
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1878
|
-
this.probingProtocols.delete(uuid);
|
|
1879
|
-
}
|
|
1880
1528
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1881
1529
|
this.deviceProtocol.delete(uuid);
|
|
1882
1530
|
}
|
|
1883
1531
|
}
|
|
1884
1532
|
|
|
1885
|
-
/** Protocol to route a call with: confirmed if known, otherwise the one being probed. */
|
|
1886
|
-
private getActiveProtocol(uuid: string): ProtocolType | undefined {
|
|
1887
|
-
return this.deviceProtocol.get(uuid) ?? this.probingProtocols.get(uuid);
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
1533
|
private async detectProtocol(
|
|
1891
1534
|
uuid: string,
|
|
1892
1535
|
expectedProtocol?: ProtocolType,
|
|
@@ -1906,7 +1549,6 @@ export default class ReactNativeBleTransport {
|
|
|
1906
1549
|
if (expectedProtocol === 'V1') {
|
|
1907
1550
|
if (await this.probeProtocolV1(uuid)) {
|
|
1908
1551
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1909
|
-
this.sessionProtocols.set(uuid, 'V1');
|
|
1910
1552
|
Log?.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1911
1553
|
deviceId: uuid,
|
|
1912
1554
|
protocol: 'V1',
|
|
@@ -1920,7 +1562,6 @@ export default class ReactNativeBleTransport {
|
|
|
1920
1562
|
if (expectedProtocol === 'V2') {
|
|
1921
1563
|
if (await this.probeProtocolV2(uuid)) {
|
|
1922
1564
|
this.deviceProtocol.set(uuid, 'V2');
|
|
1923
|
-
this.sessionProtocols.set(uuid, 'V2');
|
|
1924
1565
|
Log?.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1925
1566
|
deviceId: uuid,
|
|
1926
1567
|
protocol: 'V2',
|
|
@@ -1933,18 +1574,8 @@ export default class ReactNativeBleTransport {
|
|
|
1933
1574
|
|
|
1934
1575
|
// Protocol must be actively probed after connection. Name, PID, and descriptors only
|
|
1935
1576
|
// influence probe order; a V2 hint probes V2 first and falls back to V1.
|
|
1936
|
-
const
|
|
1937
|
-
const reprobeFailures = this.protocolReprobeFailures.get(uuid) ?? 0;
|
|
1938
|
-
const fullProbeOrder: ProtocolType[] =
|
|
1577
|
+
const probeOrder: ProtocolType[] =
|
|
1939
1578
|
protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1940
|
-
// A device that already answered on a protocol in this session keeps answering on
|
|
1941
|
-
// it; while it is rebooting nothing answers at all, so probing the other protocol
|
|
1942
|
-
// only adds its timeout to every poll.
|
|
1943
|
-
const trustSessionProtocol =
|
|
1944
|
-
sessionProtocol !== undefined &&
|
|
1945
|
-
!protocolHint &&
|
|
1946
|
-
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1947
|
-
const probeOrder: ProtocolType[] = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
1948
1579
|
|
|
1949
1580
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1950
1581
|
const protocol = probeOrder[i];
|
|
@@ -1962,8 +1593,6 @@ export default class ReactNativeBleTransport {
|
|
|
1962
1593
|
protocol === 'V1' ? await this.probeProtocolV1(uuid) : await this.probeProtocolV2(uuid);
|
|
1963
1594
|
if (detected) {
|
|
1964
1595
|
this.deviceProtocol.set(uuid, protocol);
|
|
1965
|
-
this.sessionProtocols.set(uuid, protocol);
|
|
1966
|
-
this.protocolReprobeFailures.delete(uuid);
|
|
1967
1596
|
Log?.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1968
1597
|
deviceId: uuid,
|
|
1969
1598
|
protocol,
|
|
@@ -1973,16 +1602,7 @@ export default class ReactNativeBleTransport {
|
|
|
1973
1602
|
}
|
|
1974
1603
|
}
|
|
1975
1604
|
|
|
1976
|
-
if (trustSessionProtocol) {
|
|
1977
|
-
// Still silent on its own protocol: count it, and let the streak expire the
|
|
1978
|
-
// shortcut so a device that genuinely switched protocols is found again.
|
|
1979
|
-
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
1980
|
-
} else {
|
|
1981
|
-
this.protocolReprobeFailures.delete(uuid);
|
|
1982
|
-
}
|
|
1983
|
-
|
|
1984
1605
|
this.deviceProtocol.delete(uuid);
|
|
1985
|
-
this.probingProtocols.delete(uuid);
|
|
1986
1606
|
throw this.createProtocolDetectionError();
|
|
1987
1607
|
}
|
|
1988
1608
|
|
|
@@ -2044,20 +1664,14 @@ export default class ReactNativeBleTransport {
|
|
|
2044
1664
|
}
|
|
2045
1665
|
|
|
2046
1666
|
try {
|
|
2047
|
-
this.
|
|
1667
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
2048
1668
|
// GetFeatures identifies Protocol V1 without resetting an existing wallet
|
|
2049
1669
|
// session before Core has a chance to restore a hidden wallet.
|
|
2050
1670
|
await this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
2051
|
-
this.probingProtocols.delete(uuid);
|
|
2052
1671
|
return true;
|
|
2053
1672
|
} catch (error) {
|
|
2054
1673
|
this.clearProbeProtocol(uuid, 'V1');
|
|
2055
1674
|
Log?.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
2056
|
-
// A wedged write already dropped the link, so probing another protocol on it
|
|
2057
|
-
// would only fail against a torn-down transport: surface the real cause.
|
|
2058
|
-
if (isWedgedWriteError(error)) {
|
|
2059
|
-
throw error;
|
|
2060
|
-
}
|
|
2061
1675
|
return false;
|
|
2062
1676
|
}
|
|
2063
1677
|
}
|
|
@@ -2067,7 +1681,7 @@ export default class ReactNativeBleTransport {
|
|
|
2067
1681
|
return false;
|
|
2068
1682
|
}
|
|
2069
1683
|
|
|
2070
|
-
this.
|
|
1684
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
2071
1685
|
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
2072
1686
|
const detected = await probeProtocolV2Helper({
|
|
2073
1687
|
call: (name: string, data: Record<string, unknown>, options?: TransportCallOptions) =>
|
|
@@ -2082,8 +1696,6 @@ export default class ReactNativeBleTransport {
|
|
|
2082
1696
|
});
|
|
2083
1697
|
if (!detected) {
|
|
2084
1698
|
this.clearProbeProtocol(uuid, 'V2');
|
|
2085
|
-
} else {
|
|
2086
|
-
this.probingProtocols.delete(uuid);
|
|
2087
1699
|
}
|
|
2088
1700
|
return detected;
|
|
2089
1701
|
}
|
|
@@ -2165,7 +1777,6 @@ export default class ReactNativeBleTransport {
|
|
|
2165
1777
|
}
|
|
2166
1778
|
|
|
2167
1779
|
private async writeProtocolV2Packet(
|
|
2168
|
-
uuid: string,
|
|
2169
1780
|
transport: BleTransport,
|
|
2170
1781
|
base64: string,
|
|
2171
1782
|
context: ProtocolV2CallContext,
|
|
@@ -2184,24 +1795,11 @@ export default class ReactNativeBleTransport {
|
|
|
2184
1795
|
throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
|
|
2185
1796
|
}
|
|
2186
1797
|
try {
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
2193
|
-
: transport.writeCharacteristic.writeWithoutResponse(payload),
|
|
2194
|
-
// Same rule as Protocol V1: a write from a superseded generation must not
|
|
2195
|
-
// tear down the link that the current generation is using.
|
|
2196
|
-
() => {
|
|
2197
|
-
try {
|
|
2198
|
-
assertCurrentGeneration();
|
|
2199
|
-
return !context.signal.aborted;
|
|
2200
|
-
} catch {
|
|
2201
|
-
return false;
|
|
2202
|
-
}
|
|
2203
|
-
}
|
|
2204
|
-
);
|
|
1798
|
+
if (shouldUseWriteWithResponse) {
|
|
1799
|
+
await transport.writeCharacteristic.writeWithResponse(base64);
|
|
1800
|
+
} else {
|
|
1801
|
+
await transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
1802
|
+
}
|
|
2205
1803
|
assertCurrentGeneration();
|
|
2206
1804
|
return;
|
|
2207
1805
|
} catch (error) {
|
|
@@ -2224,7 +1822,6 @@ export default class ReactNativeBleTransport {
|
|
|
2224
1822
|
}
|
|
2225
1823
|
|
|
2226
1824
|
private async writeProtocolV2Frame(
|
|
2227
|
-
uuid: string,
|
|
2228
1825
|
transport: BleTransport,
|
|
2229
1826
|
frame: Uint8Array,
|
|
2230
1827
|
context: ProtocolV2CallContext,
|
|
@@ -2246,7 +1843,6 @@ export default class ReactNativeBleTransport {
|
|
|
2246
1843
|
wait: delay,
|
|
2247
1844
|
writePacket: packet =>
|
|
2248
1845
|
this.writeProtocolV2Packet(
|
|
2249
|
-
uuid,
|
|
2250
1846
|
transport,
|
|
2251
1847
|
Buffer.from(packet).toString('base64'),
|
|
2252
1848
|
context,
|
|
@@ -2424,13 +2020,7 @@ export default class ReactNativeBleTransport {
|
|
|
2424
2020
|
writeFrame: async (frame: Uint8Array, context: ProtocolV2CallContext) => {
|
|
2425
2021
|
assertCurrentGeneration();
|
|
2426
2022
|
const currentTransport = this.getCachedTransport(uuid);
|
|
2427
|
-
await this.writeProtocolV2Frame(
|
|
2428
|
-
uuid,
|
|
2429
|
-
currentTransport,
|
|
2430
|
-
frame,
|
|
2431
|
-
context,
|
|
2432
|
-
assertCurrentGeneration
|
|
2433
|
-
);
|
|
2023
|
+
await this.writeProtocolV2Frame(currentTransport, frame, context, assertCurrentGeneration);
|
|
2434
2024
|
},
|
|
2435
2025
|
readFrame: async () => {
|
|
2436
2026
|
assertCurrentGeneration();
|
|
@@ -2455,6 +2045,6 @@ export default class ReactNativeBleTransport {
|
|
|
2455
2045
|
}
|
|
2456
2046
|
|
|
2457
2047
|
getProtocolType(path: string): ProtocolType | undefined {
|
|
2458
|
-
return this.
|
|
2048
|
+
return this.deviceProtocol.get(path);
|
|
2459
2049
|
}
|
|
2460
2050
|
}
|