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