@onekeyfe/hd-transport-react-native 1.2.0-alpha.33 → 1.2.0-alpha.35
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 +1 -3
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/constants.d.ts +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +7 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +107 -158
- package/dist/transportLog.d.ts +1 -12
- package/dist/transportLog.d.ts.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/BleTransport.ts +2 -43
- package/src/__tests__/BleTransport.test.ts +41 -0
- package/src/__tests__/constants.test.ts +20 -0
- package/src/__tests__/protocolV2Link.test.ts +180 -2
- package/src/constants.ts +5 -19
- package/src/index.ts +139 -129
- package/src/transportLog.ts +1 -18
- package/src/types.ts +1 -0
package/src/index.ts
CHANGED
|
@@ -23,7 +23,12 @@ import transport, {
|
|
|
23
23
|
probeProtocolV2 as probeProtocolV2Helper,
|
|
24
24
|
writeProtocolV2BleFrame,
|
|
25
25
|
} from '@onekeyfe/hd-transport';
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
ERRORS,
|
|
28
|
+
HardwareErrorCode,
|
|
29
|
+
createDeferred,
|
|
30
|
+
isOnekeyBluetoothDevice,
|
|
31
|
+
} from '@onekeyfe/hd-shared';
|
|
27
32
|
|
|
28
33
|
import { getConnectedDeviceIds, onDeviceBondState, pairDevice } from './BleManager';
|
|
29
34
|
import { hasWritableCapability, resolveProtocolV2PacketCapacity } from './bleStrategy';
|
|
@@ -31,7 +36,6 @@ import { subscribeBleOn } from './subscribeBleOn';
|
|
|
31
36
|
import {
|
|
32
37
|
ANDROID_PACKET_LENGTH,
|
|
33
38
|
IOS_PACKET_LENGTH,
|
|
34
|
-
getBleUuidKey,
|
|
35
39
|
getBluetoothServiceUuids,
|
|
36
40
|
getInfosForServiceUuid,
|
|
37
41
|
isSameBleUuid,
|
|
@@ -56,13 +60,12 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 5;
|
|
|
56
60
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 8 : 10;
|
|
57
61
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 24 : 30;
|
|
58
62
|
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
59
|
-
const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
60
63
|
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
61
64
|
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY =
|
|
62
65
|
Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
63
66
|
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
64
67
|
|
|
65
|
-
type FirmwareUploadWriteRetryType = 'congested'
|
|
68
|
+
type FirmwareUploadWriteRetryType = 'congested';
|
|
66
69
|
type ResolvedBleCharacteristics = {
|
|
67
70
|
writeCharacteristic: Characteristic;
|
|
68
71
|
notifyCharacteristic: Characteristic;
|
|
@@ -73,7 +76,9 @@ const delay = (ms: number) =>
|
|
|
73
76
|
setTimeout(resolve, ms);
|
|
74
77
|
});
|
|
75
78
|
|
|
76
|
-
const getFirmwareUploadWriteRetryType = (
|
|
79
|
+
export const getFirmwareUploadWriteRetryType = (
|
|
80
|
+
error: unknown
|
|
81
|
+
): FirmwareUploadWriteRetryType | null => {
|
|
77
82
|
if (!error || typeof error !== 'object') return null;
|
|
78
83
|
const bleWriteError = error as {
|
|
79
84
|
androidErrorCode?: unknown;
|
|
@@ -84,13 +89,6 @@ const getFirmwareUploadWriteRetryType = (error: unknown): FirmwareUploadWriteRet
|
|
|
84
89
|
name?: unknown;
|
|
85
90
|
};
|
|
86
91
|
|
|
87
|
-
if (
|
|
88
|
-
bleWriteError.errorCode === BleErrorCode.DeviceDisconnected ||
|
|
89
|
-
bleWriteError.errorCode === BleErrorCode.CharacteristicNotFound
|
|
90
|
-
) {
|
|
91
|
-
return 'reconnectable';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
92
|
if (
|
|
95
93
|
bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
|
|
96
94
|
bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS
|
|
@@ -162,16 +160,6 @@ function getDeviceDisplayName(device?: Device | null) {
|
|
|
162
160
|
return device?.name || device?.localName || null;
|
|
163
161
|
}
|
|
164
162
|
|
|
165
|
-
function isGenericBleService(uuid?: string | null) {
|
|
166
|
-
return ['1800', '1801', '180a'].includes(getBleUuidKey(uuid));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function hasKnownOneKeyService(device?: Device | null) {
|
|
170
|
-
return (device?.serviceUUIDs ?? []).some(serviceUuid =>
|
|
171
|
-
getInfosForServiceUuid(serviceUuid, 'classic')
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
163
|
const ANDROID_REQUEST_MTU = 256;
|
|
176
164
|
|
|
177
165
|
const connectOptions: Record<string, unknown> = {
|
|
@@ -259,6 +247,8 @@ export default class ReactNativeBleTransport {
|
|
|
259
247
|
|
|
260
248
|
runPromise: Deferred<any> | null = null;
|
|
261
249
|
|
|
250
|
+
private runPromiseDeviceId: string | null = null;
|
|
251
|
+
|
|
262
252
|
emitter?: EventEmitter;
|
|
263
253
|
|
|
264
254
|
firmwareUploadWriteRecoveryIds = new Set<string>();
|
|
@@ -359,29 +349,15 @@ export default class ReactNativeBleTransport {
|
|
|
359
349
|
}
|
|
360
350
|
}
|
|
361
351
|
|
|
362
|
-
let fallbackServiceUuid: string | undefined;
|
|
363
|
-
|
|
364
352
|
if (!infos) {
|
|
365
353
|
const services = await device.services();
|
|
366
354
|
Log?.debug(
|
|
367
355
|
'[ReactNativeBleTransport] Known OneKey service UUID not found, discovered services:',
|
|
368
356
|
services?.map(service => service.uuid)
|
|
369
357
|
);
|
|
370
|
-
|
|
371
|
-
const knownService = services.find(service =>
|
|
372
|
-
getInfosForServiceUuid(service.uuid, 'classic')
|
|
373
|
-
);
|
|
374
|
-
const fallbackService =
|
|
375
|
-
knownService ?? services.find(service => !isGenericBleService(service.uuid)) ?? services[0];
|
|
376
|
-
|
|
377
|
-
if (fallbackService) {
|
|
378
|
-
fallbackServiceUuid = fallbackService.uuid;
|
|
379
|
-
characteristics = await device.characteristicsForService(fallbackService.uuid);
|
|
380
|
-
Log?.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
381
|
-
}
|
|
382
358
|
}
|
|
383
359
|
|
|
384
|
-
if (!infos
|
|
360
|
+
if (!infos) {
|
|
385
361
|
try {
|
|
386
362
|
Log?.debug('cancel connection when service not found');
|
|
387
363
|
await device.cancelConnection();
|
|
@@ -391,9 +367,7 @@ export default class ReactNativeBleTransport {
|
|
|
391
367
|
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
392
368
|
}
|
|
393
369
|
|
|
394
|
-
const serviceUuid = infos
|
|
395
|
-
const writeUuid = infos?.writeUuid ?? '00000002-0000-1000-8000-00805f9b34fb';
|
|
396
|
-
const notifyUuid = infos?.notifyUuid ?? '00000003-0000-1000-8000-00805f9b34fb';
|
|
370
|
+
const { serviceUuid, writeUuid, notifyUuid } = infos;
|
|
397
371
|
|
|
398
372
|
if (!serviceUuid) {
|
|
399
373
|
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
@@ -461,10 +435,9 @@ export default class ReactNativeBleTransport {
|
|
|
461
435
|
try {
|
|
462
436
|
Log?.debug('device disconnect: ', device?.id);
|
|
463
437
|
this.emitDeviceDisconnect(uuid, device?.name, monitorToken);
|
|
464
|
-
if (this.runPromise) {
|
|
438
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
465
439
|
const error = ERRORS.TypedError(HardwareErrorCode.BleConnectedError);
|
|
466
440
|
this.runPromise.reject(error);
|
|
467
|
-
this.rejectAllProtocolV2Frames(error);
|
|
468
441
|
}
|
|
469
442
|
} catch (e) {
|
|
470
443
|
Log?.debug('device disconnect error: ', e);
|
|
@@ -607,10 +580,12 @@ export default class ReactNativeBleTransport {
|
|
|
607
580
|
}
|
|
608
581
|
|
|
609
582
|
const displayName = getDeviceDisplayName(device);
|
|
610
|
-
const isOneKey =
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
583
|
+
const isOneKey = isOnekeyBluetoothDevice({
|
|
584
|
+
id: device?.id,
|
|
585
|
+
name: device?.name,
|
|
586
|
+
localName: device?.localName,
|
|
587
|
+
serviceUuids: device?.serviceUUIDs,
|
|
588
|
+
});
|
|
614
589
|
if (isOneKey) {
|
|
615
590
|
addDevice(device as unknown as Device);
|
|
616
591
|
} else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
|
|
@@ -627,10 +602,18 @@ export default class ReactNativeBleTransport {
|
|
|
627
602
|
getConnectedDeviceIds(Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(
|
|
628
603
|
devices => {
|
|
629
604
|
for (const device of devices) {
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
605
|
+
const localName =
|
|
606
|
+
'localName' in device && typeof device.localName === 'string'
|
|
607
|
+
? device.localName
|
|
608
|
+
: null;
|
|
609
|
+
if (
|
|
610
|
+
isOnekeyBluetoothDevice({
|
|
611
|
+
id: device.id,
|
|
612
|
+
name: device.name,
|
|
613
|
+
localName,
|
|
614
|
+
serviceUuids: device.serviceUUIDs,
|
|
615
|
+
})
|
|
616
|
+
) {
|
|
634
617
|
Log?.debug('search connected peripheral: ', device.id);
|
|
635
618
|
addDevice(device as unknown as Device);
|
|
636
619
|
}
|
|
@@ -666,6 +649,46 @@ export default class ReactNativeBleTransport {
|
|
|
666
649
|
});
|
|
667
650
|
}
|
|
668
651
|
|
|
652
|
+
private async installTransportForAcquire(
|
|
653
|
+
uuid: string,
|
|
654
|
+
device: Device,
|
|
655
|
+
characteristics?: ResolvedBleCharacteristics
|
|
656
|
+
) {
|
|
657
|
+
const { writeCharacteristic, notifyCharacteristic } =
|
|
658
|
+
characteristics ?? (await this.resolveCharacteristics(device));
|
|
659
|
+
const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
660
|
+
if (Platform.OS === 'android') {
|
|
661
|
+
transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport.mtuSize;
|
|
662
|
+
}
|
|
663
|
+
const monitorToken = this.nextMonitorToken;
|
|
664
|
+
this.nextMonitorToken += 1;
|
|
665
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
666
|
+
transport.monitorToken = monitorToken;
|
|
667
|
+
transport.notifyTransactionId = notifyTransactionId;
|
|
668
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
669
|
+
transport.notifySubscription = this._monitorCharacteristic(
|
|
670
|
+
transport.notifyCharacteristic,
|
|
671
|
+
uuid,
|
|
672
|
+
monitorToken,
|
|
673
|
+
notifyTransactionId
|
|
674
|
+
);
|
|
675
|
+
transportCache[uuid] = transport;
|
|
676
|
+
this.protocolV2Assemblers.set(
|
|
677
|
+
uuid,
|
|
678
|
+
new ProtocolV2FrameAssembler(PROTOCOL_V2_BLE_FRAME_MAX_BYTES)
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
if (Platform.OS === 'ios') {
|
|
682
|
+
await new Promise<void>(resolve => {
|
|
683
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
684
|
+
});
|
|
685
|
+
} else if (Platform.OS === 'android') {
|
|
686
|
+
await delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return transport;
|
|
690
|
+
}
|
|
691
|
+
|
|
669
692
|
async acquire(input: BleAcquireInput) {
|
|
670
693
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
671
694
|
|
|
@@ -699,8 +722,8 @@ export default class ReactNativeBleTransport {
|
|
|
699
722
|
if (forceCleanRunPromise && this.runPromise) {
|
|
700
723
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
701
724
|
this.runPromise.reject(error);
|
|
702
|
-
this.rejectAllProtocolV2Frames(error);
|
|
703
725
|
this.runPromise = null;
|
|
726
|
+
this.runPromiseDeviceId = null;
|
|
704
727
|
Log?.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
705
728
|
}
|
|
706
729
|
|
|
@@ -789,12 +812,16 @@ export default class ReactNativeBleTransport {
|
|
|
789
812
|
}
|
|
790
813
|
|
|
791
814
|
device = await requestAndroidMtu(device);
|
|
792
|
-
const
|
|
815
|
+
const acquiredDevice = device;
|
|
816
|
+
const { writeCharacteristic, notifyCharacteristic } = await this.resolveCharacteristics(
|
|
817
|
+
acquiredDevice
|
|
818
|
+
);
|
|
793
819
|
|
|
794
820
|
const protocolHint = expectedProtocol
|
|
795
821
|
? undefined
|
|
796
|
-
:
|
|
797
|
-
|
|
822
|
+
: input.protocolHint ??
|
|
823
|
+
this.deviceProtocolHints.get(uuid) ??
|
|
824
|
+
inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
798
825
|
|
|
799
826
|
// release transport before new transport instance
|
|
800
827
|
await this.release(uuid, true);
|
|
@@ -802,42 +829,30 @@ export default class ReactNativeBleTransport {
|
|
|
802
829
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
803
830
|
}
|
|
804
831
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
}
|
|
809
|
-
const monitorToken = this.nextMonitorToken;
|
|
810
|
-
this.nextMonitorToken += 1;
|
|
811
|
-
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
812
|
-
transport.monitorToken = monitorToken;
|
|
813
|
-
transport.notifyTransactionId = notifyTransactionId;
|
|
814
|
-
this.monitorTokens.set(uuid, monitorToken);
|
|
815
|
-
transport.notifySubscription = this._monitorCharacteristic(
|
|
816
|
-
transport.notifyCharacteristic,
|
|
817
|
-
uuid,
|
|
818
|
-
monitorToken,
|
|
819
|
-
notifyTransactionId
|
|
820
|
-
);
|
|
821
|
-
transportCache[uuid] = transport;
|
|
822
|
-
|
|
823
|
-
this.protocolV2Assemblers.set(
|
|
824
|
-
uuid,
|
|
825
|
-
new ProtocolV2FrameAssembler(PROTOCOL_V2_BLE_FRAME_MAX_BYTES)
|
|
826
|
-
);
|
|
832
|
+
await this.installTransportForAcquire(uuid, acquiredDevice, {
|
|
833
|
+
writeCharacteristic,
|
|
834
|
+
notifyCharacteristic,
|
|
835
|
+
});
|
|
827
836
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
837
|
+
try {
|
|
838
|
+
const protocolType = await this.detectProtocol(
|
|
839
|
+
uuid,
|
|
840
|
+
expectedProtocol,
|
|
841
|
+
protocolHint,
|
|
842
|
+
async () => {
|
|
843
|
+
await this.installTransportForAcquire(uuid, acquiredDevice);
|
|
844
|
+
}
|
|
845
|
+
);
|
|
846
|
+
const currentTransport = transportCache[uuid];
|
|
847
|
+
if (!currentTransport) {
|
|
848
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotFound);
|
|
849
|
+
}
|
|
850
|
+
this.attachDisconnectSubscription(currentTransport, acquiredDevice, uuid);
|
|
851
|
+
return { uuid, protocolType };
|
|
852
|
+
} catch (error) {
|
|
853
|
+
await this.release(uuid, true);
|
|
854
|
+
throw error;
|
|
834
855
|
}
|
|
835
|
-
|
|
836
|
-
const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
837
|
-
|
|
838
|
-
this.attachDisconnectSubscription(transport, device, uuid);
|
|
839
|
-
|
|
840
|
-
return { uuid, protocolType };
|
|
841
856
|
}
|
|
842
857
|
|
|
843
858
|
_monitorCharacteristic(
|
|
@@ -887,7 +902,7 @@ export default class ReactNativeBleTransport {
|
|
|
887
902
|
this.rejectProtocolV2Frames(uuid, ERRORS.TypedError(errorCode));
|
|
888
903
|
return;
|
|
889
904
|
}
|
|
890
|
-
if (this.runPromise) {
|
|
905
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
891
906
|
let ERROR:
|
|
892
907
|
| typeof HardwareErrorCode.BleDeviceBondError
|
|
893
908
|
| typeof HardwareErrorCode.BleCharacteristicNotifyError
|
|
@@ -910,7 +925,6 @@ export default class ReactNativeBleTransport {
|
|
|
910
925
|
HardwareErrorCode.BleCharacteristicNotifyChangeFailure
|
|
911
926
|
);
|
|
912
927
|
this.runPromise.reject(notifyError);
|
|
913
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
914
928
|
Log?.debug(
|
|
915
929
|
`${HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`
|
|
916
930
|
);
|
|
@@ -918,7 +932,6 @@ export default class ReactNativeBleTransport {
|
|
|
918
932
|
}
|
|
919
933
|
const notifyError = ERRORS.TypedError(ERROR);
|
|
920
934
|
this.runPromise.reject(notifyError);
|
|
921
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
922
935
|
Log?.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
923
936
|
}
|
|
924
937
|
|
|
@@ -963,14 +976,16 @@ export default class ReactNativeBleTransport {
|
|
|
963
976
|
// );
|
|
964
977
|
bufferLength = 0;
|
|
965
978
|
buffer = [];
|
|
966
|
-
this.
|
|
979
|
+
if (this.runPromiseDeviceId === uuid) {
|
|
980
|
+
this.runPromise?.resolve(value.toString('hex'));
|
|
981
|
+
}
|
|
967
982
|
}
|
|
968
983
|
} catch (error) {
|
|
969
984
|
Log?.debug('monitor data error: ', error);
|
|
970
985
|
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
971
986
|
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
972
987
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
973
|
-
} else {
|
|
988
|
+
} else if (this.runPromiseDeviceId === uuid) {
|
|
974
989
|
this.runPromise?.reject(notifyError);
|
|
975
990
|
}
|
|
976
991
|
}
|
|
@@ -986,11 +1001,12 @@ export default class ReactNativeBleTransport {
|
|
|
986
1001
|
|
|
987
1002
|
private async releaseNative(uuid: string, onclose = false) {
|
|
988
1003
|
const transport = transportCache[uuid];
|
|
989
|
-
if (this.runPromise) {
|
|
1004
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
990
1005
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
991
1006
|
this.runPromise.reject(error);
|
|
992
1007
|
this.runPromise = null;
|
|
993
|
-
this.
|
|
1008
|
+
this.runPromiseDeviceId = null;
|
|
1009
|
+
this.rejectProtocolV2Frames(uuid, error);
|
|
994
1010
|
} else {
|
|
995
1011
|
this.resetProtocolV2Frames(uuid);
|
|
996
1012
|
}
|
|
@@ -1098,6 +1114,7 @@ export default class ReactNativeBleTransport {
|
|
|
1098
1114
|
const runPromise = createDeferred<string>();
|
|
1099
1115
|
runPromise.promise.catch(() => undefined);
|
|
1100
1116
|
this.runPromise = runPromise;
|
|
1117
|
+
this.runPromiseDeviceId = uuid;
|
|
1101
1118
|
const messages = this._messages;
|
|
1102
1119
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1103
1120
|
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -1197,31 +1214,14 @@ export default class ReactNativeBleTransport {
|
|
|
1197
1214
|
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1198
1215
|
throw error;
|
|
1199
1216
|
}
|
|
1200
|
-
const
|
|
1201
|
-
const delayMs = shouldReconnect
|
|
1202
|
-
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1203
|
-
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1217
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1204
1218
|
Log?.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1205
1219
|
attempt: attempt + 1,
|
|
1206
1220
|
delayMs,
|
|
1207
|
-
reconnect: shouldReconnect,
|
|
1208
1221
|
error,
|
|
1209
1222
|
});
|
|
1210
|
-
if (shouldReconnect) {
|
|
1211
|
-
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1212
|
-
}
|
|
1213
1223
|
await delay(delayMs);
|
|
1214
1224
|
attempt += 1;
|
|
1215
|
-
if (shouldReconnect) {
|
|
1216
|
-
try {
|
|
1217
|
-
await this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
1218
|
-
} catch (e) {
|
|
1219
|
-
Log?.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
1220
|
-
if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1221
|
-
throw e;
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
1225
|
}
|
|
1226
1226
|
}
|
|
1227
1227
|
},
|
|
@@ -1274,16 +1274,25 @@ export default class ReactNativeBleTransport {
|
|
|
1274
1274
|
const jsonData = ProtocolV1.decodeMessage(messages, response);
|
|
1275
1275
|
return check.call(jsonData);
|
|
1276
1276
|
} catch (e) {
|
|
1277
|
-
if (name === '
|
|
1278
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V1
|
|
1277
|
+
if (name === 'GetFeatures' && options?.timeoutMs === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1278
|
+
Log?.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
|
|
1279
1279
|
} else {
|
|
1280
1280
|
Log?.error('call error: ', e);
|
|
1281
1281
|
}
|
|
1282
|
+
const isProbeTimeout =
|
|
1283
|
+
name === 'GetFeatures' && options?.timeoutMs === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1284
|
+
if (
|
|
1285
|
+
!isProbeTimeout &&
|
|
1286
|
+
(e as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleTimeoutError
|
|
1287
|
+
) {
|
|
1288
|
+
await this.disconnect(uuid);
|
|
1289
|
+
}
|
|
1282
1290
|
throw e;
|
|
1283
1291
|
} finally {
|
|
1284
1292
|
if (timeout) clearTimeout(timeout);
|
|
1285
1293
|
if (this.runPromise === runPromise) {
|
|
1286
1294
|
this.runPromise = null;
|
|
1295
|
+
this.runPromiseDeviceId = null;
|
|
1287
1296
|
}
|
|
1288
1297
|
}
|
|
1289
1298
|
}
|
|
@@ -1376,6 +1385,7 @@ export default class ReactNativeBleTransport {
|
|
|
1376
1385
|
// this.runPromise.reject(new Error('Transport_CallCanceled'));
|
|
1377
1386
|
}
|
|
1378
1387
|
this.runPromise = null;
|
|
1388
|
+
this.runPromiseDeviceId = null;
|
|
1379
1389
|
}
|
|
1380
1390
|
|
|
1381
1391
|
private getCachedTransport(uuid: string) {
|
|
@@ -1396,7 +1406,7 @@ export default class ReactNativeBleTransport {
|
|
|
1396
1406
|
private createProtocolDetectionError() {
|
|
1397
1407
|
return ERRORS.TypedError(
|
|
1398
1408
|
HardwareErrorCode.BleTimeoutError,
|
|
1399
|
-
'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1409
|
+
'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping'
|
|
1400
1410
|
);
|
|
1401
1411
|
}
|
|
1402
1412
|
|
|
@@ -1409,7 +1419,8 @@ export default class ReactNativeBleTransport {
|
|
|
1409
1419
|
private async detectProtocol(
|
|
1410
1420
|
uuid: string,
|
|
1411
1421
|
expectedProtocol?: ProtocolType,
|
|
1412
|
-
protocolHint?: ProtocolType
|
|
1422
|
+
protocolHint?: ProtocolType,
|
|
1423
|
+
rebuildTransport?: () => Promise<void>
|
|
1413
1424
|
): Promise<ProtocolType> {
|
|
1414
1425
|
if (expectedProtocol === 'V1') {
|
|
1415
1426
|
if (await this.probeProtocolV1(uuid)) {
|
|
@@ -1447,6 +1458,12 @@ export default class ReactNativeBleTransport {
|
|
|
1447
1458
|
if (i > 0) {
|
|
1448
1459
|
// Reset subscriptions and buffers after a failed probe before trying another protocol.
|
|
1449
1460
|
await this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1461
|
+
if (!transportCache[uuid]) {
|
|
1462
|
+
if (!rebuildTransport) {
|
|
1463
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotFound);
|
|
1464
|
+
}
|
|
1465
|
+
await rebuildTransport();
|
|
1466
|
+
}
|
|
1450
1467
|
}
|
|
1451
1468
|
const detected =
|
|
1452
1469
|
protocol === 'V1' ? await this.probeProtocolV1(uuid) : await this.probeProtocolV2(uuid);
|
|
@@ -1524,11 +1541,13 @@ export default class ReactNativeBleTransport {
|
|
|
1524
1541
|
|
|
1525
1542
|
try {
|
|
1526
1543
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1527
|
-
|
|
1544
|
+
// GetFeatures identifies Protocol V1 without resetting an existing wallet
|
|
1545
|
+
// session before Core has a chance to restore a hidden wallet.
|
|
1546
|
+
await this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1528
1547
|
return true;
|
|
1529
1548
|
} catch (error) {
|
|
1530
1549
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1531
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V1
|
|
1550
|
+
Log?.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1532
1551
|
return false;
|
|
1533
1552
|
}
|
|
1534
1553
|
}
|
|
@@ -1603,17 +1622,8 @@ export default class ReactNativeBleTransport {
|
|
|
1603
1622
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1604
1623
|
}
|
|
1605
1624
|
|
|
1606
|
-
private rejectAllProtocolV2Frames(error: Error) {
|
|
1607
|
-
this.protocolV2FrameQueues.clear();
|
|
1608
|
-
for (const framePromise of this.protocolV2FramePromises.values()) {
|
|
1609
|
-
framePromise.reject(error);
|
|
1610
|
-
}
|
|
1611
|
-
this.protocolV2FramePromises.clear();
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
1625
|
private resetProtocolV2Frames(uuid: string) {
|
|
1615
|
-
this.
|
|
1616
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1626
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1617
1627
|
}
|
|
1618
1628
|
|
|
1619
1629
|
private rejectProtocolV2Frames(uuid: string, error: Error) {
|
package/src/transportLog.ts
CHANGED
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export function createTransportCallLog(
|
|
4
|
-
name: string,
|
|
5
|
-
protocol: ProtocolType,
|
|
6
|
-
data: Record<string, unknown>
|
|
7
|
-
) {
|
|
8
|
-
if (name === 'ResourceUpdate' || name === 'ResourceAck') {
|
|
9
|
-
return {
|
|
10
|
-
name,
|
|
11
|
-
protocol,
|
|
12
|
-
file_name: data.file_name,
|
|
13
|
-
hash: data.hash,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return { name, protocol };
|
|
18
|
-
}
|
|
1
|
+
export { createTransportCallLog } from '@onekeyfe/hd-transport';
|