@ledgerhq/react-native-hw-transport-ble 6.33.4 → 6.34.0-next.0
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/CHANGELOG.md +7 -0
- package/lib/BlePlxManager.d.ts +28 -0
- package/lib/BlePlxManager.d.ts.map +1 -0
- package/lib/BlePlxManager.js +80 -0
- package/lib/BlePlxManager.js.map +1 -0
- package/lib/BleTransport.d.ts +8 -10
- package/lib/BleTransport.d.ts.map +1 -1
- package/lib/BleTransport.js +55 -55
- package/lib/BleTransport.js.map +1 -1
- package/lib-es/BlePlxManager.d.ts +28 -0
- package/lib-es/BlePlxManager.d.ts.map +1 -0
- package/lib-es/BlePlxManager.js +76 -0
- package/lib-es/BlePlxManager.js.map +1 -0
- package/lib-es/BleTransport.d.ts +8 -10
- package/lib-es/BleTransport.d.ts.map +1 -1
- package/lib-es/BleTransport.js +61 -61
- package/lib-es/BleTransport.js.map +1 -1
- package/package.json +4 -3
- package/src/BlePlxManager.ts +72 -0
- package/src/BleTransport.ts +91 -105
package/src/BleTransport.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { v4 as uuid } from "uuid";
|
|
2
|
-
import Transport from "@ledgerhq/hw-transport";
|
|
3
2
|
import type {
|
|
4
|
-
Subscription as TransportSubscription,
|
|
5
3
|
Observer as TransportObserver,
|
|
4
|
+
Subscription as TransportSubscription,
|
|
6
5
|
} from "@ledgerhq/hw-transport";
|
|
6
|
+
import Transport from "@ledgerhq/hw-transport";
|
|
7
7
|
// ---------------------------------------------------------------------------------------------
|
|
8
8
|
// Since this is a react-native library and metro bundler does not support
|
|
9
9
|
// package exports yet (see: https://github.com/facebook/metro/issues/670)
|
|
@@ -15,64 +15,62 @@ import type {
|
|
|
15
15
|
import { sendAPDU } from "@ledgerhq/devices/lib/ble/sendAPDU";
|
|
16
16
|
import { receiveAPDU } from "@ledgerhq/devices/lib/ble/receiveAPDU";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
ConnectionPriority,
|
|
18
|
+
BleError,
|
|
20
19
|
BleErrorCode,
|
|
21
|
-
LogLevel,
|
|
22
|
-
DeviceId,
|
|
23
|
-
Device,
|
|
24
20
|
Characteristic,
|
|
25
|
-
|
|
21
|
+
ConnectionPriority,
|
|
22
|
+
Device,
|
|
23
|
+
DeviceId,
|
|
26
24
|
Subscription,
|
|
27
25
|
} from "react-native-ble-plx";
|
|
26
|
+
import type { DeviceModel } from "@ledgerhq/devices";
|
|
28
27
|
import {
|
|
29
28
|
BluetoothInfos,
|
|
30
29
|
DeviceModelId,
|
|
31
30
|
getBluetoothServiceUuids,
|
|
32
31
|
getInfosForServiceUuid,
|
|
33
32
|
} from "@ledgerhq/devices";
|
|
34
|
-
import
|
|
35
|
-
import { trace, LocalTracer, TraceContext } from "@ledgerhq/logs";
|
|
33
|
+
import { LocalTracer, trace, TraceContext } from "@ledgerhq/logs";
|
|
36
34
|
import {
|
|
37
|
-
Observable,
|
|
38
35
|
defer,
|
|
39
|
-
|
|
36
|
+
firstValueFrom,
|
|
40
37
|
from,
|
|
38
|
+
merge,
|
|
39
|
+
Observable,
|
|
40
|
+
Observer,
|
|
41
41
|
of,
|
|
42
|
+
SchedulerLike,
|
|
42
43
|
throwError,
|
|
43
|
-
Observer,
|
|
44
|
-
firstValueFrom,
|
|
45
44
|
TimeoutError,
|
|
46
|
-
SchedulerLike,
|
|
47
45
|
} from "rxjs";
|
|
48
46
|
import {
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
catchError,
|
|
48
|
+
finalize,
|
|
51
49
|
first,
|
|
50
|
+
ignoreElements,
|
|
52
51
|
map,
|
|
52
|
+
share,
|
|
53
53
|
tap,
|
|
54
|
-
catchError,
|
|
55
54
|
timeout,
|
|
56
|
-
finalize,
|
|
57
55
|
} from "rxjs/operators";
|
|
58
56
|
import {
|
|
59
57
|
CantOpenDevice,
|
|
60
|
-
TransportError,
|
|
61
58
|
DisconnectedDeviceDuringOperation,
|
|
59
|
+
HwTransportError,
|
|
62
60
|
PairingFailed,
|
|
63
61
|
PeerRemovedPairing,
|
|
64
|
-
|
|
62
|
+
TransportError,
|
|
65
63
|
TransportExchangeTimeoutError,
|
|
66
64
|
} from "@ledgerhq/errors";
|
|
67
65
|
import { monitorCharacteristic } from "./monitorCharacteristic";
|
|
68
|
-
import { awaitsBleOn } from "./awaitsBleOn";
|
|
69
66
|
import {
|
|
70
67
|
decoratePromiseErrors,
|
|
71
|
-
remapError,
|
|
72
|
-
mapBleErrorToHwTransportError,
|
|
73
68
|
IOBleErrorRemap,
|
|
69
|
+
mapBleErrorToHwTransportError,
|
|
70
|
+
remapError,
|
|
74
71
|
} from "./remapErrors";
|
|
75
72
|
import { ReconnectionConfig } from "./types";
|
|
73
|
+
import { BlePlxManager } from "./BlePlxManager";
|
|
76
74
|
|
|
77
75
|
const LOG_TYPE = "ble-verbose";
|
|
78
76
|
|
|
@@ -120,22 +118,6 @@ let connectOptions: Record<string, unknown> = {
|
|
|
120
118
|
connectionPriority: 1,
|
|
121
119
|
};
|
|
122
120
|
|
|
123
|
-
/**
|
|
124
|
-
* Returns the instance of the Bluetooth Low Energy Manager. It initializes it only
|
|
125
|
-
* when it's first needed, preventing the permission prompt happening prematurely.
|
|
126
|
-
* Important: Do NOT access the _bleManager variable directly.
|
|
127
|
-
* Use this function instead.
|
|
128
|
-
* @returns {BleManager} - The instance of the BleManager.
|
|
129
|
-
*/
|
|
130
|
-
let _bleManager: BleManager | null = null;
|
|
131
|
-
const bleManagerInstance = (): BleManager => {
|
|
132
|
-
if (!_bleManager) {
|
|
133
|
-
_bleManager = new BleManager();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return _bleManager;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
121
|
const clearDisconnectTimeout = (deviceId: string, context?: TraceContext): void => {
|
|
140
122
|
const cachedTransport = transportsCache[deviceId];
|
|
141
123
|
if (cachedTransport && cachedTransport.disconnectTimeout) {
|
|
@@ -177,20 +159,17 @@ async function open(
|
|
|
177
159
|
}
|
|
178
160
|
|
|
179
161
|
tracer.trace(`Trying to open device: ${deviceOrId}`);
|
|
180
|
-
await
|
|
162
|
+
await BlePlxManager.waitOn();
|
|
181
163
|
|
|
182
164
|
// Returns a list of known devices by their identifiers
|
|
183
|
-
|
|
184
|
-
tracer.trace(`Found ${devices.length} already known device(s) with given id`, { deviceOrId });
|
|
185
|
-
[device] = devices;
|
|
165
|
+
device = await BlePlxManager.getKnownDevice(deviceOrId);
|
|
186
166
|
|
|
187
167
|
if (!device) {
|
|
168
|
+
tracer.trace(`Found already known device with given id`, { deviceOrId });
|
|
188
169
|
// Returns a list of the peripherals currently connected to the system
|
|
189
170
|
// which have discovered services, connected to system doesn't mean
|
|
190
171
|
// connected to our app, we check that below.
|
|
191
|
-
const connectedDevices = await
|
|
192
|
-
getBluetoothServiceUuids(),
|
|
193
|
-
);
|
|
172
|
+
const connectedDevices = await BlePlxManager.getConnectedDevices();
|
|
194
173
|
const connectedDevicesFiltered = connectedDevices.filter(d => d.id === deviceOrId);
|
|
195
174
|
tracer.trace(
|
|
196
175
|
`No known device with given id. Found ${connectedDevicesFiltered.length} devices from already connected devices`,
|
|
@@ -208,7 +187,7 @@ async function open(
|
|
|
208
187
|
|
|
209
188
|
// Nb ConnectionOptions dropped since it's not used internally by ble-plx.
|
|
210
189
|
try {
|
|
211
|
-
device = await
|
|
190
|
+
device = await BlePlxManager.connect(deviceOrId, {
|
|
212
191
|
...connectOptions,
|
|
213
192
|
timeout: timeoutMs,
|
|
214
193
|
});
|
|
@@ -217,7 +196,7 @@ async function open(
|
|
|
217
196
|
if (e.errorCode === BleErrorCode.DeviceMTUChangeFailed) {
|
|
218
197
|
// If the MTU update did not work, we try to connect without requesting for a specific MTU
|
|
219
198
|
connectOptions = {};
|
|
220
|
-
device = await
|
|
199
|
+
device = await BlePlxManager.connect(deviceOrId, { timeout: timeoutMs });
|
|
221
200
|
} else {
|
|
222
201
|
throw e;
|
|
223
202
|
}
|
|
@@ -457,7 +436,7 @@ export default class BleTransport extends Transport {
|
|
|
457
436
|
/**
|
|
458
437
|
*
|
|
459
438
|
*/
|
|
460
|
-
static isSupported = (): Promise<boolean> => Promise.resolve(typeof
|
|
439
|
+
static isSupported = (): Promise<boolean> => Promise.resolve(typeof BlePlxManager === "function");
|
|
461
440
|
|
|
462
441
|
/**
|
|
463
442
|
*
|
|
@@ -466,21 +445,15 @@ export default class BleTransport extends Transport {
|
|
|
466
445
|
throw new Error("not implemented");
|
|
467
446
|
};
|
|
468
447
|
|
|
469
|
-
/**
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
static setLogLevel =
|
|
475
|
-
if (Object.values<string>(LogLevel).includes(logLevel)) {
|
|
476
|
-
bleManagerInstance().setLogLevel(logLevel as LogLevel);
|
|
477
|
-
} else {
|
|
478
|
-
throw new Error(`${logLevel} is not a valid LogLevel`);
|
|
479
|
-
}
|
|
480
|
-
};
|
|
448
|
+
// /**
|
|
449
|
+
// * Exposed method from the ble-plx library
|
|
450
|
+
// * Sets new log level for native module's logging mechanism.
|
|
451
|
+
// * @param string logLevel New log level to be set.
|
|
452
|
+
// */
|
|
453
|
+
static setLogLevel = BlePlxManager.setLogLevel;
|
|
481
454
|
|
|
482
455
|
/**
|
|
483
|
-
* Listen to state changes on the
|
|
456
|
+
* Listen to state changes on the BlePlxManagerInstance and notify the
|
|
484
457
|
* specified observer.
|
|
485
458
|
* @param observer
|
|
486
459
|
* @returns TransportSubscription
|
|
@@ -498,16 +471,25 @@ export default class BleTransport extends Transport {
|
|
|
498
471
|
});
|
|
499
472
|
};
|
|
500
473
|
|
|
501
|
-
|
|
474
|
+
BlePlxManager.onStateChange(emitFromState, true);
|
|
502
475
|
|
|
503
476
|
return {
|
|
504
477
|
unsubscribe: () => {},
|
|
505
478
|
};
|
|
506
479
|
}
|
|
507
480
|
|
|
481
|
+
static safeRemove = (sub: Subscription, tracer: LocalTracer) => {
|
|
482
|
+
try {
|
|
483
|
+
sub.remove();
|
|
484
|
+
} catch (error) {
|
|
485
|
+
tracer.trace("Error removing state subscription", { error });
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
508
489
|
/**
|
|
509
490
|
* Scan for bluetooth Ledger devices
|
|
510
491
|
* @param observer Device is partial in order to avoid the live-common/this dep
|
|
492
|
+
* @param context
|
|
511
493
|
* @returns TransportSubscription
|
|
512
494
|
*/
|
|
513
495
|
static listen(
|
|
@@ -519,49 +501,55 @@ export default class BleTransport extends Transport {
|
|
|
519
501
|
|
|
520
502
|
let unsubscribed: boolean;
|
|
521
503
|
|
|
522
|
-
const stateSub =
|
|
504
|
+
const stateSub = BlePlxManager.onStateChange(async state => {
|
|
523
505
|
if (state === "PoweredOn") {
|
|
524
|
-
|
|
525
|
-
const devices = await
|
|
506
|
+
BleTransport.safeRemove(stateSub, tracer);
|
|
507
|
+
const devices = await BlePlxManager.getConnectedDevices().catch(err => {
|
|
508
|
+
// Handle possible connection errors
|
|
509
|
+
tracer.trace("Error while fetching connected devices", { err });
|
|
510
|
+
return [];
|
|
511
|
+
});
|
|
526
512
|
if (unsubscribed) return;
|
|
527
513
|
if (devices.length) {
|
|
528
514
|
tracer.trace("Disconnecting from all devices", { deviceCount: devices.length });
|
|
529
515
|
|
|
530
|
-
|
|
516
|
+
try {
|
|
517
|
+
await Promise.all(devices.map(d => BleTransport.disconnectDevice(d.id)));
|
|
518
|
+
} catch (error) {
|
|
519
|
+
tracer.trace("Error disconnecting some devices", { error });
|
|
520
|
+
}
|
|
531
521
|
}
|
|
532
522
|
|
|
533
523
|
if (unsubscribed) return;
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
},
|
|
555
|
-
);
|
|
524
|
+
await BlePlxManager.startScan((bleError: BleError | null, scannedDevice: Device | null) => {
|
|
525
|
+
if (bleError) {
|
|
526
|
+
tracer.trace("Listening startDeviceScan error", { scannedDevice, bleError });
|
|
527
|
+
observer.error(mapBleErrorToHwTransportError(bleError));
|
|
528
|
+
unsubscribe();
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const res = retrieveInfos(scannedDevice);
|
|
533
|
+
const deviceModel = res && res.deviceModel;
|
|
534
|
+
|
|
535
|
+
if (scannedDevice) {
|
|
536
|
+
observer.next({
|
|
537
|
+
type: "add",
|
|
538
|
+
descriptor: scannedDevice,
|
|
539
|
+
deviceModel,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
});
|
|
556
543
|
}
|
|
557
544
|
}, true);
|
|
558
545
|
|
|
559
546
|
const unsubscribe = () => {
|
|
547
|
+
if (unsubscribed) return;
|
|
560
548
|
unsubscribed = true;
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
549
|
+
BlePlxManager.stopScan().then(() => {
|
|
550
|
+
BleTransport.safeRemove(stateSub, tracer);
|
|
551
|
+
tracer.trace("Done listening");
|
|
552
|
+
});
|
|
565
553
|
};
|
|
566
554
|
|
|
567
555
|
return {
|
|
@@ -598,14 +586,12 @@ export default class BleTransport extends Transport {
|
|
|
598
586
|
const tracer = new LocalTracer(LOG_TYPE, context);
|
|
599
587
|
tracer.trace(`Trying to disconnect device ${id}`);
|
|
600
588
|
|
|
601
|
-
await
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
.trace(`Error while trying to cancel device connection`, { error });
|
|
608
|
-
});
|
|
589
|
+
await BlePlxManager.disconnectDevice(id).catch(error => {
|
|
590
|
+
// Only log, ignore if disconnect did not work
|
|
591
|
+
tracer
|
|
592
|
+
.withType("ble-error")
|
|
593
|
+
.trace(`Error while trying to cancel device connection`, { error });
|
|
594
|
+
});
|
|
609
595
|
tracer.trace(`Device ${id} disconnected`);
|
|
610
596
|
};
|
|
611
597
|
|
|
@@ -711,7 +697,7 @@ export default class BleTransport extends Transport {
|
|
|
711
697
|
);
|
|
712
698
|
|
|
713
699
|
// No concurrent exchange should happen at the same time, so all pending operations are part of the same exchange
|
|
714
|
-
this.cancelPendingOperations();
|
|
700
|
+
await this.cancelPendingOperations();
|
|
715
701
|
|
|
716
702
|
throw new TransportExchangeTimeoutError("Exchange aborted due to timeout");
|
|
717
703
|
}
|
|
@@ -750,11 +736,11 @@ export default class BleTransport extends Transport {
|
|
|
750
736
|
* but this error should be ignored. (In `exchange` our observable is unsubscribed before `cancelPendingOperations`
|
|
751
737
|
* is called so the error is ignored)
|
|
752
738
|
*/
|
|
753
|
-
private cancelPendingOperations() {
|
|
739
|
+
private async cancelPendingOperations() {
|
|
754
740
|
for (const transactionId of this.currentTransactionIds) {
|
|
755
741
|
try {
|
|
756
742
|
this.tracer.trace("Cancelling operation", { transactionId });
|
|
757
|
-
|
|
743
|
+
await BlePlxManager.cancelTransaction(transactionId);
|
|
758
744
|
} catch (error) {
|
|
759
745
|
this.tracer.trace("Error while cancelling operation", { transactionId, error });
|
|
760
746
|
}
|