@onekeyfe/hd-transport-electron 1.2.3-alpha.2 → 1.2.3-alpha.4
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/dist/{index-985e2bf3.js → index-474dbbae.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-263d4736.js → noble-ble-handler-23c86603.js} +5 -3
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/noble-ble-handler.test.ts +139 -3
- package/src/noble-ble-handler.ts +7 -4
|
@@ -55,13 +55,13 @@ function invokeNobleBleIpc(request) {
|
|
|
55
55
|
|
|
56
56
|
function initNobleBleSupport(webContents) {
|
|
57
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
58
|
+
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-23c86603.js'); });
|
|
59
59
|
setupNobleBleHandlers(webContents);
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
function disposeNobleBleSupport(releaseNoble) {
|
|
63
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
64
|
+
const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-23c86603.js'); });
|
|
65
65
|
yield handler.disposeNobleBleSupport(releaseNoble);
|
|
66
66
|
});
|
|
67
67
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-474dbbae.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -887,7 +887,6 @@ function enumerateDevices(isWindowDestroyed) {
|
|
|
887
887
|
return [];
|
|
888
888
|
const nobleInstance = noble;
|
|
889
889
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting device enumeration');
|
|
890
|
-
discoveredDevices.clear();
|
|
891
890
|
ensureDiscoverListener();
|
|
892
891
|
return new Promise((resolve, reject) => {
|
|
893
892
|
const devices = [];
|
|
@@ -1281,7 +1280,10 @@ function connectDevice(deviceId, webContents) {
|
|
|
1281
1280
|
totalDiscovered: discoveredDevices.size,
|
|
1282
1281
|
totalConnected: connectedDevices.size,
|
|
1283
1282
|
});
|
|
1284
|
-
let peripheral = (_a =
|
|
1283
|
+
let peripheral = (_a = connectedDevices.get(deviceId)) !== null && _a !== void 0 ? _a : discoveredDevices.get(deviceId);
|
|
1284
|
+
if ((peripheral === null || peripheral === void 0 ? void 0 : peripheral.state) !== 'connected') {
|
|
1285
|
+
peripheral = undefined;
|
|
1286
|
+
}
|
|
1285
1287
|
if (!peripheral) {
|
|
1286
1288
|
if (!noble) {
|
|
1287
1289
|
yield initializeNoble();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAiC1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAiB3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+KD,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAiC1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAiB3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+KD,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAqyDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkOpE;AAOD,wBAAgB,sBAAsB,CACpC,YAAY,GAAE,CAAC,QAAQ,EAAE;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,KAAK,IAAkC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAiEf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-electron",
|
|
3
|
-
"version": "1.2.3-alpha.
|
|
3
|
+
"version": "1.2.3-alpha.4",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"electron-log": ">=4.0.0"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-core": "1.2.3-alpha.
|
|
29
|
-
"@onekeyfe/hd-shared": "1.2.3-alpha.
|
|
30
|
-
"@onekeyfe/hd-transport": "1.2.3-alpha.
|
|
28
|
+
"@onekeyfe/hd-core": "1.2.3-alpha.4",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.3-alpha.4",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.3-alpha.4",
|
|
31
31
|
"@stoprocent/noble": "2.3.16",
|
|
32
32
|
"p-retry": "^4.6.2"
|
|
33
33
|
},
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"electron": "^25.0.0",
|
|
37
37
|
"typescript": "^5.3.3"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "705729baaec54b86a4fc28cce310a85b67b82730"
|
|
40
40
|
}
|
|
@@ -225,6 +225,133 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
225
225
|
]);
|
|
226
226
|
});
|
|
227
227
|
|
|
228
|
+
test.each(['Pro A1B2', 'Pro2 A1B2'])(
|
|
229
|
+
'retains %s across scan rounds until Bluetooth is powered off',
|
|
230
|
+
async name => {
|
|
231
|
+
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
232
|
+
|
|
233
|
+
const handlers = new Map<string, IpcHandler>();
|
|
234
|
+
const ipcMain = {
|
|
235
|
+
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
236
|
+
handlers.set(channel, handler);
|
|
237
|
+
}),
|
|
238
|
+
removeHandler: jest.fn((channel: string) => {
|
|
239
|
+
handlers.delete(channel);
|
|
240
|
+
}),
|
|
241
|
+
};
|
|
242
|
+
const noble = Object.assign(new EventEmitter(), {
|
|
243
|
+
state: 'poweredOn',
|
|
244
|
+
startScanning: jest.fn(),
|
|
245
|
+
stopScanning: jest.fn(callback => callback?.()),
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
jest.doMock('@stoprocent/noble', () => noble);
|
|
249
|
+
jest.doMock('electron', () => ({ ipcMain }));
|
|
250
|
+
jest.doMock('electron-log', () => ({
|
|
251
|
+
info: jest.fn(),
|
|
252
|
+
debug: jest.fn(),
|
|
253
|
+
error: jest.fn(),
|
|
254
|
+
}));
|
|
255
|
+
|
|
256
|
+
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
257
|
+
setupNobleBleHandlers({
|
|
258
|
+
on: jest.fn(),
|
|
259
|
+
send: jest.fn(),
|
|
260
|
+
} as unknown as WebContents);
|
|
261
|
+
|
|
262
|
+
const enumerate = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE);
|
|
263
|
+
if (!enumerate) {
|
|
264
|
+
throw new Error('Electron Noble BLE enumerate handler was not registered');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const scan = async (peripherals: ReturnType<typeof createPeripheral>[]) => {
|
|
268
|
+
let resolveScanStarted = () => undefined;
|
|
269
|
+
const scanStarted = new Promise<void>(resolve => {
|
|
270
|
+
resolveScanStarted = resolve;
|
|
271
|
+
});
|
|
272
|
+
noble.startScanning.mockImplementationOnce((_services, _duplicates, callback) => {
|
|
273
|
+
callback?.();
|
|
274
|
+
peripherals.forEach(peripheral => noble.emit('discover', peripheral));
|
|
275
|
+
resolveScanStarted();
|
|
276
|
+
});
|
|
277
|
+
const devices = Promise.resolve(enumerate());
|
|
278
|
+
await scanStarted;
|
|
279
|
+
jest.advanceTimersByTime(5_000);
|
|
280
|
+
return devices;
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const firstDevice = createPeripheral('first-device', name);
|
|
284
|
+
const secondDevice = createPeripheral('second-device', 'Pro2 C3D4');
|
|
285
|
+
await expect(scan([firstDevice])).resolves.toEqual([
|
|
286
|
+
expect.objectContaining({ id: 'first-device', name }),
|
|
287
|
+
]);
|
|
288
|
+
await expect(scan([secondDevice, secondDevice])).resolves.toEqual([
|
|
289
|
+
expect.objectContaining({ id: 'first-device', name }),
|
|
290
|
+
expect.objectContaining({ id: 'second-device', name: 'Pro2 C3D4' }),
|
|
291
|
+
]);
|
|
292
|
+
await expect(scan([])).resolves.toHaveLength(2);
|
|
293
|
+
|
|
294
|
+
noble.state = 'poweredOff';
|
|
295
|
+
noble.emit('stateChange', 'poweredOff');
|
|
296
|
+
noble.state = 'poweredOn';
|
|
297
|
+
noble.emit('stateChange', 'poweredOn');
|
|
298
|
+
await expect(scan([])).resolves.toEqual([]);
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
test.each(['Pro A1B2', 'Pro2 A1B2'])(
|
|
303
|
+
'refreshes a retained disconnected %s peripheral before cold connecting',
|
|
304
|
+
async name => {
|
|
305
|
+
const handlers = new Map<string, IpcHandler>();
|
|
306
|
+
const stalePeripheral = Object.assign(new EventEmitter(), createPeripheral('device', name), {
|
|
307
|
+
connect: jest.fn(),
|
|
308
|
+
});
|
|
309
|
+
const freshPeripheral = Object.assign(new EventEmitter(), createPeripheral('device', name), {
|
|
310
|
+
connect: jest.fn((callback: (error?: Error) => void) => {
|
|
311
|
+
callback(new Error('expected fresh connection failure'));
|
|
312
|
+
}),
|
|
313
|
+
});
|
|
314
|
+
const noble = Object.assign(new EventEmitter(), {
|
|
315
|
+
state: 'poweredOn',
|
|
316
|
+
startScanning: jest.fn((_services, _duplicates, callback) => {
|
|
317
|
+
callback?.();
|
|
318
|
+
noble.emit('discover', freshPeripheral);
|
|
319
|
+
}),
|
|
320
|
+
stopScanning: jest.fn(callback => callback?.()),
|
|
321
|
+
connectAsync: jest.fn(() => Promise.resolve(undefined)),
|
|
322
|
+
});
|
|
323
|
+
jest.doMock('@stoprocent/noble', () => noble);
|
|
324
|
+
jest.doMock('electron', () => ({
|
|
325
|
+
ipcMain: {
|
|
326
|
+
handle: (channel: string, handler: IpcHandler) => handlers.set(channel, handler),
|
|
327
|
+
removeHandler: (channel: string) => handlers.delete(channel),
|
|
328
|
+
},
|
|
329
|
+
}));
|
|
330
|
+
jest.doMock('electron-log', () => ({
|
|
331
|
+
info: jest.fn(),
|
|
332
|
+
debug: jest.fn(),
|
|
333
|
+
error: jest.fn(),
|
|
334
|
+
}));
|
|
335
|
+
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
336
|
+
setupNobleBleHandlers({ on: jest.fn(), send: jest.fn() } as unknown as WebContents);
|
|
337
|
+
const availability = handlers.get(EOneKeyBleMessageKeys.BLE_AVAILABILITY_CHECK);
|
|
338
|
+
const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
|
|
339
|
+
if (!availability || !connect) throw new Error('Noble handlers were not registered');
|
|
340
|
+
await availability();
|
|
341
|
+
noble.emit('discover', stalePeripheral);
|
|
342
|
+
|
|
343
|
+
await expect(Promise.resolve(connect(undefined, stalePeripheral.id))).resolves.toMatchObject({
|
|
344
|
+
success: false,
|
|
345
|
+
error: { message: 'expected fresh connection failure' },
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
expect(stalePeripheral.connect).not.toHaveBeenCalled();
|
|
349
|
+
expect(freshPeripheral.connect).toHaveBeenCalledTimes(1);
|
|
350
|
+
expect(noble.startScanning).toHaveBeenCalledTimes(1);
|
|
351
|
+
expect(noble.connectAsync).toHaveBeenCalledTimes(name.startsWith('Pro2') ? 1 : 0);
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
|
|
228
355
|
test('waits for a targeted scan to stop before connecting', async () => {
|
|
229
356
|
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
230
357
|
|
|
@@ -846,9 +973,12 @@ describe('Noble BLE process shutdown', () => {
|
|
|
846
973
|
discoverServices: jest.fn(),
|
|
847
974
|
});
|
|
848
975
|
native.emit('discover', peripheral);
|
|
976
|
+
native.startScanning.mockImplementationOnce((_uuids, _duplicates, callback) => {
|
|
977
|
+
callback?.();
|
|
978
|
+
native.emit('discover', peripheral);
|
|
979
|
+
});
|
|
849
980
|
const connecting = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT)?.({}, peripheral.id);
|
|
850
|
-
await
|
|
851
|
-
await Promise.resolve();
|
|
981
|
+
await flushCallbacks();
|
|
852
982
|
expect(peripheral.connect).toHaveBeenCalledTimes(1);
|
|
853
983
|
const disposing = sdk.disposeNobleBleSupport();
|
|
854
984
|
await flushCallbacks();
|
|
@@ -886,7 +1016,13 @@ describe('Noble BLE process shutdown', () => {
|
|
|
886
1016
|
);
|
|
887
1017
|
const cancelConnect = jest.fn();
|
|
888
1018
|
if (route === 'direct') Object.assign(native, { connectAsync, cancelConnect });
|
|
889
|
-
else
|
|
1019
|
+
else {
|
|
1020
|
+
native.emit('discover', peripheral);
|
|
1021
|
+
native.startScanning.mockImplementationOnce((_uuids, _duplicates, callback) => {
|
|
1022
|
+
callback?.();
|
|
1023
|
+
native.emit('discover', peripheral);
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
890
1026
|
const connecting = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT)?.({}, peripheral.id);
|
|
891
1027
|
await flushCallbacks();
|
|
892
1028
|
if (route === 'direct') {
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -1167,8 +1167,7 @@ async function enumerateDevices(isWindowDestroyed: () => boolean): Promise<Devic
|
|
|
1167
1167
|
|
|
1168
1168
|
logger?.info('[NobleBLE] Starting device enumeration');
|
|
1169
1169
|
|
|
1170
|
-
//
|
|
1171
|
-
discoveredDevices.clear();
|
|
1170
|
+
// Keep prior discoveries when a polling round misses an advertisement.
|
|
1172
1171
|
|
|
1173
1172
|
// Ensure discover listener is properly set up before scanning
|
|
1174
1173
|
// This is crucial to fix the issue where devices are not found after web-usb failures
|
|
@@ -1766,8 +1765,12 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
|
|
|
1766
1765
|
totalConnected: connectedDevices.size,
|
|
1767
1766
|
});
|
|
1768
1767
|
|
|
1769
|
-
//
|
|
1770
|
-
|
|
1768
|
+
// Retained discoveries are display metadata, not proof of a reusable native link.
|
|
1769
|
+
// Prefer the live connection when an older discovery exists for the same device.
|
|
1770
|
+
let peripheral = connectedDevices.get(deviceId) ?? discoveredDevices.get(deviceId);
|
|
1771
|
+
if (peripheral?.state !== 'connected') {
|
|
1772
|
+
peripheral = undefined;
|
|
1773
|
+
}
|
|
1771
1774
|
|
|
1772
1775
|
if (!peripheral) {
|
|
1773
1776
|
// Initialize Noble if not already done
|