@onekeyfe/hd-transport-react-native 1.2.0-alpha.53 → 1.2.0-alpha.54
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 +38 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +160 -74
- package/jest.config.js +5 -0
- package/package.json +5 -5
- package/src/__tests__/protocolV2Link.test.ts +41 -230
- package/src/__tests__/staleCallTimeout.test.ts +211 -0
- package/src/__tests__/writePacketTimeout.test.ts +306 -0
- package/src/index.ts +235 -74
- package/src/__tests__/enumerate.test.ts +0 -132
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,17 @@ type ResolvedBleCharacteristics = {
|
|
|
35
35
|
notifyCharacteristic: Characteristic;
|
|
36
36
|
};
|
|
37
37
|
declare const getFirmwareUploadWriteRetryType: (error: unknown) => FirmwareUploadWriteRetryType | null;
|
|
38
|
+
/**
|
|
39
|
+
* Per-packet write budget. iOS only resolves writeWithoutResponse once CoreBluetooth
|
|
40
|
+
* reports the peripheral ready again; a peripheral wedged by its own firmware reboot
|
|
41
|
+
* stops reporting ready while staying connected, so the write promise never settles.
|
|
42
|
+
* Response timeouts cannot cover that — they are armed after the writes complete —
|
|
43
|
+
* and an unbounded write leaves the whole transport unusable until the process dies.
|
|
44
|
+
* A healthy packet completes in milliseconds, so this only fires on a dead link.
|
|
45
|
+
*/
|
|
46
|
+
declare const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
|
|
47
|
+
/** Consecutive wedged writes on one device before the BLE manager itself is recreated. */
|
|
48
|
+
declare const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
38
49
|
type ProtocolV2BleTuning = {
|
|
39
50
|
iosPacketLength?: number;
|
|
40
51
|
androidPacketLength?: number;
|
|
@@ -61,6 +72,15 @@ declare class ReactNativeBleTransport {
|
|
|
61
72
|
firmwareUploadWriteRecoveryIds: Set<string>;
|
|
62
73
|
/** Per-device protocol type detected by active wire-level probe after connect. */
|
|
63
74
|
private deviceProtocol;
|
|
75
|
+
/**
|
|
76
|
+
* Protocol a probe is currently trying, before the device has confirmed it. Calls
|
|
77
|
+
* must route with it, but acquire() must not treat it as a detected protocol: a
|
|
78
|
+
* probe that never answers would otherwise leave the reuse fast path handing out a
|
|
79
|
+
* transport that was never validated.
|
|
80
|
+
*/
|
|
81
|
+
private probingProtocols;
|
|
82
|
+
/** Consecutive write timeouts per device; reset by any write that completes. */
|
|
83
|
+
private writeTimeoutCounts;
|
|
64
84
|
private deviceProtocolHints;
|
|
65
85
|
private protocolV2Assemblers;
|
|
66
86
|
private protocolV2FrameQueues;
|
|
@@ -100,9 +120,26 @@ declare class ReactNativeBleTransport {
|
|
|
100
120
|
disconnect(session: string): Promise<void>;
|
|
101
121
|
cancel(): void;
|
|
102
122
|
private getCachedTransport;
|
|
123
|
+
/**
|
|
124
|
+
* Write one packet under a bounded budget. A write that never settles means the
|
|
125
|
+
* peripheral is wedged even though the GATT link still reports connected, so the
|
|
126
|
+
* link is torn down: releasing JS state alone would leave the poisoned peripheral
|
|
127
|
+
* cached and every later call would hang on it again.
|
|
128
|
+
*/
|
|
129
|
+
private writeBlePacket;
|
|
130
|
+
/**
|
|
131
|
+
* Drop a link whose writes stopped completing. The JS state is purged synchronously
|
|
132
|
+
* so the next acquire() cannot reuse the dead transport, while the native teardown is
|
|
133
|
+
* intentionally NOT awaited: it talks to the very layer that just stopped settling
|
|
134
|
+
* promises, so awaiting it could hang exactly like the write it is recovering from.
|
|
135
|
+
*/
|
|
136
|
+
private tearDownWedgedLink;
|
|
137
|
+
private resetPlxManager;
|
|
103
138
|
private createProtocolMismatchError;
|
|
104
139
|
private createProtocolDetectionError;
|
|
105
140
|
private clearProbeProtocol;
|
|
141
|
+
/** Protocol to route a call with: confirmed if known, otherwise the one being probed. */
|
|
142
|
+
private getActiveProtocol;
|
|
106
143
|
private detectProtocol;
|
|
107
144
|
private resetProbeStateAfterProtocolProbe;
|
|
108
145
|
private probeProtocolV1;
|
|
@@ -120,4 +157,4 @@ declare class ReactNativeBleTransport {
|
|
|
120
157
|
getProtocolType(path: string): ProtocolType | undefined;
|
|
121
158
|
}
|
|
122
159
|
|
|
123
|
-
export { IOneKeyDevice, ProtocolV2BleTuning, configureProtocolV2BleTuning, ReactNativeBleTransport as default, getFirmwareUploadWriteRetryType, getProtocolV2BleTuning, resetProtocolV2BleTuning };
|
|
160
|
+
export { BLE_WRITE_PACKET_TIMEOUT_MS, BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD, IOneKeyDevice, ProtocolV2BleTuning, configureProtocolV2BleTuning, ReactNativeBleTransport as default, getFirmwareUploadWriteRetryType, getProtocolV2BleTuning, resetProtocolV2BleTuning };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAG1B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -222,7 +222,6 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 :
|
|
|
222
222
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
223
223
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
224
224
|
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
225
|
-
const IOS_PROTOCOL_V2_CONTROL_WRITE_DELAY_MS = 5;
|
|
226
225
|
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
227
226
|
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
228
227
|
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
@@ -245,6 +244,12 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
245
244
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
246
245
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
247
246
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
247
|
+
const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
|
|
248
|
+
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
249
|
+
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
250
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
251
|
+
error.message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
252
|
+
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
248
253
|
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
249
254
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
250
255
|
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
@@ -342,6 +347,8 @@ class ReactNativeBleTransport {
|
|
|
342
347
|
this.runPromiseDeviceId = null;
|
|
343
348
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
344
349
|
this.deviceProtocol = new Map();
|
|
350
|
+
this.probingProtocols = new Map();
|
|
351
|
+
this.writeTimeoutCounts = new Map();
|
|
345
352
|
this.deviceProtocolHints = new Map();
|
|
346
353
|
this.protocolV2Assemblers = new Map();
|
|
347
354
|
this.protocolV2FrameQueues = new Map();
|
|
@@ -615,17 +622,12 @@ class ReactNativeBleTransport {
|
|
|
615
622
|
return;
|
|
616
623
|
}
|
|
617
624
|
const displayName = getDeviceDisplayName(device);
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
id: device === null || device === void 0 ? void 0 : device.id,
|
|
625
|
-
name: device === null || device === void 0 ? void 0 : device.name,
|
|
626
|
-
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
627
|
-
serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
628
|
-
});
|
|
625
|
+
const isOneKey = hdShared.isOnekeyBluetoothDevice({
|
|
626
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
627
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
628
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
629
|
+
serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
630
|
+
});
|
|
629
631
|
if (isOneKey) {
|
|
630
632
|
addDevice(device);
|
|
631
633
|
}
|
|
@@ -643,15 +645,12 @@ class ReactNativeBleTransport {
|
|
|
643
645
|
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
644
646
|
? device.localName
|
|
645
647
|
: null;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
localName,
|
|
653
|
-
serviceUuids: device.serviceUUIDs,
|
|
654
|
-
})) {
|
|
648
|
+
if (hdShared.isOnekeyBluetoothDevice({
|
|
649
|
+
id: device.id,
|
|
650
|
+
name: device.name,
|
|
651
|
+
localName,
|
|
652
|
+
serviceUuids: device.serviceUUIDs,
|
|
653
|
+
})) {
|
|
655
654
|
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
656
655
|
addDevice(device);
|
|
657
656
|
}
|
|
@@ -861,7 +860,7 @@ class ReactNativeBleTransport {
|
|
|
861
860
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
862
861
|
return;
|
|
863
862
|
}
|
|
864
|
-
if (this.
|
|
863
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
865
864
|
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
866
865
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
867
866
|
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
@@ -912,7 +911,7 @@ class ReactNativeBleTransport {
|
|
|
912
911
|
}
|
|
913
912
|
try {
|
|
914
913
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
915
|
-
const protocol = this.
|
|
914
|
+
const protocol = this.getActiveProtocol(uuid);
|
|
916
915
|
if (!protocol) {
|
|
917
916
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
918
917
|
return;
|
|
@@ -940,7 +939,7 @@ class ReactNativeBleTransport {
|
|
|
940
939
|
catch (error) {
|
|
941
940
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
942
941
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
943
|
-
if (this.
|
|
942
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
944
943
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
945
944
|
}
|
|
946
945
|
else if (this.runPromiseDeviceId === uuid) {
|
|
@@ -996,6 +995,7 @@ class ReactNativeBleTransport {
|
|
|
996
995
|
delete transportCache[uuid];
|
|
997
996
|
}
|
|
998
997
|
this.deviceProtocol.delete(uuid);
|
|
998
|
+
this.probingProtocols.delete(uuid);
|
|
999
999
|
(_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
|
|
1000
1000
|
this.protocolV2Assemblers.delete(uuid);
|
|
1001
1001
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -1044,8 +1044,19 @@ class ReactNativeBleTransport {
|
|
|
1044
1044
|
const transport = this.getCachedTransport(uuid);
|
|
1045
1045
|
const runPromise = hdShared.createDeferred();
|
|
1046
1046
|
runPromise.promise.catch(() => undefined);
|
|
1047
|
+
const supersededRunPromise = this.runPromise;
|
|
1048
|
+
if (supersededRunPromise) {
|
|
1049
|
+
supersededRunPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
|
|
1050
|
+
}
|
|
1047
1051
|
this.runPromise = runPromise;
|
|
1048
1052
|
this.runPromiseDeviceId = uuid;
|
|
1053
|
+
const releaseOwnershipIfCurrent = () => {
|
|
1054
|
+
if (this.runPromise === runPromise) {
|
|
1055
|
+
this.runPromise = null;
|
|
1056
|
+
this.runPromiseDeviceId = null;
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
const isCurrentOwner = () => this.runPromise === runPromise;
|
|
1049
1060
|
const messages = this._messages;
|
|
1050
1061
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1051
1062
|
let timeout;
|
|
@@ -1066,6 +1077,9 @@ class ReactNativeBleTransport {
|
|
|
1066
1077
|
}
|
|
1067
1078
|
catch (e) {
|
|
1068
1079
|
onError(e);
|
|
1080
|
+
if (isWedgedWriteError(e)) {
|
|
1081
|
+
throw e;
|
|
1082
|
+
}
|
|
1069
1083
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1070
1084
|
}
|
|
1071
1085
|
}
|
|
@@ -1093,6 +1107,9 @@ class ReactNativeBleTransport {
|
|
|
1093
1107
|
}
|
|
1094
1108
|
catch (e) {
|
|
1095
1109
|
onError(e);
|
|
1110
|
+
if (isWedgedWriteError(e)) {
|
|
1111
|
+
throw e;
|
|
1112
|
+
}
|
|
1096
1113
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1097
1114
|
}
|
|
1098
1115
|
}
|
|
@@ -1103,8 +1120,8 @@ class ReactNativeBleTransport {
|
|
|
1103
1120
|
});
|
|
1104
1121
|
}
|
|
1105
1122
|
if (name === 'EmmcFileWrite') {
|
|
1106
|
-
yield writeChunkedData(buffers, data => transport.writeWithRetry(
|
|
1107
|
-
|
|
1123
|
+
yield writeChunkedData(buffers, data => this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner), e => {
|
|
1124
|
+
releaseOwnershipIfCurrent();
|
|
1108
1125
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1109
1126
|
});
|
|
1110
1127
|
}
|
|
@@ -1120,7 +1137,7 @@ class ReactNativeBleTransport {
|
|
|
1120
1137
|
let attempt = 0;
|
|
1121
1138
|
while (true) {
|
|
1122
1139
|
try {
|
|
1123
|
-
yield transport.writeCharacteristic.writeWithoutResponse(
|
|
1140
|
+
yield this.writeBlePacket(uuid, data, payload => transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1124
1141
|
return;
|
|
1125
1142
|
}
|
|
1126
1143
|
catch (error) {
|
|
@@ -1139,7 +1156,7 @@ class ReactNativeBleTransport {
|
|
|
1139
1156
|
}
|
|
1140
1157
|
}
|
|
1141
1158
|
}), e => {
|
|
1142
|
-
|
|
1159
|
+
releaseOwnershipIfCurrent();
|
|
1143
1160
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1144
1161
|
});
|
|
1145
1162
|
}
|
|
@@ -1147,17 +1164,14 @@ class ReactNativeBleTransport {
|
|
|
1147
1164
|
for (const o of buffers) {
|
|
1148
1165
|
const outData = o.toString('base64');
|
|
1149
1166
|
try {
|
|
1150
|
-
|
|
1151
|
-
if (shouldUseWriteWithResponse) {
|
|
1152
|
-
yield transport.writeCharacteristic.writeWithResponse(outData);
|
|
1153
|
-
}
|
|
1154
|
-
else {
|
|
1155
|
-
yield transport.writeCharacteristic.writeWithoutResponse(outData);
|
|
1156
|
-
}
|
|
1167
|
+
yield this.writeBlePacket(uuid, outData, payload => transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1157
1168
|
}
|
|
1158
1169
|
catch (e) {
|
|
1159
1170
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
1160
|
-
|
|
1171
|
+
releaseOwnershipIfCurrent();
|
|
1172
|
+
if (isWedgedWriteError(e)) {
|
|
1173
|
+
throw e;
|
|
1174
|
+
}
|
|
1161
1175
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected) {
|
|
1162
1176
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded);
|
|
1163
1177
|
}
|
|
@@ -1197,7 +1211,9 @@ class ReactNativeBleTransport {
|
|
|
1197
1211
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1198
1212
|
}
|
|
1199
1213
|
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1214
|
+
const isStaleCall = this.runPromise !== runPromise;
|
|
1200
1215
|
if (!isProbeTimeout &&
|
|
1216
|
+
!isStaleCall &&
|
|
1201
1217
|
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1202
1218
|
yield this.disconnect(uuid);
|
|
1203
1219
|
}
|
|
@@ -1268,6 +1284,7 @@ class ReactNativeBleTransport {
|
|
|
1268
1284
|
delete transportCache[session];
|
|
1269
1285
|
}
|
|
1270
1286
|
this.deviceProtocol.delete(session);
|
|
1287
|
+
this.probingProtocols.delete(session);
|
|
1271
1288
|
this.deviceProtocolHints.delete(session);
|
|
1272
1289
|
this.protocolV2Assemblers.delete(session);
|
|
1273
1290
|
this.resetProtocolV2Frames(session);
|
|
@@ -1296,6 +1313,80 @@ class ReactNativeBleTransport {
|
|
|
1296
1313
|
}
|
|
1297
1314
|
return transport;
|
|
1298
1315
|
}
|
|
1316
|
+
writeBlePacket(uuid, data, write, isCurrentOwner) {
|
|
1317
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1318
|
+
let timer;
|
|
1319
|
+
let timedOut = false;
|
|
1320
|
+
try {
|
|
1321
|
+
yield Promise.race([
|
|
1322
|
+
write(data),
|
|
1323
|
+
new Promise((_, reject) => {
|
|
1324
|
+
timer = setTimeout(() => {
|
|
1325
|
+
timedOut = true;
|
|
1326
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write timeout after ${BLE_WRITE_PACKET_TIMEOUT_MS}ms`));
|
|
1327
|
+
}, BLE_WRITE_PACKET_TIMEOUT_MS);
|
|
1328
|
+
}),
|
|
1329
|
+
]);
|
|
1330
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1331
|
+
}
|
|
1332
|
+
catch (error) {
|
|
1333
|
+
if (timedOut) {
|
|
1334
|
+
if (isCurrentOwner && !isCurrentOwner()) {
|
|
1335
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] stale BLE write timed out, link kept:', uuid);
|
|
1336
|
+
}
|
|
1337
|
+
else {
|
|
1338
|
+
this.tearDownWedgedLink(uuid);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
throw error;
|
|
1342
|
+
}
|
|
1343
|
+
finally {
|
|
1344
|
+
if (timer)
|
|
1345
|
+
clearTimeout(timer);
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
tearDownWedgedLink(uuid) {
|
|
1350
|
+
var _a;
|
|
1351
|
+
const timeouts = ((_a = this.writeTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1352
|
+
this.writeTimeoutCounts.set(uuid, timeouts);
|
|
1353
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE write timed out, tearing down link:', uuid, {
|
|
1354
|
+
consecutiveWriteTimeouts: timeouts,
|
|
1355
|
+
});
|
|
1356
|
+
const wedged = transportCache[uuid];
|
|
1357
|
+
this.disconnect(uuid).catch(error => {
|
|
1358
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] wedged link teardown failed (ignored):', error);
|
|
1359
|
+
});
|
|
1360
|
+
if (wedged && transportCache[uuid] === wedged) {
|
|
1361
|
+
delete transportCache[uuid];
|
|
1362
|
+
}
|
|
1363
|
+
this.deviceProtocol.delete(uuid);
|
|
1364
|
+
this.probingProtocols.delete(uuid);
|
|
1365
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1366
|
+
this.resetProtocolV2Frames(uuid);
|
|
1367
|
+
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1368
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE writes wedged repeatedly, resetting BLE manager');
|
|
1369
|
+
this.resetPlxManager();
|
|
1370
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
resetPlxManager() {
|
|
1374
|
+
const manager = this.blePlxManager;
|
|
1375
|
+
this.blePlxManager = undefined;
|
|
1376
|
+
Object.keys(transportCache).forEach(key => {
|
|
1377
|
+
delete transportCache[key];
|
|
1378
|
+
});
|
|
1379
|
+
this.deviceProtocol.clear();
|
|
1380
|
+
this.probingProtocols.clear();
|
|
1381
|
+
this.monitorTokens.clear();
|
|
1382
|
+
this.protocolV2Assemblers.clear();
|
|
1383
|
+
try {
|
|
1384
|
+
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
1385
|
+
}
|
|
1386
|
+
catch (error) {
|
|
1387
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1299
1390
|
createProtocolMismatchError(expected) {
|
|
1300
1391
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1301
1392
|
}
|
|
@@ -1303,30 +1394,19 @@ class ReactNativeBleTransport {
|
|
|
1303
1394
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1304
1395
|
}
|
|
1305
1396
|
clearProbeProtocol(uuid, protocol) {
|
|
1397
|
+
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1398
|
+
this.probingProtocols.delete(uuid);
|
|
1399
|
+
}
|
|
1306
1400
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1307
1401
|
this.deviceProtocol.delete(uuid);
|
|
1308
1402
|
}
|
|
1309
1403
|
}
|
|
1310
|
-
|
|
1404
|
+
getActiveProtocol(uuid) {
|
|
1311
1405
|
var _a;
|
|
1406
|
+
return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
|
|
1407
|
+
}
|
|
1408
|
+
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1312
1409
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1313
|
-
if (reactNative.Platform.OS === 'ios') {
|
|
1314
|
-
const protocol = (_a = expectedProtocol !== null && expectedProtocol !== void 0 ? expectedProtocol : protocolHint) !== null && _a !== void 0 ? _a : 'V1';
|
|
1315
|
-
let source = 'ios-legacy-default';
|
|
1316
|
-
if (expectedProtocol) {
|
|
1317
|
-
source = 'expected';
|
|
1318
|
-
}
|
|
1319
|
-
else if (protocolHint) {
|
|
1320
|
-
source = 'hint';
|
|
1321
|
-
}
|
|
1322
|
-
this.deviceProtocol.set(uuid, protocol);
|
|
1323
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
|
|
1324
|
-
deviceId: uuid,
|
|
1325
|
-
protocol,
|
|
1326
|
-
source,
|
|
1327
|
-
});
|
|
1328
|
-
return protocol;
|
|
1329
|
-
}
|
|
1330
1410
|
if (expectedProtocol === 'V1') {
|
|
1331
1411
|
if (yield this.probeProtocolV1(uuid)) {
|
|
1332
1412
|
this.deviceProtocol.set(uuid, 'V1');
|
|
@@ -1375,6 +1455,7 @@ class ReactNativeBleTransport {
|
|
|
1375
1455
|
}
|
|
1376
1456
|
}
|
|
1377
1457
|
this.deviceProtocol.delete(uuid);
|
|
1458
|
+
this.probingProtocols.delete(uuid);
|
|
1378
1459
|
throw this.createProtocolDetectionError();
|
|
1379
1460
|
});
|
|
1380
1461
|
}
|
|
@@ -1426,13 +1507,17 @@ class ReactNativeBleTransport {
|
|
|
1426
1507
|
return false;
|
|
1427
1508
|
}
|
|
1428
1509
|
try {
|
|
1429
|
-
this.
|
|
1510
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
1430
1511
|
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1512
|
+
this.probingProtocols.delete(uuid);
|
|
1431
1513
|
return true;
|
|
1432
1514
|
}
|
|
1433
1515
|
catch (error) {
|
|
1434
1516
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1435
1517
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1518
|
+
if (isWedgedWriteError(error)) {
|
|
1519
|
+
throw error;
|
|
1520
|
+
}
|
|
1436
1521
|
return false;
|
|
1437
1522
|
}
|
|
1438
1523
|
});
|
|
@@ -1443,7 +1528,7 @@ class ReactNativeBleTransport {
|
|
|
1443
1528
|
if (!this._messages || !this._messagesV2) {
|
|
1444
1529
|
return false;
|
|
1445
1530
|
}
|
|
1446
|
-
this.
|
|
1531
|
+
this.probingProtocols.set(uuid, 'V2');
|
|
1447
1532
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1448
1533
|
const detected = yield transport.probeProtocolV2({
|
|
1449
1534
|
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
@@ -1459,6 +1544,9 @@ class ReactNativeBleTransport {
|
|
|
1459
1544
|
if (!detected) {
|
|
1460
1545
|
this.clearProbeProtocol(uuid, 'V2');
|
|
1461
1546
|
}
|
|
1547
|
+
else {
|
|
1548
|
+
this.probingProtocols.delete(uuid);
|
|
1549
|
+
}
|
|
1462
1550
|
return detected;
|
|
1463
1551
|
});
|
|
1464
1552
|
}
|
|
@@ -1530,11 +1618,8 @@ class ReactNativeBleTransport {
|
|
|
1530
1618
|
}
|
|
1531
1619
|
});
|
|
1532
1620
|
}
|
|
1533
|
-
writeProtocolV2Packet(transport, base64, context, assertCurrentGeneration) {
|
|
1621
|
+
writeProtocolV2Packet(uuid, transport, base64, context, assertCurrentGeneration) {
|
|
1534
1622
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1535
|
-
const shouldUseWriteWithResponse = reactNative.Platform.OS === 'ios' &&
|
|
1536
|
-
!context.highVolume &&
|
|
1537
|
-
transport.writeCharacteristic.isWritableWithResponse;
|
|
1538
1623
|
let attempt = 0;
|
|
1539
1624
|
for (;;) {
|
|
1540
1625
|
assertCurrentGeneration();
|
|
@@ -1542,12 +1627,15 @@ class ReactNativeBleTransport {
|
|
|
1542
1627
|
throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
|
|
1543
1628
|
}
|
|
1544
1629
|
try {
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1630
|
+
yield this.writeBlePacket(uuid, base64, payload => transport.writeCharacteristic.writeWithoutResponse(payload), () => {
|
|
1631
|
+
try {
|
|
1632
|
+
assertCurrentGeneration();
|
|
1633
|
+
return !context.signal.aborted;
|
|
1634
|
+
}
|
|
1635
|
+
catch (_a) {
|
|
1636
|
+
return false;
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1551
1639
|
assertCurrentGeneration();
|
|
1552
1640
|
return;
|
|
1553
1641
|
}
|
|
@@ -1568,7 +1656,7 @@ class ReactNativeBleTransport {
|
|
|
1568
1656
|
}
|
|
1569
1657
|
});
|
|
1570
1658
|
}
|
|
1571
|
-
writeProtocolV2Frame(transport$1, frame, context, assertCurrentGeneration) {
|
|
1659
|
+
writeProtocolV2Frame(uuid, transport$1, frame, context, assertCurrentGeneration) {
|
|
1572
1660
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1573
1661
|
const tuning = getProtocolV2BleTuning();
|
|
1574
1662
|
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
@@ -1577,21 +1665,17 @@ class ReactNativeBleTransport {
|
|
|
1577
1665
|
androidPacketLength: tuning.androidPacketLength,
|
|
1578
1666
|
mtu: reactNative.Platform.OS === 'android' ? transport$1.mtuSize : undefined,
|
|
1579
1667
|
});
|
|
1580
|
-
const initialDelayMs = reactNative.Platform.OS === 'ios' && !context.highVolume && frame.length <= packetCapacity
|
|
1581
|
-
? IOS_PROTOCOL_V2_CONTROL_WRITE_DELAY_MS
|
|
1582
|
-
: 0;
|
|
1583
1668
|
yield transport.writeProtocolV2BleFrame({
|
|
1584
1669
|
frame,
|
|
1585
1670
|
packetCapacity,
|
|
1586
1671
|
assertActive: assertCurrentGeneration,
|
|
1587
1672
|
signal: context.signal,
|
|
1588
1673
|
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1589
|
-
initialDelayMs,
|
|
1590
1674
|
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
1591
1675
|
burstPauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
1592
1676
|
flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
|
|
1593
1677
|
wait: delay,
|
|
1594
|
-
writePacket: packet => this.writeProtocolV2Packet(transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
|
|
1678
|
+
writePacket: packet => this.writeProtocolV2Packet(uuid, transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
|
|
1595
1679
|
});
|
|
1596
1680
|
});
|
|
1597
1681
|
}
|
|
@@ -1640,7 +1724,7 @@ class ReactNativeBleTransport {
|
|
|
1640
1724
|
writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
|
|
1641
1725
|
assertCurrentGeneration();
|
|
1642
1726
|
const currentTransport = this.getCachedTransport(uuid);
|
|
1643
|
-
yield this.writeProtocolV2Frame(currentTransport, frame, context, assertCurrentGeneration);
|
|
1727
|
+
yield this.writeProtocolV2Frame(uuid, currentTransport, frame, context, assertCurrentGeneration);
|
|
1644
1728
|
}),
|
|
1645
1729
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1646
1730
|
assertCurrentGeneration();
|
|
@@ -1661,10 +1745,12 @@ class ReactNativeBleTransport {
|
|
|
1661
1745
|
};
|
|
1662
1746
|
}
|
|
1663
1747
|
getProtocolType(path) {
|
|
1664
|
-
return this.
|
|
1748
|
+
return this.getActiveProtocol(path);
|
|
1665
1749
|
}
|
|
1666
1750
|
}
|
|
1667
1751
|
|
|
1752
|
+
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
1753
|
+
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
1668
1754
|
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1669
1755
|
exports["default"] = ReactNativeBleTransport;
|
|
1670
1756
|
exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
|
package/jest.config.js
CHANGED
|
@@ -2,4 +2,9 @@ module.exports = {
|
|
|
2
2
|
preset: '../../jest.config.js',
|
|
3
3
|
testEnvironment: 'node',
|
|
4
4
|
modulePathIgnorePatterns: ['node_modules', '<rootDir>/dist'],
|
|
5
|
+
moduleNameMapper: {
|
|
6
|
+
// The workspace symlinks resolve to prebuilt dist outputs that can lag behind src.
|
|
7
|
+
'^@onekeyfe/hd-transport$': '<rootDir>/../hd-transport/src/index.ts',
|
|
8
|
+
'^@onekeyfe/hd-shared$': '<rootDir>/../shared/src/index.ts',
|
|
9
|
+
},
|
|
5
10
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.54",
|
|
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.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.54",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.54",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.54",
|
|
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": "a382a4719286e0df04fe706ed13099020eb8e13f"
|
|
30
30
|
}
|