@onekeyfe/hardware-cli 1.2.2-alpha.1 → 1.2.2-alpha.100
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.
|
@@ -20,7 +20,6 @@ const connectedDevices = new Map();
|
|
|
20
20
|
const deviceCharacteristics = new Map();
|
|
21
21
|
const notificationStates = new Map();
|
|
22
22
|
const notificationGenerations = new Map();
|
|
23
|
-
const disconnectListeners = new Map();
|
|
24
23
|
function isOneKeyPeripheral(peripheral) {
|
|
25
24
|
const serviceUuids = peripheral.advertisement?.serviceUuids;
|
|
26
25
|
return ((0, hd_shared_1.hasOnekeyCommunicationService)(serviceUuids) &&
|
|
@@ -64,32 +63,11 @@ function clearNotificationState(deviceId, reason) {
|
|
|
64
63
|
if (!state)
|
|
65
64
|
return;
|
|
66
65
|
notificationStates.delete(deviceId);
|
|
67
|
-
const error =
|
|
66
|
+
const error = new Error(reason);
|
|
68
67
|
state.pendingReceivers.forEach(receiver => receiver.reject(error));
|
|
69
68
|
state.pendingReceivers.clear();
|
|
70
69
|
state.queue.length = 0;
|
|
71
70
|
}
|
|
72
|
-
function removeDisconnectListener(deviceId) {
|
|
73
|
-
const tracked = disconnectListeners.get(deviceId);
|
|
74
|
-
if (!tracked)
|
|
75
|
-
return;
|
|
76
|
-
tracked.peripheral.removeListener('disconnect', tracked.listener);
|
|
77
|
-
disconnectListeners.delete(deviceId);
|
|
78
|
-
}
|
|
79
|
-
function trackUnexpectedDisconnect(deviceId, peripheral) {
|
|
80
|
-
removeDisconnectListener(deviceId);
|
|
81
|
-
const listener = (reason) => {
|
|
82
|
-
removeDisconnectListener(deviceId);
|
|
83
|
-
if (connectedDevices.get(deviceId) !== peripheral)
|
|
84
|
-
return;
|
|
85
|
-
deviceCharacteristics.get(deviceId)?.notify.removeAllListeners('data');
|
|
86
|
-
connectedDevices.delete(deviceId);
|
|
87
|
-
deviceCharacteristics.delete(deviceId);
|
|
88
|
-
clearNotificationState(deviceId, hd_shared_1.ERRORS.TypedError(hd_shared_1.HardwareErrorCode.BleDeviceDisconnected, reason || `BLE device disconnected: ${deviceId}`));
|
|
89
|
-
};
|
|
90
|
-
disconnectListeners.set(deviceId, { peripheral, listener });
|
|
91
|
-
peripheral.on('disconnect', listener);
|
|
92
|
-
}
|
|
93
71
|
function waitForNobleCleanup(registerCallback) {
|
|
94
72
|
return new Promise(resolve => {
|
|
95
73
|
let completed = false;
|
|
@@ -302,7 +280,6 @@ function writeCharacteristic(characteristic, buffer, withoutResponse) {
|
|
|
302
280
|
async function disconnectDevice(uuid) {
|
|
303
281
|
const peripheral = connectedDevices.get(uuid);
|
|
304
282
|
const characteristics = deviceCharacteristics.get(uuid);
|
|
305
|
-
removeDisconnectListener(uuid);
|
|
306
283
|
clearNotificationState(uuid, `BLE device disconnected: ${uuid}`);
|
|
307
284
|
if (characteristics) {
|
|
308
285
|
characteristics.notify.removeAllListeners('data');
|
|
@@ -344,10 +321,8 @@ function createNobleBlePlugin() {
|
|
|
344
321
|
await subscribeNotifications(uuid, notificationState.generation, characteristics.notify);
|
|
345
322
|
connectedDevices.set(uuid, peripheral);
|
|
346
323
|
deviceCharacteristics.set(uuid, characteristics);
|
|
347
|
-
trackUnexpectedDisconnect(uuid, peripheral);
|
|
348
324
|
}
|
|
349
325
|
catch (error) {
|
|
350
|
-
removeDisconnectListener(uuid);
|
|
351
326
|
clearNotificationState(uuid, `BLE notification subscription failed: ${uuid}`);
|
|
352
327
|
if (characteristics) {
|
|
353
328
|
characteristics.notify.removeAllListeners('data');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hardware-cli",
|
|
3
|
-
"version": "1.2.2-alpha.
|
|
3
|
+
"version": "1.2.2-alpha.100",
|
|
4
4
|
"description": "OneKey hardware wallet CLI for testing device communication",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"test": "jest"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@onekeyfe/hd-common-connect-sdk": "1.2.2-alpha.
|
|
35
|
-
"@onekeyfe/hd-core": "1.2.2-alpha.
|
|
36
|
-
"@onekeyfe/hd-shared": "1.2.2-alpha.
|
|
37
|
-
"@onekeyfe/hd-transport-usb": "1.2.2-alpha.
|
|
34
|
+
"@onekeyfe/hd-common-connect-sdk": "1.2.2-alpha.100",
|
|
35
|
+
"@onekeyfe/hd-core": "1.2.2-alpha.100",
|
|
36
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.100",
|
|
37
|
+
"@onekeyfe/hd-transport-usb": "1.2.2-alpha.100",
|
|
38
38
|
"@stoprocent/noble": "2.3.16",
|
|
39
39
|
"commander": "^12.0.0"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "c40dad085297b0e3cc2020bd218c146dff6ed3e1"
|
|
42
42
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
2
|
|
|
4
3
|
type MockCharacteristic = EventEmitter & {
|
|
5
4
|
uuid: string;
|
|
@@ -28,19 +27,18 @@ const createPeripheral = (id: string) => {
|
|
|
28
27
|
uuid: '0001',
|
|
29
28
|
discoverCharacteristics: jest.fn((_uuids, callback) => callback(null, [write, notify])),
|
|
30
29
|
};
|
|
31
|
-
const peripheral = Object.assign(new EventEmitter(), {
|
|
32
|
-
id,
|
|
33
|
-
state: 'connected',
|
|
34
|
-
advertisement: {
|
|
35
|
-
localName: `OneKey Pro 2 ${id}`,
|
|
36
|
-
serviceUuids: ['0001'],
|
|
37
|
-
},
|
|
38
|
-
discoverServices: jest.fn((_uuids, callback) => callback(null, [service])),
|
|
39
|
-
connect: jest.fn(callback => callback()),
|
|
40
|
-
disconnect: jest.fn(callback => callback()),
|
|
41
|
-
});
|
|
42
30
|
return {
|
|
43
|
-
peripheral
|
|
31
|
+
peripheral: {
|
|
32
|
+
id,
|
|
33
|
+
state: 'connected',
|
|
34
|
+
advertisement: {
|
|
35
|
+
localName: `OneKey Pro 2 ${id}`,
|
|
36
|
+
serviceUuids: ['0001'],
|
|
37
|
+
},
|
|
38
|
+
discoverServices: jest.fn((_uuids, callback) => callback(null, [service])),
|
|
39
|
+
connect: jest.fn(callback => callback()),
|
|
40
|
+
disconnect: jest.fn(callback => callback()),
|
|
41
|
+
},
|
|
44
42
|
service,
|
|
45
43
|
write,
|
|
46
44
|
notify,
|
|
@@ -179,38 +177,6 @@ describe('Noble BLE plugin notification routing', () => {
|
|
|
179
177
|
expect(result).toBe('completed');
|
|
180
178
|
});
|
|
181
179
|
|
|
182
|
-
test('rejects a pending receive when the peripheral disconnects unexpectedly', async () => {
|
|
183
|
-
const device = createPeripheral('device-a');
|
|
184
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
185
|
-
state: string;
|
|
186
|
-
startScanning: jest.Mock;
|
|
187
|
-
stopScanning: jest.Mock;
|
|
188
|
-
};
|
|
189
|
-
noble.state = 'poweredOn';
|
|
190
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
191
|
-
callback?.();
|
|
192
|
-
noble.emit('discover', device.peripheral);
|
|
193
|
-
});
|
|
194
|
-
noble.stopScanning = jest.fn(callback => callback?.());
|
|
195
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
196
|
-
|
|
197
|
-
const { createNobleBlePlugin } = await import('../transports/nobleBlePlugin');
|
|
198
|
-
const plugin = createNobleBlePlugin();
|
|
199
|
-
await plugin.init();
|
|
200
|
-
await plugin.connect('device-a');
|
|
201
|
-
|
|
202
|
-
const receive = plugin.receive('device-a');
|
|
203
|
-
device.peripheral.state = 'disconnected';
|
|
204
|
-
device.peripheral.emit('disconnect', 'Remote User Terminated Connection');
|
|
205
|
-
|
|
206
|
-
await expect(receive).rejects.toMatchObject({
|
|
207
|
-
errorCode: HardwareErrorCode.BleDeviceDisconnected,
|
|
208
|
-
});
|
|
209
|
-
await expect(plugin.receive('device-a')).rejects.toMatchObject({
|
|
210
|
-
errorCode: HardwareErrorCode.TransportNotFound,
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
180
|
test('disconnects an untracked peripheral when service discovery fails', async () => {
|
|
215
181
|
const device = createPeripheral('device-a');
|
|
216
182
|
device.peripheral.discoverServices.mockImplementation((_uuids, callback) =>
|
|
@@ -43,11 +43,6 @@ type NobleNotificationState = {
|
|
|
43
43
|
pendingReceivers: Set<NoblePendingReceiver>;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
type NobleDisconnectListener = {
|
|
47
|
-
peripheral: Peripheral;
|
|
48
|
-
listener: (reason: string) => void;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
46
|
const ONEKEY_SERVICE_UUIDS = [ONEKEY_SERVICE_UUID];
|
|
52
47
|
const ONEKEY_SERVICE_UUID_ALIASES = createKnownBleUuidAliases(ONEKEY_SERVICE_UUID);
|
|
53
48
|
const ONEKEY_WRITE_UUID_ALIASES = createKnownBleUuidAliases(ONEKEY_WRITE_CHARACTERISTIC_UUID);
|
|
@@ -68,7 +63,6 @@ const connectedDevices = new Map<string, Peripheral>();
|
|
|
68
63
|
const deviceCharacteristics = new Map<string, CharacteristicPair>();
|
|
69
64
|
const notificationStates = new Map<string, NobleNotificationState>();
|
|
70
65
|
const notificationGenerations = new Map<string, number>();
|
|
71
|
-
const disconnectListeners = new Map<string, NobleDisconnectListener>();
|
|
72
66
|
|
|
73
67
|
function isOneKeyPeripheral(peripheral: Peripheral) {
|
|
74
68
|
const serviceUuids = peripheral.advertisement?.serviceUuids;
|
|
@@ -114,45 +108,17 @@ function createNotificationState(deviceId: string) {
|
|
|
114
108
|
return state;
|
|
115
109
|
}
|
|
116
110
|
|
|
117
|
-
function clearNotificationState(deviceId: string, reason: string
|
|
111
|
+
function clearNotificationState(deviceId: string, reason: string) {
|
|
118
112
|
const state = notificationStates.get(deviceId);
|
|
119
113
|
if (!state) return;
|
|
120
114
|
|
|
121
115
|
notificationStates.delete(deviceId);
|
|
122
|
-
const error =
|
|
116
|
+
const error = new Error(reason);
|
|
123
117
|
state.pendingReceivers.forEach(receiver => receiver.reject(error));
|
|
124
118
|
state.pendingReceivers.clear();
|
|
125
119
|
state.queue.length = 0;
|
|
126
120
|
}
|
|
127
121
|
|
|
128
|
-
function removeDisconnectListener(deviceId: string) {
|
|
129
|
-
const tracked = disconnectListeners.get(deviceId);
|
|
130
|
-
if (!tracked) return;
|
|
131
|
-
tracked.peripheral.removeListener('disconnect', tracked.listener);
|
|
132
|
-
disconnectListeners.delete(deviceId);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function trackUnexpectedDisconnect(deviceId: string, peripheral: Peripheral) {
|
|
136
|
-
removeDisconnectListener(deviceId);
|
|
137
|
-
const listener = (reason: string) => {
|
|
138
|
-
removeDisconnectListener(deviceId);
|
|
139
|
-
if (connectedDevices.get(deviceId) !== peripheral) return;
|
|
140
|
-
|
|
141
|
-
deviceCharacteristics.get(deviceId)?.notify.removeAllListeners('data');
|
|
142
|
-
connectedDevices.delete(deviceId);
|
|
143
|
-
deviceCharacteristics.delete(deviceId);
|
|
144
|
-
clearNotificationState(
|
|
145
|
-
deviceId,
|
|
146
|
-
ERRORS.TypedError(
|
|
147
|
-
HardwareErrorCode.BleDeviceDisconnected,
|
|
148
|
-
reason || `BLE device disconnected: ${deviceId}`
|
|
149
|
-
)
|
|
150
|
-
);
|
|
151
|
-
};
|
|
152
|
-
disconnectListeners.set(deviceId, { peripheral, listener });
|
|
153
|
-
peripheral.on('disconnect', listener);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
122
|
function waitForNobleCleanup(registerCallback: (callback: () => void) => void) {
|
|
157
123
|
return new Promise<void>(resolve => {
|
|
158
124
|
let completed = false;
|
|
@@ -411,7 +377,6 @@ function writeCharacteristic(
|
|
|
411
377
|
async function disconnectDevice(uuid: string) {
|
|
412
378
|
const peripheral = connectedDevices.get(uuid);
|
|
413
379
|
const characteristics = deviceCharacteristics.get(uuid);
|
|
414
|
-
removeDisconnectListener(uuid);
|
|
415
380
|
clearNotificationState(uuid, `BLE device disconnected: ${uuid}`);
|
|
416
381
|
if (characteristics) {
|
|
417
382
|
characteristics.notify.removeAllListeners('data');
|
|
@@ -460,9 +425,7 @@ export function createNobleBlePlugin(): LowlevelTransportSharedPlugin {
|
|
|
460
425
|
await subscribeNotifications(uuid, notificationState.generation, characteristics.notify);
|
|
461
426
|
connectedDevices.set(uuid, peripheral);
|
|
462
427
|
deviceCharacteristics.set(uuid, characteristics);
|
|
463
|
-
trackUnexpectedDisconnect(uuid, peripheral);
|
|
464
428
|
} catch (error) {
|
|
465
|
-
removeDisconnectListener(uuid);
|
|
466
429
|
clearNotificationState(uuid, `BLE notification subscription failed: ${uuid}`);
|
|
467
430
|
if (characteristics) {
|
|
468
431
|
characteristics.notify.removeAllListeners('data');
|