@ledgerhq/react-native-hw-transport-ble 6.28.3-nightly.0 → 6.28.4-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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +20 -3
- package/lib/BleTransport.d.ts +67 -37
- package/lib/BleTransport.d.ts.map +1 -1
- package/lib/BleTransport.js +257 -198
- package/lib/BleTransport.js.map +1 -1
- package/lib/BleTransport.test.d.ts +2 -0
- package/lib/BleTransport.test.d.ts.map +1 -0
- package/lib/BleTransport.test.js +370 -0
- package/lib/BleTransport.test.js.map +1 -0
- package/lib/remapErrors.d.ts +4 -0
- package/lib/remapErrors.d.ts.map +1 -1
- package/lib/remapErrors.js +20 -1
- package/lib/remapErrors.js.map +1 -1
- package/lib/types.d.ts +4 -0
- package/lib/types.d.ts.map +1 -1
- package/lib-es/BleTransport.d.ts +67 -37
- package/lib-es/BleTransport.d.ts.map +1 -1
- package/lib-es/BleTransport.js +257 -198
- package/lib-es/BleTransport.js.map +1 -1
- package/lib-es/BleTransport.test.d.ts +2 -0
- package/lib-es/BleTransport.test.d.ts.map +1 -0
- package/lib-es/BleTransport.test.js +365 -0
- package/lib-es/BleTransport.test.js.map +1 -0
- package/lib-es/remapErrors.d.ts +4 -0
- package/lib-es/remapErrors.d.ts.map +1 -1
- package/lib-es/remapErrors.js +19 -1
- package/lib-es/remapErrors.js.map +1 -1
- package/lib-es/types.d.ts +4 -0
- package/lib-es/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/BleTransport.test.ts +275 -0
- package/src/BleTransport.ts +250 -172
- package/src/remapErrors.ts +33 -2
- package/src/types.ts +5 -0
package/lib-es/BleTransport.js
CHANGED
|
@@ -76,10 +76,7 @@ var __values = (this && this.__values) || function(o) {
|
|
|
76
76
|
};
|
|
77
77
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
78
78
|
};
|
|
79
|
-
/* eslint-disable prefer-template */
|
|
80
79
|
import Transport from "@ledgerhq/hw-transport";
|
|
81
|
-
import { BleManager, ConnectionPriority, BleErrorCode, } from "react-native-ble-plx";
|
|
82
|
-
import { getBluetoothServiceUuids, getInfosForServiceUuid, } from "@ledgerhq/devices";
|
|
83
80
|
// ---------------------------------------------------------------------------------------------
|
|
84
81
|
// Since this is a react-native library and metro bundler does not support
|
|
85
82
|
// package exports yet (see: https://github.com/facebook/metro/issues/670)
|
|
@@ -90,31 +87,25 @@ import { getBluetoothServiceUuids, getInfosForServiceUuid, } from "@ledgerhq/dev
|
|
|
90
87
|
// See: https://github.com/LedgerHQ/ledger-live/pull/879
|
|
91
88
|
import { sendAPDU } from "@ledgerhq/devices/lib/ble/sendAPDU";
|
|
92
89
|
import { receiveAPDU } from "@ledgerhq/devices/lib/ble/receiveAPDU";
|
|
90
|
+
import { BleManager, ConnectionPriority, BleErrorCode, LogLevel, } from "react-native-ble-plx";
|
|
91
|
+
import { getBluetoothServiceUuids, getInfosForServiceUuid, } from "@ledgerhq/devices";
|
|
93
92
|
import { log } from "@ledgerhq/logs";
|
|
94
93
|
import { defer, merge, from, of, throwError } from "rxjs";
|
|
95
94
|
import { share, ignoreElements, first, map, tap, catchError, } from "rxjs/operators";
|
|
96
|
-
import { CantOpenDevice, TransportError, DisconnectedDeviceDuringOperation, PairingFailed,
|
|
95
|
+
import { CantOpenDevice, TransportError, DisconnectedDeviceDuringOperation, PairingFailed, } from "@ledgerhq/errors";
|
|
97
96
|
import { monitorCharacteristic } from "./monitorCharacteristic";
|
|
98
97
|
import { awaitsBleOn } from "./awaitsBleOn";
|
|
99
|
-
import { decoratePromiseErrors, remapError } from "./remapErrors";
|
|
100
|
-
var connectOptions = {
|
|
101
|
-
requestMTU: 156,
|
|
102
|
-
connectionPriority: 1
|
|
103
|
-
};
|
|
104
|
-
var transportsCache = {};
|
|
105
|
-
var _bleManager = null;
|
|
98
|
+
import { decoratePromiseErrors, mapBleErrorToHwTransportError, remapError, } from "./remapErrors";
|
|
106
99
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* Do not use _bleManager directly
|
|
111
|
-
* Only use this instance getter inside BleTransport
|
|
100
|
+
* This is potentially not needed anymore, to be checked if the bug is still
|
|
101
|
+
* happening.
|
|
112
102
|
*/
|
|
113
|
-
var
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
var reconnectionConfig = {
|
|
104
|
+
pairingThreshold: 1000,
|
|
105
|
+
delayAfterFirstPairing: 4000
|
|
106
|
+
};
|
|
107
|
+
export var setReconnectionConfig = function (config) {
|
|
108
|
+
reconnectionConfig = config;
|
|
118
109
|
};
|
|
119
110
|
var retrieveInfos = function (device) {
|
|
120
111
|
if (!device || !device.serviceUUIDs)
|
|
@@ -127,146 +118,168 @@ var retrieveInfos = function (device) {
|
|
|
127
118
|
return;
|
|
128
119
|
return infos;
|
|
129
120
|
};
|
|
130
|
-
var
|
|
131
|
-
|
|
132
|
-
|
|
121
|
+
var delay = function (ms) {
|
|
122
|
+
return new Promise(function (success) { return setTimeout(success, ms); });
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* A cache of Bluetooth transport instances associated with device IDs.
|
|
126
|
+
* Allows efficient storage and retrieval of previously initialized transports.
|
|
127
|
+
* @type {Object.<string, BluetoothTransport>}
|
|
128
|
+
*/
|
|
129
|
+
var transportsCache = {};
|
|
130
|
+
/**
|
|
131
|
+
* Returns the instance of the Bluetooth Low Energy Manager. It initializes it only
|
|
132
|
+
* when it's first needed, preventing the permission prompt happening prematurely.
|
|
133
|
+
* Important: Do NOT access the _bleManager variable directly.
|
|
134
|
+
* Use this function instead.
|
|
135
|
+
* @returns {BleManager} - The instance of the BleManager.
|
|
136
|
+
*/
|
|
137
|
+
var _bleManager = null;
|
|
138
|
+
var bleManagerInstance = function () {
|
|
139
|
+
if (!_bleManager) {
|
|
140
|
+
_bleManager = new BleManager();
|
|
141
|
+
}
|
|
142
|
+
return _bleManager;
|
|
143
|
+
};
|
|
144
|
+
var clearDisconnectTimeout = function (deviceId) {
|
|
145
|
+
var cachedTransport = transportsCache[deviceId];
|
|
146
|
+
if (cachedTransport && cachedTransport.disconnectTimeout) {
|
|
147
|
+
log(TAG, "Clearing queued disconnect");
|
|
148
|
+
clearTimeout(cachedTransport.disconnectTimeout);
|
|
149
|
+
}
|
|
133
150
|
};
|
|
134
|
-
export function setReconnectionConfig(config) {
|
|
135
|
-
reconnectionConfig = config;
|
|
136
|
-
}
|
|
137
|
-
var delay = function (ms) { return new Promise(function (success) { return setTimeout(success, ms); }); };
|
|
138
151
|
function open(deviceOrId, needsReconnect) {
|
|
139
152
|
return __awaiter(this, void 0, void 0, function () {
|
|
140
|
-
var device, devices, connectedDevices, connectedDevicesFiltered, e_1, e_2, res, characteristics, _a, _b, uuid, e_3, e_4_1, deviceModel, serviceUuid, writeUuid, writeCmdUuid, notifyUuid, writeC, writeCmdC, notifyC, characteristics_1, characteristics_1_1, c, notifyObservable, notif, transport,
|
|
153
|
+
var device, devices, connectedDevices, connectedDevicesFiltered, e_1, e_2, res, characteristics, _a, _b, uuid, e_3, e_4_1, deviceModel, serviceUuid, writeUuid, writeCmdUuid, notifyUuid, writeC, writeCmdC, notifyC, characteristics_1, characteristics_1_1, c, notifyObservable, notif, transport, disconnectedSub, onDisconnect, beforeMTUTime, afterMTUTime;
|
|
141
154
|
var _c, _d, e_4, _e, e_5, _f;
|
|
142
155
|
return __generator(this, function (_g) {
|
|
143
156
|
switch (_g.label) {
|
|
144
157
|
case 0:
|
|
145
|
-
|
|
158
|
+
log(TAG, "open with ".concat(deviceOrId));
|
|
159
|
+
if (!(typeof deviceOrId === "string")) return [3 /*break*/, 12];
|
|
146
160
|
if (transportsCache[deviceOrId]) {
|
|
147
|
-
log(
|
|
161
|
+
log(TAG, "Transport in cache, using that.");
|
|
162
|
+
clearDisconnectTimeout(deviceOrId);
|
|
148
163
|
return [2 /*return*/, transportsCache[deviceOrId]];
|
|
149
164
|
}
|
|
150
|
-
log(
|
|
165
|
+
log(TAG, "Tries to open device: ".concat(deviceOrId));
|
|
151
166
|
return [4 /*yield*/, awaitsBleOn(bleManagerInstance())];
|
|
152
167
|
case 1:
|
|
153
168
|
_g.sent();
|
|
154
|
-
if (!!device) return [3 /*break*/, 3];
|
|
155
169
|
return [4 /*yield*/, bleManagerInstance().devices([deviceOrId])];
|
|
156
170
|
case 2:
|
|
157
171
|
devices = _g.sent();
|
|
158
|
-
log(
|
|
172
|
+
log(TAG, "found ".concat(devices.length, " devices"));
|
|
159
173
|
_c = __read(devices, 1), device = _c[0];
|
|
160
|
-
|
|
161
|
-
case 3:
|
|
162
|
-
if (!!device) return [3 /*break*/, 5];
|
|
174
|
+
if (!!device) return [3 /*break*/, 4];
|
|
163
175
|
return [4 /*yield*/, bleManagerInstance().connectedDevices(getBluetoothServiceUuids())];
|
|
164
|
-
case
|
|
176
|
+
case 3:
|
|
165
177
|
connectedDevices = _g.sent();
|
|
166
178
|
connectedDevicesFiltered = connectedDevices.filter(function (d) { return d.id === deviceOrId; });
|
|
167
|
-
log(
|
|
179
|
+
log(TAG, "found ".concat(connectedDevicesFiltered.length, " connected devices"));
|
|
168
180
|
_d = __read(connectedDevicesFiltered, 1), device = _d[0];
|
|
181
|
+
_g.label = 4;
|
|
182
|
+
case 4:
|
|
183
|
+
if (!!device) return [3 /*break*/, 11];
|
|
184
|
+
// We still don't have a device, so we attempt to connect to it.
|
|
185
|
+
log(TAG, "connectToDevice(".concat(deviceOrId, ")"));
|
|
169
186
|
_g.label = 5;
|
|
170
187
|
case 5:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
_g.label = 6;
|
|
188
|
+
_g.trys.push([5, 7, , 11]);
|
|
189
|
+
return [4 /*yield*/, bleManagerInstance().connectToDevice(deviceOrId)];
|
|
174
190
|
case 6:
|
|
175
|
-
_g.trys.push([6, 8, , 12]);
|
|
176
|
-
return [4 /*yield*/, bleManagerInstance().connectToDevice(deviceOrId, connectOptions)];
|
|
177
|
-
case 7:
|
|
178
191
|
device = _g.sent();
|
|
179
|
-
return [3 /*break*/,
|
|
180
|
-
case
|
|
192
|
+
return [3 /*break*/, 11];
|
|
193
|
+
case 7:
|
|
181
194
|
e_1 = _g.sent();
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
connectOptions = {};
|
|
195
|
+
log(TAG, "error code ".concat(e_1.errorCode));
|
|
196
|
+
if (!(e_1.errorCode === BleErrorCode.DeviceMTUChangeFailed)) return [3 /*break*/, 9];
|
|
185
197
|
return [4 /*yield*/, bleManagerInstance().connectToDevice(deviceOrId)];
|
|
186
|
-
case
|
|
198
|
+
case 8:
|
|
187
199
|
device = _g.sent();
|
|
188
|
-
return [3 /*break*/,
|
|
189
|
-
case
|
|
190
|
-
case
|
|
191
|
-
case
|
|
200
|
+
return [3 /*break*/, 10];
|
|
201
|
+
case 9: throw e_1;
|
|
202
|
+
case 10: return [3 /*break*/, 11];
|
|
203
|
+
case 11:
|
|
192
204
|
if (!device) {
|
|
193
205
|
throw new CantOpenDevice();
|
|
194
206
|
}
|
|
195
|
-
return [3 /*break*/,
|
|
196
|
-
case
|
|
207
|
+
return [3 /*break*/, 13];
|
|
208
|
+
case 12:
|
|
209
|
+
// It was already a Device
|
|
197
210
|
device = deviceOrId;
|
|
198
|
-
_g.label =
|
|
199
|
-
case
|
|
211
|
+
_g.label = 13;
|
|
212
|
+
case 13: return [4 /*yield*/, device.isConnected()];
|
|
213
|
+
case 14:
|
|
214
|
+
if (!!(_g.sent())) return [3 /*break*/, 21];
|
|
215
|
+
log(TAG, "not connected. connecting...");
|
|
216
|
+
_g.label = 15;
|
|
200
217
|
case 15:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
_g.label = 16;
|
|
218
|
+
_g.trys.push([15, 17, , 21]);
|
|
219
|
+
return [4 /*yield*/, device.connect()];
|
|
204
220
|
case 16:
|
|
205
|
-
_g.trys.push([16, 18, , 22]);
|
|
206
|
-
return [4 /*yield*/, device.connect(connectOptions)];
|
|
207
|
-
case 17:
|
|
208
221
|
_g.sent();
|
|
209
|
-
return [3 /*break*/,
|
|
210
|
-
case
|
|
222
|
+
return [3 /*break*/, 21];
|
|
223
|
+
case 17:
|
|
211
224
|
e_2 = _g.sent();
|
|
212
|
-
if (!(e_2.errorCode === BleErrorCode.DeviceMTUChangeFailed)) return [3 /*break*/,
|
|
213
|
-
//
|
|
214
|
-
connectOptions = {};
|
|
225
|
+
if (!(e_2.errorCode === BleErrorCode.DeviceMTUChangeFailed)) return [3 /*break*/, 19];
|
|
226
|
+
// Retry once for this specific error.
|
|
215
227
|
return [4 /*yield*/, device.connect()];
|
|
216
|
-
case
|
|
228
|
+
case 18:
|
|
229
|
+
// Retry once for this specific error.
|
|
217
230
|
_g.sent();
|
|
218
|
-
return [3 /*break*/,
|
|
219
|
-
case
|
|
220
|
-
case
|
|
221
|
-
case
|
|
222
|
-
case
|
|
231
|
+
return [3 /*break*/, 20];
|
|
232
|
+
case 19: throw e_2;
|
|
233
|
+
case 20: return [3 /*break*/, 21];
|
|
234
|
+
case 21: return [4 /*yield*/, device.discoverAllServicesAndCharacteristics()];
|
|
235
|
+
case 22:
|
|
223
236
|
_g.sent();
|
|
224
237
|
res = retrieveInfos(device);
|
|
225
|
-
if (!!res) return [3 /*break*/,
|
|
238
|
+
if (!!res) return [3 /*break*/, 32];
|
|
239
|
+
_g.label = 23;
|
|
240
|
+
case 23:
|
|
241
|
+
_g.trys.push([23, 30, 31, 32]);
|
|
242
|
+
_a = __values(getBluetoothServiceUuids()), _b = _a.next();
|
|
226
243
|
_g.label = 24;
|
|
227
244
|
case 24:
|
|
228
|
-
|
|
229
|
-
|
|
245
|
+
if (!!_b.done) return [3 /*break*/, 29];
|
|
246
|
+
uuid = _b.value;
|
|
230
247
|
_g.label = 25;
|
|
231
248
|
case 25:
|
|
232
|
-
|
|
233
|
-
uuid = _b.value;
|
|
234
|
-
_g.label = 26;
|
|
235
|
-
case 26:
|
|
236
|
-
_g.trys.push([26, 28, , 29]);
|
|
249
|
+
_g.trys.push([25, 27, , 28]);
|
|
237
250
|
return [4 /*yield*/, device.characteristicsForService(uuid)];
|
|
238
|
-
case
|
|
251
|
+
case 26:
|
|
239
252
|
characteristics = _g.sent();
|
|
240
253
|
res = getInfosForServiceUuid(uuid);
|
|
241
|
-
return [3 /*break*/, 30];
|
|
242
|
-
case 28:
|
|
243
|
-
e_3 = _g.sent();
|
|
244
254
|
return [3 /*break*/, 29];
|
|
245
|
-
case
|
|
255
|
+
case 27:
|
|
256
|
+
e_3 = _g.sent();
|
|
257
|
+
return [3 /*break*/, 28];
|
|
258
|
+
case 28:
|
|
246
259
|
_b = _a.next();
|
|
247
|
-
return [3 /*break*/,
|
|
248
|
-
case
|
|
249
|
-
case
|
|
260
|
+
return [3 /*break*/, 24];
|
|
261
|
+
case 29: return [3 /*break*/, 32];
|
|
262
|
+
case 30:
|
|
250
263
|
e_4_1 = _g.sent();
|
|
251
264
|
e_4 = { error: e_4_1 };
|
|
252
|
-
return [3 /*break*/,
|
|
253
|
-
case
|
|
265
|
+
return [3 /*break*/, 32];
|
|
266
|
+
case 31:
|
|
254
267
|
try {
|
|
255
268
|
if (_b && !_b.done && (_e = _a["return"])) _e.call(_a);
|
|
256
269
|
}
|
|
257
270
|
finally { if (e_4) throw e_4.error; }
|
|
258
271
|
return [7 /*endfinally*/];
|
|
259
|
-
case
|
|
272
|
+
case 32:
|
|
260
273
|
if (!res) {
|
|
261
274
|
throw new TransportError("service not found", "BLEServiceNotFound");
|
|
262
275
|
}
|
|
263
276
|
deviceModel = res.deviceModel, serviceUuid = res.serviceUuid, writeUuid = res.writeUuid, writeCmdUuid = res.writeCmdUuid, notifyUuid = res.notifyUuid;
|
|
264
|
-
if (!!characteristics) return [3 /*break*/,
|
|
277
|
+
if (!!characteristics) return [3 /*break*/, 34];
|
|
265
278
|
return [4 /*yield*/, device.characteristicsForService(serviceUuid)];
|
|
266
|
-
case
|
|
279
|
+
case 33:
|
|
267
280
|
characteristics = _g.sent();
|
|
268
|
-
_g.label =
|
|
269
|
-
case
|
|
281
|
+
_g.label = 34;
|
|
282
|
+
case 34:
|
|
270
283
|
if (!characteristics) {
|
|
271
284
|
throw new TransportError("service not found", "BLEServiceNotFound");
|
|
272
285
|
}
|
|
@@ -292,23 +305,23 @@ function open(deviceOrId, needsReconnect) {
|
|
|
292
305
|
finally { if (e_5) throw e_5.error; }
|
|
293
306
|
}
|
|
294
307
|
if (!writeC) {
|
|
295
|
-
throw new TransportError("write characteristic not found", "
|
|
308
|
+
throw new TransportError("write characteristic not found", "BLECharacteristicNotFound");
|
|
296
309
|
}
|
|
297
310
|
if (!notifyC) {
|
|
298
|
-
throw new TransportError("notify characteristic not found", "
|
|
311
|
+
throw new TransportError("notify characteristic not found", "BLECharacteristicNotFound");
|
|
299
312
|
}
|
|
300
313
|
if (!writeC.isWritableWithResponse) {
|
|
301
|
-
throw new TransportError("write characteristic not writableWithResponse", "
|
|
314
|
+
throw new TransportError("write characteristic not writableWithResponse", "BLECharacteristicInvalid");
|
|
302
315
|
}
|
|
303
316
|
if (!notifyC.isNotifiable) {
|
|
304
|
-
throw new TransportError("notify characteristic not notifiable", "
|
|
317
|
+
throw new TransportError("notify characteristic not notifiable", "BLECharacteristicInvalid");
|
|
305
318
|
}
|
|
306
319
|
if (writeCmdC) {
|
|
307
320
|
if (!writeCmdC.isWritableWithoutResponse) {
|
|
308
|
-
throw new TransportError("write cmd characteristic not writableWithoutResponse", "
|
|
321
|
+
throw new TransportError("write cmd characteristic not writableWithoutResponse", "BLECharacteristicInvalid");
|
|
309
322
|
}
|
|
310
323
|
}
|
|
311
|
-
log(
|
|
324
|
+
log(TAG, "device.mtu=".concat(device.mtu));
|
|
312
325
|
notifyObservable = monitorCharacteristic(notifyC).pipe(catchError(function (e) {
|
|
313
326
|
// LL-9033 fw 2.0.2 introduced this case, we silence the inner unhandled error.
|
|
314
327
|
var msg = String(e);
|
|
@@ -321,58 +334,57 @@ function open(deviceOrId, needsReconnect) {
|
|
|
321
334
|
log("ble-frame", "<= " + value.toString("hex"));
|
|
322
335
|
}), share());
|
|
323
336
|
notif = notifyObservable.subscribe();
|
|
324
|
-
transport = new
|
|
325
|
-
return [4 /*yield*/, transport.requestConnectionPriority("High")];
|
|
326
|
-
case 36:
|
|
327
|
-
_g.sent();
|
|
337
|
+
transport = new BleTransport(device, writeC, writeCmdC, notifyObservable, deviceModel);
|
|
328
338
|
onDisconnect = function (e) {
|
|
339
|
+
transport.isConnected = false;
|
|
329
340
|
transport.notYetDisconnected = false;
|
|
330
341
|
notif.unsubscribe();
|
|
331
|
-
disconnectedSub.remove();
|
|
342
|
+
disconnectedSub === null || disconnectedSub === void 0 ? void 0 : disconnectedSub.remove();
|
|
343
|
+
clearDisconnectTimeout(transport.id);
|
|
332
344
|
delete transportsCache[transport.id];
|
|
333
|
-
log(
|
|
345
|
+
log(TAG, "BleTransport(".concat(transport.id, ") disconnected"));
|
|
334
346
|
transport.emit("disconnect", e);
|
|
335
347
|
};
|
|
336
348
|
// eslint-disable-next-line require-atomic-updates
|
|
337
349
|
transportsCache[transport.id] = transport;
|
|
350
|
+
beforeMTUTime = Date.now();
|
|
338
351
|
disconnectedSub = device.onDisconnected(function (e) {
|
|
339
352
|
if (!transport.notYetDisconnected)
|
|
340
353
|
return;
|
|
341
354
|
onDisconnect(e);
|
|
342
355
|
});
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
_g.trys.push([37, , 39, 45]);
|
|
356
|
+
_g.label = 35;
|
|
357
|
+
case 35:
|
|
358
|
+
_g.trys.push([35, , 37, 43]);
|
|
347
359
|
return [4 /*yield*/, transport.inferMTU()];
|
|
348
|
-
case
|
|
360
|
+
case 36:
|
|
349
361
|
_g.sent();
|
|
350
|
-
return [3 /*break*/,
|
|
351
|
-
case
|
|
362
|
+
return [3 /*break*/, 43];
|
|
363
|
+
case 37:
|
|
352
364
|
afterMTUTime = Date.now();
|
|
353
|
-
if (!reconnectionConfig) return [3 /*break*/,
|
|
365
|
+
if (!reconnectionConfig) return [3 /*break*/, 41];
|
|
354
366
|
// workaround for #279: we need to open() again if we come the first time here,
|
|
355
367
|
// to make sure we do a disconnect() after the first pairing time
|
|
356
368
|
// because of a firmware bug
|
|
357
369
|
if (afterMTUTime - beforeMTUTime < reconnectionConfig.pairingThreshold) {
|
|
358
370
|
needsReconnect = false; // (optim) there is likely no new pairing done because mtu answer was fast.
|
|
359
371
|
}
|
|
360
|
-
if (!needsReconnect) return [3 /*break*/,
|
|
372
|
+
if (!needsReconnect) return [3 /*break*/, 40];
|
|
361
373
|
// necessary time for the bonding workaround
|
|
362
|
-
return [4 /*yield*/,
|
|
363
|
-
case
|
|
374
|
+
return [4 /*yield*/, BleTransport.disconnect(transport.id)["catch"](function () { })];
|
|
375
|
+
case 38:
|
|
364
376
|
// necessary time for the bonding workaround
|
|
365
377
|
_g.sent();
|
|
366
378
|
return [4 /*yield*/, delay(reconnectionConfig.delayAfterFirstPairing)];
|
|
367
|
-
case
|
|
379
|
+
case 39:
|
|
368
380
|
_g.sent();
|
|
381
|
+
_g.label = 40;
|
|
382
|
+
case 40: return [3 /*break*/, 42];
|
|
383
|
+
case 41:
|
|
384
|
+
needsReconnect = false;
|
|
369
385
|
_g.label = 42;
|
|
370
|
-
case 42: return [
|
|
386
|
+
case 42: return [7 /*endfinally*/];
|
|
371
387
|
case 43:
|
|
372
|
-
needsReconnect = false;
|
|
373
|
-
_g.label = 44;
|
|
374
|
-
case 44: return [7 /*endfinally*/];
|
|
375
|
-
case 45:
|
|
376
388
|
if (needsReconnect) {
|
|
377
389
|
return [2 /*return*/, open(device, false)];
|
|
378
390
|
}
|
|
@@ -384,16 +396,22 @@ function open(deviceOrId, needsReconnect) {
|
|
|
384
396
|
/**
|
|
385
397
|
* react-native bluetooth BLE implementation
|
|
386
398
|
* @example
|
|
387
|
-
* import
|
|
399
|
+
* import BleTransport from "@ledgerhq/react-native-hw-transport-ble";
|
|
388
400
|
*/
|
|
389
|
-
var
|
|
390
|
-
|
|
391
|
-
|
|
401
|
+
var TAG = "ble-verbose";
|
|
402
|
+
var BleTransport = /** @class */ (function (_super) {
|
|
403
|
+
__extends(BleTransport, _super);
|
|
404
|
+
function BleTransport(device, writeCharacteristic, writeCmdCharacteristic, notifyObservable, deviceModel) {
|
|
392
405
|
var _this = _super.call(this) || this;
|
|
406
|
+
_this.disconnectTimeout = null;
|
|
407
|
+
_this.isConnected = true;
|
|
393
408
|
_this.mtuSize = 20;
|
|
394
409
|
_this.notYetDisconnected = true;
|
|
395
410
|
/**
|
|
396
|
-
*
|
|
411
|
+
* Send data to the device using a low level API.
|
|
412
|
+
* It's recommended to use the "send" method for a higher level API.
|
|
413
|
+
* @param {Buffer} apdu - The data to send.
|
|
414
|
+
* @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
|
|
397
415
|
*/
|
|
398
416
|
_this.exchange = function (apdu) {
|
|
399
417
|
return _this.exchangeAtomicImpl(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
@@ -404,9 +422,7 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
404
422
|
_b.trys.push([0, 2, , 5]);
|
|
405
423
|
msgIn = apdu.toString("hex");
|
|
406
424
|
log("apdu", "=> ".concat(msgIn));
|
|
407
|
-
return [4 /*yield*/, merge(
|
|
408
|
-
// $FlowFixMe
|
|
409
|
-
this.notifyObservable.pipe(receiveAPDU), sendAPDU(this.write, apdu, this.mtuSize)).toPromise()];
|
|
425
|
+
return [4 /*yield*/, merge(this.notifyObservable.pipe(receiveAPDU), sendAPDU(this.write, apdu, this.mtuSize)).toPromise()];
|
|
410
426
|
case 1:
|
|
411
427
|
data = _b.sent();
|
|
412
428
|
msgOut = data.toString("hex");
|
|
@@ -429,6 +445,12 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
429
445
|
});
|
|
430
446
|
}); });
|
|
431
447
|
};
|
|
448
|
+
/**
|
|
449
|
+
* Do not call this directly unless you know what you're doing. Communication
|
|
450
|
+
* with a Ledger device should be through the {@link exchange} method.
|
|
451
|
+
* @param buffer
|
|
452
|
+
* @param txid
|
|
453
|
+
*/
|
|
432
454
|
_this.write = function (buffer, txid) { return __awaiter(_this, void 0, void 0, function () {
|
|
433
455
|
var e_7, e_8;
|
|
434
456
|
return __generator(this, function (_b) {
|
|
@@ -466,15 +488,17 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
466
488
|
_this.writeCmdCharacteristic = writeCmdCharacteristic;
|
|
467
489
|
_this.notifyObservable = notifyObservable;
|
|
468
490
|
_this.deviceModel = deviceModel;
|
|
469
|
-
log(
|
|
491
|
+
log(TAG, "BleTransport(".concat(String(_this.id), ") new instance"));
|
|
492
|
+
clearDisconnectTimeout(_this.id);
|
|
470
493
|
return _this;
|
|
471
494
|
}
|
|
472
495
|
/**
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
496
|
+
* Listen to state changes on the bleManagerInstance and notify the
|
|
497
|
+
* specified observer.
|
|
498
|
+
* @param observer
|
|
499
|
+
* @returns TransportSubscription
|
|
476
500
|
*/
|
|
477
|
-
|
|
501
|
+
BleTransport.observeState = function (observer) {
|
|
478
502
|
var emitFromState = function (type) {
|
|
479
503
|
observer.next({
|
|
480
504
|
type: type,
|
|
@@ -488,48 +512,52 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
488
512
|
};
|
|
489
513
|
/**
|
|
490
514
|
* Scan for bluetooth Ledger devices
|
|
515
|
+
* @param observer Device is partial in order to avoid the live-common/this dep
|
|
516
|
+
* @returns TransportSubscription
|
|
491
517
|
*/
|
|
492
|
-
|
|
518
|
+
BleTransport.listen = function (observer) {
|
|
493
519
|
var _this = this;
|
|
494
|
-
log(
|
|
520
|
+
log(TAG, "listening for devices");
|
|
495
521
|
var unsubscribed;
|
|
496
522
|
var stateSub = bleManagerInstance().onStateChange(function (state) { return __awaiter(_this, void 0, void 0, function () {
|
|
497
523
|
var devices;
|
|
498
524
|
return __generator(this, function (_b) {
|
|
499
525
|
switch (_b.label) {
|
|
500
526
|
case 0:
|
|
501
|
-
if (!(state === "PoweredOn")) return [3 /*break*/,
|
|
527
|
+
if (!(state === "PoweredOn")) return [3 /*break*/, 4];
|
|
502
528
|
stateSub.remove();
|
|
503
529
|
return [4 /*yield*/, bleManagerInstance().connectedDevices(getBluetoothServiceUuids())];
|
|
504
530
|
case 1:
|
|
505
531
|
devices = _b.sent();
|
|
506
532
|
if (unsubscribed)
|
|
507
533
|
return [2 /*return*/];
|
|
508
|
-
return [
|
|
509
|
-
|
|
510
|
-
|
|
534
|
+
if (!devices.length) return [3 /*break*/, 3];
|
|
535
|
+
log(TAG, "disconnecting from devices");
|
|
536
|
+
return [4 /*yield*/, Promise.all(devices.map(function (d) { return BleTransport.disconnect(d.id)["catch"](function () { }); }))];
|
|
511
537
|
case 2:
|
|
512
538
|
_b.sent();
|
|
539
|
+
_b.label = 3;
|
|
540
|
+
case 3:
|
|
513
541
|
if (unsubscribed)
|
|
514
542
|
return [2 /*return*/];
|
|
515
|
-
bleManagerInstance().startDeviceScan(getBluetoothServiceUuids(), null, function (bleError,
|
|
543
|
+
bleManagerInstance().startDeviceScan(getBluetoothServiceUuids(), null, function (bleError, scannedDevice) {
|
|
516
544
|
if (bleError) {
|
|
517
545
|
observer.error(mapBleErrorToHwTransportError(bleError));
|
|
518
546
|
unsubscribe();
|
|
519
547
|
return;
|
|
520
548
|
}
|
|
521
|
-
var res = retrieveInfos(
|
|
549
|
+
var res = retrieveInfos(scannedDevice);
|
|
522
550
|
var deviceModel = res && res.deviceModel;
|
|
523
|
-
if (
|
|
551
|
+
if (scannedDevice) {
|
|
524
552
|
observer.next({
|
|
525
553
|
type: "add",
|
|
526
|
-
descriptor:
|
|
554
|
+
descriptor: scannedDevice,
|
|
527
555
|
deviceModel: deviceModel
|
|
528
556
|
});
|
|
529
557
|
}
|
|
530
558
|
});
|
|
531
|
-
_b.label =
|
|
532
|
-
case
|
|
559
|
+
_b.label = 4;
|
|
560
|
+
case 4: return [2 /*return*/];
|
|
533
561
|
}
|
|
534
562
|
});
|
|
535
563
|
}); }, true);
|
|
@@ -537,7 +565,7 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
537
565
|
unsubscribed = true;
|
|
538
566
|
bleManagerInstance().stopDeviceScan();
|
|
539
567
|
stateSub.remove();
|
|
540
|
-
log(
|
|
568
|
+
log(TAG, "done listening.");
|
|
541
569
|
};
|
|
542
570
|
return {
|
|
543
571
|
unsubscribe: unsubscribe
|
|
@@ -545,17 +573,20 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
545
573
|
};
|
|
546
574
|
/**
|
|
547
575
|
* Open a BLE transport
|
|
548
|
-
* @param {
|
|
576
|
+
* @param {Device | string} deviceOrId
|
|
549
577
|
*/
|
|
550
|
-
|
|
578
|
+
BleTransport.open = function (deviceOrId) {
|
|
551
579
|
return __awaiter(this, void 0, void 0, function () {
|
|
552
580
|
return __generator(this, function (_b) {
|
|
553
581
|
return [2 /*return*/, open(deviceOrId, true)];
|
|
554
582
|
});
|
|
555
583
|
});
|
|
556
584
|
};
|
|
557
|
-
|
|
558
|
-
|
|
585
|
+
/**
|
|
586
|
+
* Negotiate with the device the maximum transfer unit for the ble frames
|
|
587
|
+
* @returns Promise<number>
|
|
588
|
+
*/
|
|
589
|
+
BleTransport.prototype.inferMTU = function () {
|
|
559
590
|
return __awaiter(this, void 0, void 0, function () {
|
|
560
591
|
var mtu, mtuSize;
|
|
561
592
|
var _this = this;
|
|
@@ -580,7 +611,7 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
580
611
|
return [3 /*break*/, 4];
|
|
581
612
|
case 2:
|
|
582
613
|
e_9 = _b.sent();
|
|
583
|
-
log("ble-error", "inferMTU got " +
|
|
614
|
+
log("ble-error", "inferMTU got " + JSON.stringify(e_9));
|
|
584
615
|
return [4 /*yield*/, bleManagerInstance()
|
|
585
616
|
.cancelDeviceConnection(this.id)["catch"](function () { })];
|
|
586
617
|
case 3:
|
|
@@ -594,7 +625,7 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
594
625
|
_b.sent();
|
|
595
626
|
if (mtu > 23) {
|
|
596
627
|
mtuSize = mtu - 3;
|
|
597
|
-
log(
|
|
628
|
+
log(TAG, "BleTransport(".concat(this.id, ") mtu set to ").concat(mtuSize));
|
|
598
629
|
this.mtuSize = mtuSize;
|
|
599
630
|
}
|
|
600
631
|
return [2 /*return*/, this.mtuSize];
|
|
@@ -602,84 +633,112 @@ var BluetoothTransport = /** @class */ (function (_super) {
|
|
|
602
633
|
});
|
|
603
634
|
});
|
|
604
635
|
};
|
|
605
|
-
|
|
636
|
+
/**
|
|
637
|
+
* Exposed method from the ble-plx library
|
|
638
|
+
* Request the connection priority for the given device.
|
|
639
|
+
* @param {"Balanced" | "High" | "LowPower"} connectionPriority: Connection priority.
|
|
640
|
+
* @returns {Promise<Device>} Connected device.
|
|
641
|
+
*/
|
|
642
|
+
BleTransport.prototype.requestConnectionPriority = function (connectionPriority) {
|
|
606
643
|
return __awaiter(this, void 0, void 0, function () {
|
|
607
644
|
return __generator(this, function (_b) {
|
|
608
645
|
switch (_b.label) {
|
|
609
646
|
case 0: return [4 /*yield*/, decoratePromiseErrors(this.device.requestConnectionPriority(ConnectionPriority[connectionPriority]))];
|
|
610
|
-
case 1:
|
|
611
|
-
_b.sent();
|
|
612
|
-
return [2 /*return*/];
|
|
647
|
+
case 1: return [2 /*return*/, _b.sent()];
|
|
613
648
|
}
|
|
614
649
|
});
|
|
615
650
|
});
|
|
616
651
|
};
|
|
617
|
-
|
|
618
|
-
|
|
652
|
+
/**
|
|
653
|
+
* We intentionally do not immediately close a transport connection.
|
|
654
|
+
* Instead, we queue the disconnect and wait for a future connection to dismiss the event.
|
|
655
|
+
* This approach prevents unnecessary disconnects and reconnects. We use the isConnected
|
|
656
|
+
* flag to ensure that we do not trigger a disconnect if the current cached transport has
|
|
657
|
+
* already been disconnected.
|
|
658
|
+
* @returns {Promise<void>}
|
|
659
|
+
*/
|
|
660
|
+
BleTransport.prototype.close = function () {
|
|
619
661
|
return __awaiter(this, void 0, void 0, function () {
|
|
662
|
+
var resolve, disconnectPromise;
|
|
663
|
+
var _this = this;
|
|
620
664
|
return __generator(this, function (_b) {
|
|
621
665
|
switch (_b.label) {
|
|
622
666
|
case 0:
|
|
623
|
-
|
|
624
|
-
|
|
667
|
+
disconnectPromise = new Promise(function (innerResolve) {
|
|
668
|
+
resolve = innerResolve;
|
|
669
|
+
});
|
|
670
|
+
clearDisconnectTimeout(this.id);
|
|
671
|
+
log(TAG, "Queuing a disconnect");
|
|
672
|
+
this.disconnectTimeout = setTimeout(function () {
|
|
673
|
+
log(TAG, "Triggering a disconnect from ".concat(_this.id));
|
|
674
|
+
if (_this.isConnected) {
|
|
675
|
+
BleTransport.disconnect(_this.id)["catch"](function () { })["finally"](resolve);
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
resolve();
|
|
679
|
+
}
|
|
680
|
+
}, BleTransport.disconnectTimeoutMs);
|
|
681
|
+
// The closure will occur no later than 5s, triggered either by disconnection
|
|
682
|
+
// or the actual response of the apdu.
|
|
683
|
+
return [4 /*yield*/, Promise.race([
|
|
684
|
+
this.exchangeBusyPromise || Promise.resolve(),
|
|
685
|
+
disconnectPromise,
|
|
686
|
+
])];
|
|
625
687
|
case 1:
|
|
688
|
+
// The closure will occur no later than 5s, triggered either by disconnection
|
|
689
|
+
// or the actual response of the apdu.
|
|
626
690
|
_b.sent();
|
|
627
|
-
|
|
628
|
-
case 2: return [2 /*return*/];
|
|
691
|
+
return [2 /*return*/];
|
|
629
692
|
}
|
|
630
693
|
});
|
|
631
694
|
});
|
|
632
695
|
};
|
|
633
696
|
var _a;
|
|
634
|
-
_a =
|
|
697
|
+
_a = BleTransport;
|
|
698
|
+
BleTransport.disconnectTimeoutMs = 5000;
|
|
635
699
|
/**
|
|
636
700
|
*
|
|
637
701
|
*/
|
|
638
|
-
|
|
702
|
+
BleTransport.isSupported = function () {
|
|
639
703
|
return Promise.resolve(typeof BleManager === "function");
|
|
640
704
|
};
|
|
641
705
|
/**
|
|
642
706
|
*
|
|
643
707
|
*/
|
|
644
|
-
|
|
645
|
-
bleManagerInstance().setLogLevel(level);
|
|
646
|
-
};
|
|
647
|
-
BluetoothTransport.list = function () {
|
|
708
|
+
BleTransport.list = function () {
|
|
648
709
|
throw new Error("not implemented");
|
|
649
710
|
};
|
|
650
711
|
/**
|
|
651
|
-
*
|
|
712
|
+
* Exposed method from the ble-plx library
|
|
713
|
+
* Sets new log level for native module's logging mechanism.
|
|
714
|
+
* @param string logLevel New log level to be set.
|
|
652
715
|
*/
|
|
653
|
-
|
|
716
|
+
BleTransport.setLogLevel = function (logLevel) {
|
|
717
|
+
if (Object.values(LogLevel).includes(logLevel)) {
|
|
718
|
+
bleManagerInstance().setLogLevel(logLevel);
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
throw new Error("".concat(logLevel, " is not a valid LogLevel"));
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
/**
|
|
725
|
+
* Exposed method from the ble-plx library
|
|
726
|
+
* Disconnects from {@link Device} if it's connected or cancels pending connection.
|
|
727
|
+
*/
|
|
728
|
+
BleTransport.disconnect = function (id) { return __awaiter(void 0, void 0, void 0, function () {
|
|
654
729
|
return __generator(_a, function (_b) {
|
|
655
730
|
switch (_b.label) {
|
|
656
731
|
case 0:
|
|
657
|
-
log(
|
|
732
|
+
log(TAG, "user disconnect(".concat(id, ")"));
|
|
658
733
|
return [4 /*yield*/, bleManagerInstance().cancelDeviceConnection(id)];
|
|
659
734
|
case 1:
|
|
660
735
|
_b.sent();
|
|
736
|
+
log(TAG, "disconnected");
|
|
661
737
|
return [2 /*return*/];
|
|
662
738
|
}
|
|
663
739
|
});
|
|
664
740
|
}); };
|
|
665
|
-
return
|
|
741
|
+
return BleTransport;
|
|
666
742
|
}(Transport));
|
|
667
|
-
export default
|
|
668
|
-
var bleErrorToHwTransportError = new Map([
|
|
669
|
-
[BleErrorCode.ScanStartFailed, HwTransportErrorType.BleScanStartFailed],
|
|
670
|
-
[
|
|
671
|
-
BleErrorCode.LocationServicesDisabled,
|
|
672
|
-
HwTransportErrorType.BleLocationServicesDisabled,
|
|
673
|
-
],
|
|
674
|
-
[
|
|
675
|
-
BleErrorCode.BluetoothUnauthorized,
|
|
676
|
-
HwTransportErrorType.BleBluetoothUnauthorized,
|
|
677
|
-
],
|
|
678
|
-
]);
|
|
679
|
-
var mapBleErrorToHwTransportError = function (bleError) {
|
|
680
|
-
var message = "".concat(bleError.message, ". Origin: ").concat(bleError.errorCode);
|
|
681
|
-
var inferedType = bleErrorToHwTransportError.get(bleError.errorCode);
|
|
682
|
-
var type = !inferedType ? HwTransportErrorType.Unknown : inferedType;
|
|
683
|
-
return new HwTransportError(type, message);
|
|
684
|
-
};
|
|
743
|
+
export default BleTransport;
|
|
685
744
|
//# sourceMappingURL=BleTransport.js.map
|