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