@onekeyfe/hd-transport-react-native 1.2.2-alpha.114 → 1.2.2-alpha.116
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 +74 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +274 -32
- package/package.json +5 -5
- package/src/__tests__/connectTimeout.test.ts +104 -0
- package/src/__tests__/protocolV2Link.test.ts +494 -37
- package/src/index.ts +468 -43
package/dist/index.js
CHANGED
|
@@ -384,7 +384,8 @@ const shouldRethrowProtocolProbeError = (error) => {
|
|
|
384
384
|
code === hdShared.HardwareErrorCode.BleDeviceDisconnected ||
|
|
385
385
|
code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
|
|
386
386
|
code === hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure ||
|
|
387
|
-
code === hdShared.HardwareErrorCode.BleWriteCharacteristicError
|
|
387
|
+
code === hdShared.HardwareErrorCode.BleWriteCharacteristicError ||
|
|
388
|
+
isProtocolV2DefaultMtuError(error));
|
|
388
389
|
};
|
|
389
390
|
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
390
391
|
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
@@ -432,6 +433,40 @@ const connectOptions = {
|
|
|
432
433
|
const fallbackConnectOptions = {
|
|
433
434
|
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
434
435
|
};
|
|
436
|
+
const androidConnectOptions = {
|
|
437
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
438
|
+
};
|
|
439
|
+
const androidRefreshGattConnectOptions = {
|
|
440
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
441
|
+
refreshGatt: 'OnConnected',
|
|
442
|
+
};
|
|
443
|
+
const ANDROID_MTU_EXCHANGE_TIMEOUT_MS = 12000;
|
|
444
|
+
const ANDROID_LINK_DROP_QUIET_MS = 5000;
|
|
445
|
+
const ANDROID_LINK_DROP_TIMEOUT_MS = 8000;
|
|
446
|
+
const ANDROID_LINK_DROP_POLL_MS = 250;
|
|
447
|
+
const isKnownDefaultMtu = (mtu) => typeof mtu === 'number' && Number.isFinite(mtu) && mtu <= 23;
|
|
448
|
+
const DEFAULT_MTU_LINK_MESSAGE = 'BLE link stayed at the default MTU';
|
|
449
|
+
const createDefaultMtuLinkError = (mtu) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${DEFAULT_MTU_LINK_MESSAGE} ${String(mtu)}, reconnecting on a fresh link`);
|
|
450
|
+
const PROTOCOL_V2_DEFAULT_MTU_MESSAGE = 'Protocol V2 needs a negotiated BLE MTU';
|
|
451
|
+
const isProtocolV2DefaultMtuError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
452
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
453
|
+
error.message.startsWith(PROTOCOL_V2_DEFAULT_MTU_MESSAGE);
|
|
454
|
+
const createProtocolV2DefaultMtuError = (mtu) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${PROTOCOL_V2_DEFAULT_MTU_MESSAGE}, current MTU ${String(mtu)}`);
|
|
455
|
+
const isMissingGattShapeError = (error) => {
|
|
456
|
+
const code = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
457
|
+
const message = error === null || error === void 0 ? void 0 : error.message;
|
|
458
|
+
return (code === hdShared.HardwareErrorCode.BleServiceNotFound ||
|
|
459
|
+
code === hdShared.HardwareErrorCode.BleCharacteristicNotFound ||
|
|
460
|
+
(typeof message === 'string' &&
|
|
461
|
+
(message.includes('BLECharacteristicNotFound') ||
|
|
462
|
+
message.includes('BLECharacteristicNotWritable') ||
|
|
463
|
+
message.includes('BLECharacteristicNotNotifiable'))));
|
|
464
|
+
};
|
|
465
|
+
const isStaleGattTableNotifyReason = (reason) => !!reason &&
|
|
466
|
+
(reason.includes('Cannot write client characteristic config descriptor') ||
|
|
467
|
+
reason.includes('Cannot find client characteristic config descriptor') ||
|
|
468
|
+
reason.includes('The handle is invalid') ||
|
|
469
|
+
reason.includes('Writing is not permitted'));
|
|
435
470
|
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
436
471
|
const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
437
472
|
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
@@ -446,10 +481,9 @@ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? v
|
|
|
446
481
|
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
447
482
|
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
448
483
|
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
449
|
-
const
|
|
484
|
+
const isAbandonedNativeOperationError = (error) => {
|
|
450
485
|
const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
451
|
-
return (errorCode === reactNativeBlePlx.BleErrorCode.
|
|
452
|
-
errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled);
|
|
486
|
+
return (errorCode === reactNativeBlePlx.BleErrorCode.OperationTimedOut || errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled);
|
|
453
487
|
};
|
|
454
488
|
const tryToGetConfiguration = (device) => {
|
|
455
489
|
if (!device || !device.serviceUUIDs)
|
|
@@ -464,7 +498,7 @@ const tryToGetConfiguration = (device) => {
|
|
|
464
498
|
};
|
|
465
499
|
const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
466
500
|
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
467
|
-
return { device,
|
|
501
|
+
return { device, abandoned: false };
|
|
468
502
|
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
469
503
|
let timeoutId;
|
|
470
504
|
let timedOut = false;
|
|
@@ -480,7 +514,7 @@ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __aw
|
|
|
480
514
|
}, BLE_MTU_REQUEST_TIMEOUT_MS);
|
|
481
515
|
}),
|
|
482
516
|
]);
|
|
483
|
-
return { device: mtuDevice,
|
|
517
|
+
return { device: mtuDevice, abandoned: false };
|
|
484
518
|
}
|
|
485
519
|
catch (error) {
|
|
486
520
|
if (timedOut && cancelTransaction) {
|
|
@@ -508,10 +542,9 @@ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __aw
|
|
|
508
542
|
stage,
|
|
509
543
|
attempt,
|
|
510
544
|
actual: device.mtu,
|
|
511
|
-
timedOut,
|
|
512
545
|
error: error instanceof Error ? error.message : String(error),
|
|
513
546
|
});
|
|
514
|
-
return { device, timedOut };
|
|
547
|
+
return { device, abandoned: timedOut };
|
|
515
548
|
}
|
|
516
549
|
finally {
|
|
517
550
|
if (timeoutId)
|
|
@@ -520,7 +553,7 @@ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __aw
|
|
|
520
553
|
});
|
|
521
554
|
const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
|
|
522
555
|
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
523
|
-
: Promise.resolve({ device,
|
|
556
|
+
: Promise.resolve({ device, abandoned: false });
|
|
524
557
|
function remapError(error) {
|
|
525
558
|
var _a;
|
|
526
559
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -557,6 +590,12 @@ class ReactNativeBleTransport {
|
|
|
557
590
|
this.sessionProtocols = new Map();
|
|
558
591
|
this.confirmedProtocolV2 = new Set();
|
|
559
592
|
this.protocolReprobeFailures = new Map();
|
|
593
|
+
this.silentDetections = new Set();
|
|
594
|
+
this.androidGattCacheRefreshes = new Set();
|
|
595
|
+
this.androidMtuExchangeTimeoutMs = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
|
|
596
|
+
this.androidLinkDropQuietMs = ANDROID_LINK_DROP_QUIET_MS;
|
|
597
|
+
this.androidLinkDropTimeoutMs = ANDROID_LINK_DROP_TIMEOUT_MS;
|
|
598
|
+
this.protocolWakeAttempts = new Set();
|
|
560
599
|
this.staleBondErrors = new Map();
|
|
561
600
|
this.acquiringProtocolV2 = new Set();
|
|
562
601
|
this.protocolV2Assemblers = new Map();
|
|
@@ -790,9 +829,10 @@ class ReactNativeBleTransport {
|
|
|
790
829
|
transport.notifySubscription = undefined;
|
|
791
830
|
let { device } = transport;
|
|
792
831
|
const isConnected = yield device.isConnected().catch(() => false);
|
|
832
|
+
const reconnectOptions = reactNative.Platform.OS === 'android' ? androidRefreshGattConnectOptions : connectOptions;
|
|
793
833
|
if (!isConnected) {
|
|
794
834
|
try {
|
|
795
|
-
device = yield this.connectWithTimeout(uuid, () => device.connect(
|
|
835
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect(reconnectOptions));
|
|
796
836
|
}
|
|
797
837
|
catch (e) {
|
|
798
838
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
@@ -805,7 +845,16 @@ class ReactNativeBleTransport {
|
|
|
805
845
|
}
|
|
806
846
|
}
|
|
807
847
|
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, device);
|
|
848
|
+
if (reactNative.Platform.OS === 'android') {
|
|
849
|
+
const manager = yield this.getPlxManager();
|
|
850
|
+
device = yield this.negotiateAndroidMtu(uuid, manager, device);
|
|
851
|
+
if (isKnownDefaultMtu(device.mtu)) {
|
|
852
|
+
yield this.dropAndroidLink(uuid, manager, device, 'firmware reconnect default mtu');
|
|
853
|
+
throw createDefaultMtuLinkError(device.mtu);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
808
856
|
transport.device = device;
|
|
857
|
+
transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport.mtuSize;
|
|
809
858
|
transport.writeCharacteristic = writeCharacteristic;
|
|
810
859
|
transport.notifyCharacteristic = notifyCharacteristic;
|
|
811
860
|
const monitorToken = this.nextMonitorToken;
|
|
@@ -952,7 +1001,7 @@ class ReactNativeBleTransport {
|
|
|
952
1001
|
}
|
|
953
1002
|
installTransportForAcquire(uuid, device, characteristics) {
|
|
954
1003
|
return __awaiter(this, void 0, void 0, function* () {
|
|
955
|
-
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.
|
|
1004
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsForAcquire(uuid, device));
|
|
956
1005
|
if (this.stopped)
|
|
957
1006
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
958
1007
|
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
@@ -1030,7 +1079,11 @@ class ReactNativeBleTransport {
|
|
|
1030
1079
|
const isCachedDeviceConnected = yield cachedTransport.device
|
|
1031
1080
|
.isConnected()
|
|
1032
1081
|
.catch(() => false);
|
|
1082
|
+
const isCachedAndroidLinkUsable = reactNative.Platform.OS !== 'android' ||
|
|
1083
|
+
(!isKnownDefaultMtu(cachedTransport.mtuSize) &&
|
|
1084
|
+
!this.androidGattCacheRefreshes.has(uuid));
|
|
1033
1085
|
if (isCachedDeviceConnected &&
|
|
1086
|
+
isCachedAndroidLinkUsable &&
|
|
1034
1087
|
cachedProtocol &&
|
|
1035
1088
|
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
1036
1089
|
if (this.stopped)
|
|
@@ -1043,6 +1096,15 @@ class ReactNativeBleTransport {
|
|
|
1043
1096
|
}
|
|
1044
1097
|
}
|
|
1045
1098
|
let device = null;
|
|
1099
|
+
const isAndroid = reactNative.Platform.OS === 'android';
|
|
1100
|
+
const refreshAndroidGattCache = isAndroid && (!!skipProtocolProbe || this.androidGattCacheRefreshes.has(uuid));
|
|
1101
|
+
let nativeConnectOptions = connectOptions;
|
|
1102
|
+
if (isAndroid) {
|
|
1103
|
+
nativeConnectOptions = refreshAndroidGattCache
|
|
1104
|
+
? androidRefreshGattConnectOptions
|
|
1105
|
+
: androidConnectOptions;
|
|
1106
|
+
}
|
|
1107
|
+
let androidRefreshConnectRan = false;
|
|
1046
1108
|
if (forceCleanRunPromise && this.runPromise) {
|
|
1047
1109
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1048
1110
|
this.runPromise.reject(error);
|
|
@@ -1051,7 +1113,6 @@ class ReactNativeBleTransport {
|
|
|
1051
1113
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
1052
1114
|
}
|
|
1053
1115
|
const blePlxManager = yield this.getPlxManager();
|
|
1054
|
-
let skipPostConnectMtu = false;
|
|
1055
1116
|
try {
|
|
1056
1117
|
yield subscribeBleOn(blePlxManager);
|
|
1057
1118
|
}
|
|
@@ -1093,16 +1154,18 @@ class ReactNativeBleTransport {
|
|
|
1093
1154
|
if (!device) {
|
|
1094
1155
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
1095
1156
|
try {
|
|
1096
|
-
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid,
|
|
1157
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, nativeConnectOptions));
|
|
1158
|
+
androidRefreshConnectRan = refreshAndroidGattCache;
|
|
1097
1159
|
}
|
|
1098
1160
|
catch (e) {
|
|
1099
1161
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
1100
1162
|
if (shouldRethrowBleSetupError(e)) {
|
|
1101
1163
|
throw e;
|
|
1102
1164
|
}
|
|
1103
|
-
if (
|
|
1104
|
-
|
|
1165
|
+
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
1166
|
+
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
1105
1167
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
1168
|
+
yield this.runBestEffortNativeOperation('connect cancelled: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid));
|
|
1106
1169
|
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
1107
1170
|
}
|
|
1108
1171
|
else if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
@@ -1117,20 +1180,27 @@ class ReactNativeBleTransport {
|
|
|
1117
1180
|
if (!device) {
|
|
1118
1181
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'unable to connect to device');
|
|
1119
1182
|
}
|
|
1183
|
+
if (isAndroid && refreshAndroidGattCache && (yield device.isConnected().catch(() => false))) {
|
|
1184
|
+
yield this.dropAndroidLink(uuid, blePlxManager, device, 'gatt cache refresh');
|
|
1185
|
+
if (this.stopped)
|
|
1186
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1187
|
+
}
|
|
1120
1188
|
if (!(yield device.isConnected())) {
|
|
1121
1189
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
1122
1190
|
const disconnectedDevice = device;
|
|
1123
1191
|
try {
|
|
1124
|
-
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(
|
|
1192
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(nativeConnectOptions));
|
|
1193
|
+
androidRefreshConnectRan = refreshAndroidGattCache;
|
|
1125
1194
|
}
|
|
1126
1195
|
catch (e) {
|
|
1127
1196
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
1128
1197
|
if (shouldRethrowBleSetupError(e)) {
|
|
1129
1198
|
throw e;
|
|
1130
1199
|
}
|
|
1131
|
-
if (
|
|
1132
|
-
|
|
1200
|
+
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
1201
|
+
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
1133
1202
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
1203
|
+
yield this.runBestEffortNativeOperation('connect cancelled: cancel device connection', () => disconnectedDevice.cancelConnection());
|
|
1134
1204
|
try {
|
|
1135
1205
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
1136
1206
|
}
|
|
@@ -1165,24 +1235,38 @@ class ReactNativeBleTransport {
|
|
|
1165
1235
|
}
|
|
1166
1236
|
if (this.stopped)
|
|
1167
1237
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
if (
|
|
1173
|
-
|
|
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());
|
|
1238
|
+
let characteristics;
|
|
1239
|
+
if (isAndroid) {
|
|
1240
|
+
if (refreshAndroidGattCache) {
|
|
1241
|
+
characteristics = yield this.resolveCharacteristicsForAcquire(uuid, device);
|
|
1242
|
+
if (androidRefreshConnectRan)
|
|
1243
|
+
this.androidGattCacheRefreshes.delete(uuid);
|
|
1177
1244
|
if (this.stopped)
|
|
1178
1245
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1179
|
-
|
|
1246
|
+
}
|
|
1247
|
+
device = yield this.negotiateAndroidMtu(uuid, blePlxManager, device);
|
|
1248
|
+
if (isKnownDefaultMtu(device.mtu)) {
|
|
1249
|
+
const resetManager = this.abandonStalledConnection(uuid, 'mtu-default');
|
|
1250
|
+
yield this.dropAndroidLink(uuid, blePlxManager, device, 'default mtu');
|
|
1251
|
+
if (resetManager)
|
|
1252
|
+
throw this.createWedgedBleSetupError();
|
|
1253
|
+
throw createDefaultMtuLinkError(device.mtu);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
else {
|
|
1257
|
+
const negotiatedMtu = yield resolveNegotiatedMtu(device, transactionId => blePlxManager.cancelTransaction(transactionId));
|
|
1258
|
+
device = negotiatedMtu.device;
|
|
1259
|
+
if (negotiatedMtu.abandoned) {
|
|
1260
|
+
yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1261
|
+
yield this.runBestEffortNativeOperation('mtu abandoned: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid));
|
|
1262
|
+
}));
|
|
1263
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'BLE MTU negotiation abandoned, reconnecting');
|
|
1180
1264
|
}
|
|
1181
1265
|
}
|
|
1182
1266
|
if (this.stopped)
|
|
1183
1267
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1184
1268
|
const acquiredDevice = device;
|
|
1185
|
-
const { writeCharacteristic, notifyCharacteristic } = yield this.
|
|
1269
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsForAcquire(uuid, acquiredDevice));
|
|
1186
1270
|
if (this.stopped)
|
|
1187
1271
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1188
1272
|
const protocolHint = expectedProtocol
|
|
@@ -1278,6 +1362,9 @@ class ReactNativeBleTransport {
|
|
|
1278
1362
|
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('notify change failed for device'))) {
|
|
1279
1363
|
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
1280
1364
|
}
|
|
1365
|
+
if (reactNative.Platform.OS === 'android' && isStaleGattTableNotifyReason(error.reason)) {
|
|
1366
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
1367
|
+
}
|
|
1281
1368
|
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
1282
1369
|
return;
|
|
1283
1370
|
}
|
|
@@ -1292,6 +1379,9 @@ class ReactNativeBleTransport {
|
|
|
1292
1379
|
((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Writing is not permitted')) ||
|
|
1293
1380
|
((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('notify change failed for device'))) {
|
|
1294
1381
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
1382
|
+
if (reactNative.Platform.OS === 'android' && isStaleGattTableNotifyReason(error.reason)) {
|
|
1383
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
1384
|
+
}
|
|
1295
1385
|
this.runPromise.reject(notifyError);
|
|
1296
1386
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
1297
1387
|
return;
|
|
@@ -1826,6 +1916,111 @@ class ReactNativeBleTransport {
|
|
|
1826
1916
|
}
|
|
1827
1917
|
});
|
|
1828
1918
|
}
|
|
1919
|
+
negotiateAndroidMtu(uuid, manager, device) {
|
|
1920
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1921
|
+
if (!shouldRefreshNegotiatedMtu(device.mtu))
|
|
1922
|
+
return device;
|
|
1923
|
+
const startedAt = Date.now();
|
|
1924
|
+
const transactionId = `${device.id}:mtu:connected:0:${startedAt}`;
|
|
1925
|
+
let timer;
|
|
1926
|
+
let timedOut = false;
|
|
1927
|
+
const request = device.requestMTU(ANDROID_REQUEST_MTU, transactionId);
|
|
1928
|
+
request.catch(() => undefined);
|
|
1929
|
+
try {
|
|
1930
|
+
const negotiated = yield Promise.race([
|
|
1931
|
+
request,
|
|
1932
|
+
new Promise((_, reject) => {
|
|
1933
|
+
timer = setTimeout(() => {
|
|
1934
|
+
timedOut = true;
|
|
1935
|
+
reject(new Error(`BLE MTU exchange timeout after ${this.androidMtuExchangeTimeoutMs}ms`));
|
|
1936
|
+
}, this.androidMtuExchangeTimeoutMs);
|
|
1937
|
+
}),
|
|
1938
|
+
]);
|
|
1939
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU exchange completed', {
|
|
1940
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1941
|
+
elapsedMs: Date.now() - startedAt,
|
|
1942
|
+
actual: negotiated.mtu,
|
|
1943
|
+
});
|
|
1944
|
+
return negotiated;
|
|
1945
|
+
}
|
|
1946
|
+
catch (error) {
|
|
1947
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU exchange failed', {
|
|
1948
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1949
|
+
elapsedMs: Date.now() - startedAt,
|
|
1950
|
+
timedOut,
|
|
1951
|
+
actual: device.mtu,
|
|
1952
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1953
|
+
});
|
|
1954
|
+
if (this.stopped)
|
|
1955
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1956
|
+
if (!timedOut)
|
|
1957
|
+
return device;
|
|
1958
|
+
yield Promise.resolve(manager.cancelTransaction(transactionId)).catch(() => undefined);
|
|
1959
|
+
const resetManager = this.abandonStalledConnection(uuid, 'mtu-backstop');
|
|
1960
|
+
yield this.dropAndroidLink(uuid, manager, device, 'mtu exchange timeout');
|
|
1961
|
+
if (resetManager)
|
|
1962
|
+
throw this.createWedgedBleSetupError();
|
|
1963
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'BLE MTU exchange did not complete, reconnecting on a fresh link');
|
|
1964
|
+
}
|
|
1965
|
+
finally {
|
|
1966
|
+
if (timer)
|
|
1967
|
+
clearTimeout(timer);
|
|
1968
|
+
}
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
dropAndroidLink(uuid, manager, device, reason) {
|
|
1972
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1973
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1974
|
+
yield Promise.all([
|
|
1975
|
+
this.runBestEffortNativeOperation(`${reason}: cancel manager connection`, () => manager.cancelDeviceConnection(uuid)),
|
|
1976
|
+
this.runBestEffortNativeOperation(`${reason}: cancel device connection`, () => device.cancelConnection()),
|
|
1977
|
+
]);
|
|
1978
|
+
}));
|
|
1979
|
+
const startedAt = Date.now();
|
|
1980
|
+
const target = uuid.toUpperCase();
|
|
1981
|
+
let registryClear = false;
|
|
1982
|
+
let quietPeriodElapsed = false;
|
|
1983
|
+
while (!this.stopped) {
|
|
1984
|
+
const elapsed = Date.now() - startedAt;
|
|
1985
|
+
quietPeriodElapsed = elapsed >= this.androidLinkDropQuietMs;
|
|
1986
|
+
if (!registryClear) {
|
|
1987
|
+
const connected = yield getConnectedDeviceIds([]).catch(() => undefined);
|
|
1988
|
+
registryClear =
|
|
1989
|
+
!!connected &&
|
|
1990
|
+
!connected.some(peripheral => { var _a; return String((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.id) !== null && _a !== void 0 ? _a : '').toUpperCase() === target; });
|
|
1991
|
+
}
|
|
1992
|
+
if ((registryClear && quietPeriodElapsed) || elapsed >= this.androidLinkDropTimeoutMs) {
|
|
1993
|
+
break;
|
|
1994
|
+
}
|
|
1995
|
+
yield delay(ANDROID_LINK_DROP_POLL_MS);
|
|
1996
|
+
}
|
|
1997
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE link drop', {
|
|
1998
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1999
|
+
reason,
|
|
2000
|
+
registryClear,
|
|
2001
|
+
quietPeriodElapsed,
|
|
2002
|
+
stopped: this.stopped,
|
|
2003
|
+
elapsedMs: Date.now() - startedAt,
|
|
2004
|
+
});
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
resolveCharacteristicsForAcquire(uuid, device) {
|
|
2008
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2009
|
+
try {
|
|
2010
|
+
return yield this.resolveCharacteristicsWithTimeout(uuid, device);
|
|
2011
|
+
}
|
|
2012
|
+
catch (error) {
|
|
2013
|
+
if (reactNative.Platform.OS === 'android' && isMissingGattShapeError(error)) {
|
|
2014
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
2015
|
+
const manager = this.blePlxManager;
|
|
2016
|
+
if (manager) {
|
|
2017
|
+
yield this.dropAndroidLink(uuid, manager, device, 'stale gatt table');
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
throw error;
|
|
2021
|
+
}
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
1829
2024
|
connectWithTimeout(uuid, connect) {
|
|
1830
2025
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1831
2026
|
if (this.stopped)
|
|
@@ -1893,7 +2088,7 @@ class ReactNativeBleTransport {
|
|
|
1893
2088
|
return result;
|
|
1894
2089
|
}
|
|
1895
2090
|
catch (error) {
|
|
1896
|
-
if (timedOut ||
|
|
2091
|
+
if (timedOut || isAbandonedNativeOperationError(error)) {
|
|
1897
2092
|
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1898
2093
|
if (resetManager) {
|
|
1899
2094
|
throw this.createWedgedBleSetupError();
|
|
@@ -2050,6 +2245,8 @@ class ReactNativeBleTransport {
|
|
|
2050
2245
|
this.acquiringProtocolV2.clear();
|
|
2051
2246
|
this.sessionProtocols.clear();
|
|
2052
2247
|
this.protocolReprobeFailures.clear();
|
|
2248
|
+
this.silentDetections.clear();
|
|
2249
|
+
this.protocolWakeAttempts.clear();
|
|
2053
2250
|
this.writeTimeoutCounts.clear();
|
|
2054
2251
|
this.connectionSetupTimeoutCounts.clear();
|
|
2055
2252
|
this.monitorTokens.clear();
|
|
@@ -2123,6 +2320,7 @@ class ReactNativeBleTransport {
|
|
|
2123
2320
|
!protocolHint &&
|
|
2124
2321
|
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
2125
2322
|
const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
2323
|
+
yield this.wakeSilentProtocolV1Device(uuid, probeOrder);
|
|
2126
2324
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
2127
2325
|
const protocol = probeOrder[i];
|
|
2128
2326
|
if (i > 0) {
|
|
@@ -2142,6 +2340,8 @@ class ReactNativeBleTransport {
|
|
|
2142
2340
|
this.confirmedProtocolV2.add(uuid);
|
|
2143
2341
|
}
|
|
2144
2342
|
this.protocolReprobeFailures.delete(uuid);
|
|
2343
|
+
this.silentDetections.delete(uuid);
|
|
2344
|
+
this.protocolWakeAttempts.delete(uuid);
|
|
2145
2345
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
2146
2346
|
deviceId: uuid,
|
|
2147
2347
|
protocol,
|
|
@@ -2150,6 +2350,7 @@ class ReactNativeBleTransport {
|
|
|
2150
2350
|
return protocol;
|
|
2151
2351
|
}
|
|
2152
2352
|
}
|
|
2353
|
+
this.silentDetections.add(uuid);
|
|
2153
2354
|
if (trustSessionProtocol) {
|
|
2154
2355
|
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
2155
2356
|
}
|
|
@@ -2161,6 +2362,38 @@ class ReactNativeBleTransport {
|
|
|
2161
2362
|
throw this.createProtocolDetectionError();
|
|
2162
2363
|
});
|
|
2163
2364
|
}
|
|
2365
|
+
wakeSilentProtocolV1Device(uuid, probeOrder) {
|
|
2366
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2367
|
+
if (!this._messages)
|
|
2368
|
+
return;
|
|
2369
|
+
if (!probeOrder.includes('V1'))
|
|
2370
|
+
return;
|
|
2371
|
+
if (!this.silentDetections.has(uuid))
|
|
2372
|
+
return;
|
|
2373
|
+
if (this.protocolWakeAttempts.has(uuid))
|
|
2374
|
+
return;
|
|
2375
|
+
if (!transportCache[uuid])
|
|
2376
|
+
return;
|
|
2377
|
+
this.protocolWakeAttempts.add(uuid);
|
|
2378
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] sending Protocol V1 Initialize wake', {
|
|
2379
|
+
connectIdSuffix: uuid.slice(-8),
|
|
2380
|
+
});
|
|
2381
|
+
try {
|
|
2382
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
2383
|
+
yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
2384
|
+
}
|
|
2385
|
+
catch (error) {
|
|
2386
|
+
if (shouldRethrowProtocolProbeError(error)) {
|
|
2387
|
+
this.clearProbeProtocol(uuid, 'V1');
|
|
2388
|
+
throw error;
|
|
2389
|
+
}
|
|
2390
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize wake did not answer:', error);
|
|
2391
|
+
}
|
|
2392
|
+
finally {
|
|
2393
|
+
this.clearProbeProtocol(uuid, 'V1');
|
|
2394
|
+
}
|
|
2395
|
+
});
|
|
2396
|
+
}
|
|
2164
2397
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
2165
2398
|
var _a, _b, _c;
|
|
2166
2399
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -2415,6 +2648,12 @@ class ReactNativeBleTransport {
|
|
|
2415
2648
|
if (!this._messages || !this._messagesV2) {
|
|
2416
2649
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
2417
2650
|
}
|
|
2651
|
+
if (reactNative.Platform.OS === 'android') {
|
|
2652
|
+
const activeTransport = transportCache[uuid];
|
|
2653
|
+
if (activeTransport && isKnownDefaultMtu(activeTransport.mtuSize)) {
|
|
2654
|
+
throw createProtocolV2DefaultMtuError(activeTransport.mtuSize);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2418
2657
|
const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
|
|
2419
2658
|
const callOptions = options;
|
|
2420
2659
|
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
@@ -2478,11 +2717,11 @@ class ReactNativeBleTransport {
|
|
|
2478
2717
|
const transport = this.getCachedTransport(uuid);
|
|
2479
2718
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2480
2719
|
return;
|
|
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); });
|
|
2720
|
+
const { device: refreshedDevice, abandoned } = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1, transactionId => { var _a; return (_a = this.blePlxManager) === null || _a === void 0 ? void 0 : _a.cancelTransaction(transactionId); });
|
|
2482
2721
|
transport.device = refreshedDevice;
|
|
2483
2722
|
transport.mtuSize =
|
|
2484
2723
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
2485
|
-
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
2724
|
+
if (abandoned || shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
2486
2725
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Protocol V2 high-throughput BLE MTU unavailable: ${String(transport.mtuSize)}`);
|
|
2487
2726
|
}
|
|
2488
2727
|
});
|
|
@@ -2595,6 +2834,9 @@ class ReactNativeBleTransport {
|
|
|
2595
2834
|
}
|
|
2596
2835
|
}
|
|
2597
2836
|
|
|
2837
|
+
exports.ANDROID_LINK_DROP_QUIET_MS = ANDROID_LINK_DROP_QUIET_MS;
|
|
2838
|
+
exports.ANDROID_LINK_DROP_TIMEOUT_MS = ANDROID_LINK_DROP_TIMEOUT_MS;
|
|
2839
|
+
exports.ANDROID_MTU_EXCHANGE_TIMEOUT_MS = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
|
|
2598
2840
|
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2599
2841
|
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2600
2842
|
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|
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.116",
|
|
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.116",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.116",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.116",
|
|
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": "222deb57d08349d95cfcaa8fac4b705e3aeaff8a"
|
|
30
30
|
}
|