@onekeyfe/hd-transport-electron 1.2.0-alpha.66 → 1.2.0-alpha.67
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-84fea839.js → index-5f728113.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-a0b2f06d.js → noble-ble-handler-d58af248.js} +34 -66
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/noble-ble-handler.ts +32 -74
- package/dist/noble-ble-timeouts.d.ts +0 -3
- package/dist/noble-ble-timeouts.d.ts.map +0 -1
- package/src/__tests__/noble-ble-handler.test.ts +0 -354
- package/src/noble-ble-timeouts.ts +0 -2
|
@@ -32,7 +32,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
32
32
|
|
|
33
33
|
function initNobleBleSupport(webContents) {
|
|
34
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
-
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
35
|
+
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-d58af248.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
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-5f728113.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -78,9 +78,6 @@ function softRefreshSubscription(params) {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5000;
|
|
82
|
-
const NOBLE_BLE_CONNECTION_TIMEOUT_MS = 10000;
|
|
83
|
-
|
|
84
81
|
let noble = null;
|
|
85
82
|
let logger = null;
|
|
86
83
|
const bluetoothState = {
|
|
@@ -103,8 +100,10 @@ const ONEKEY_SERVICE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.
|
|
|
103
100
|
const ONEKEY_WRITE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_WRITE_CHARACTERISTIC_UUID);
|
|
104
101
|
const ONEKEY_NOTIFY_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_NOTIFY_CHARACTERISTIC_UUID);
|
|
105
102
|
const BLUETOOTH_INIT_TIMEOUT = 10000;
|
|
106
|
-
const DEVICE_SCAN_TIMEOUT =
|
|
103
|
+
const DEVICE_SCAN_TIMEOUT = 8000;
|
|
104
|
+
const FAST_SCAN_TIMEOUT = 8000;
|
|
107
105
|
const DEVICE_CHECK_INTERVAL = 500;
|
|
106
|
+
const CONNECTION_TIMEOUT = 8000;
|
|
108
107
|
const SERVICE_DISCOVERY_TIMEOUT = 10000;
|
|
109
108
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
110
109
|
const BLE_PACKET_SIZE = 192;
|
|
@@ -117,14 +116,10 @@ const ABORTABLE_WRITE_ERROR_PATTERNS = [
|
|
|
117
116
|
function isOneKeyPeripheral(peripheral) {
|
|
118
117
|
var _a, _b;
|
|
119
118
|
const serviceUuids = (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.serviceUuids;
|
|
120
|
-
const localName = (_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName;
|
|
121
|
-
if (!(localName === null || localName === void 0 ? void 0 : localName.trim()) || hdShared.isPro2FindMyAdvertisementName(localName)) {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
119
|
return (hdShared.hasOnekeyCommunicationService(serviceUuids) &&
|
|
125
120
|
hdShared.isOnekeyBluetoothDevice({
|
|
126
121
|
id: peripheral.id,
|
|
127
|
-
localName,
|
|
122
|
+
localName: (_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName,
|
|
128
123
|
serviceUuids,
|
|
129
124
|
}));
|
|
130
125
|
}
|
|
@@ -514,14 +509,6 @@ function ensureDiscoverListener() {
|
|
|
514
509
|
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] Discover listener already registered');
|
|
515
510
|
}
|
|
516
511
|
}
|
|
517
|
-
function waitForNobleScanStop(nobleInstance) {
|
|
518
|
-
return index.__awaiter(this, void 0, void 0, function* () {
|
|
519
|
-
yield runBleCallbackOperation(callback => nobleInstance.stopScanning(() => callback()), {
|
|
520
|
-
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
521
|
-
timeoutBehavior: 'resolve',
|
|
522
|
-
});
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
512
|
function performTargetedScan(targetDeviceId) {
|
|
526
513
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
527
514
|
if (!noble) {
|
|
@@ -530,25 +517,6 @@ function performTargetedScan(targetDeviceId) {
|
|
|
530
517
|
const nobleInstance = noble;
|
|
531
518
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting targeted scan for device:', targetDeviceId);
|
|
532
519
|
return new Promise((resolve, reject) => {
|
|
533
|
-
let settled = false;
|
|
534
|
-
const finish = (peripheral, error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
535
|
-
if (settled)
|
|
536
|
-
return;
|
|
537
|
-
settled = true;
|
|
538
|
-
if (timeoutId)
|
|
539
|
-
clearTimeout(timeoutId);
|
|
540
|
-
nobleInstance.removeListener('discover', onDiscover);
|
|
541
|
-
yield waitForNobleScanStop(nobleInstance);
|
|
542
|
-
if (error) {
|
|
543
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start targeted scan:', error);
|
|
544
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, error.message));
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
if (peripheral) {
|
|
548
|
-
discoveredDevices.set(peripheral.id, peripheral);
|
|
549
|
-
}
|
|
550
|
-
resolve(peripheral);
|
|
551
|
-
});
|
|
552
520
|
const onDiscover = (peripheral) => {
|
|
553
521
|
var _a;
|
|
554
522
|
if (peripheral.id === targetDeviceId && isOneKeyPeripheral(peripheral)) {
|
|
@@ -556,17 +524,26 @@ function performTargetedScan(targetDeviceId) {
|
|
|
556
524
|
id: peripheral.id,
|
|
557
525
|
name: (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName,
|
|
558
526
|
});
|
|
559
|
-
|
|
527
|
+
clearTimeout(timeoutId);
|
|
528
|
+
nobleInstance.removeListener('discover', onDiscover);
|
|
529
|
+
nobleInstance.stopScanning();
|
|
530
|
+
discoveredDevices.set(peripheral.id, peripheral);
|
|
531
|
+
resolve(peripheral);
|
|
560
532
|
}
|
|
561
533
|
};
|
|
562
534
|
const timeoutId = setTimeout(() => {
|
|
535
|
+
nobleInstance.removeListener('discover', onDiscover);
|
|
536
|
+
nobleInstance.stopScanning();
|
|
563
537
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
|
|
564
|
-
|
|
565
|
-
},
|
|
538
|
+
resolve(null);
|
|
539
|
+
}, FAST_SCAN_TIMEOUT);
|
|
566
540
|
nobleInstance.on('discover', onDiscover);
|
|
567
541
|
nobleInstance.startScanning([], false, (error) => {
|
|
568
542
|
if (error) {
|
|
569
|
-
|
|
543
|
+
clearTimeout(timeoutId);
|
|
544
|
+
nobleInstance.removeListener('discover', onDiscover);
|
|
545
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start targeted scan:', error);
|
|
546
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, error.message));
|
|
570
547
|
return;
|
|
571
548
|
}
|
|
572
549
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan started for device:', targetDeviceId);
|
|
@@ -589,12 +566,12 @@ function enumerateDevices() {
|
|
|
589
566
|
return new Promise((resolve, reject) => {
|
|
590
567
|
const devices = [];
|
|
591
568
|
let intervalId;
|
|
592
|
-
const cleanup = () =>
|
|
569
|
+
const cleanup = () => {
|
|
593
570
|
clearTimeout(timeoutId);
|
|
594
571
|
if (intervalId)
|
|
595
572
|
clearInterval(intervalId);
|
|
596
|
-
|
|
597
|
-
}
|
|
573
|
+
nobleInstance.stopScanning();
|
|
574
|
+
};
|
|
598
575
|
const checkDevices = () => {
|
|
599
576
|
discoveredDevices.forEach((peripheral, id) => {
|
|
600
577
|
var _a;
|
|
@@ -610,23 +587,23 @@ function enumerateDevices() {
|
|
|
610
587
|
}
|
|
611
588
|
});
|
|
612
589
|
};
|
|
613
|
-
const timeoutId = setTimeout(() =>
|
|
590
|
+
const timeoutId = setTimeout(() => {
|
|
614
591
|
checkDevices();
|
|
615
|
-
|
|
592
|
+
cleanup();
|
|
616
593
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scan completed, found devices:', devices.length);
|
|
617
594
|
resolve(devices);
|
|
618
|
-
}
|
|
595
|
+
}, DEVICE_SCAN_TIMEOUT);
|
|
619
596
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning for OneKey BLE devices');
|
|
620
|
-
nobleInstance.startScanning([], false, (error) =>
|
|
597
|
+
nobleInstance.startScanning([], false, (error) => {
|
|
621
598
|
if (error) {
|
|
622
|
-
|
|
599
|
+
cleanup();
|
|
623
600
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start scanning:', error);
|
|
624
601
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, error.message));
|
|
625
602
|
return;
|
|
626
603
|
}
|
|
627
604
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning started for OneKey devices');
|
|
628
605
|
intervalId = setInterval(checkDevices, DEVICE_CHECK_INTERVAL);
|
|
629
|
-
})
|
|
606
|
+
});
|
|
630
607
|
});
|
|
631
608
|
});
|
|
632
609
|
}
|
|
@@ -635,7 +612,10 @@ function stopScanning() {
|
|
|
635
612
|
if (!noble)
|
|
636
613
|
return;
|
|
637
614
|
const nobleInstance = noble;
|
|
638
|
-
yield
|
|
615
|
+
yield runBleCallbackOperation(callback => nobleInstance.stopScanning(() => callback()), {
|
|
616
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
617
|
+
timeoutBehavior: 'resolve',
|
|
618
|
+
});
|
|
639
619
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning stopped');
|
|
640
620
|
});
|
|
641
621
|
}
|
|
@@ -790,7 +770,7 @@ function forceReconnectPeripheral(peripheral, deviceId) {
|
|
|
790
770
|
}), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
|
|
791
771
|
}
|
|
792
772
|
yield runBleCallbackOperation(callback => peripheral.connect(callback), {
|
|
793
|
-
timeoutMs:
|
|
773
|
+
timeoutMs: CONNECTION_TIMEOUT,
|
|
794
774
|
timeoutBehavior: 'reject',
|
|
795
775
|
});
|
|
796
776
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
|
|
@@ -960,24 +940,12 @@ function connectDevice(deviceId, webContents) {
|
|
|
960
940
|
return;
|
|
961
941
|
}
|
|
962
942
|
return new Promise((resolve, reject) => {
|
|
963
|
-
let connectionTimedOut = false;
|
|
964
943
|
const timeout = setTimeout(() => {
|
|
965
|
-
connectionTimedOut = true;
|
|
966
944
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'Connection timeout'));
|
|
967
|
-
},
|
|
945
|
+
}, CONNECTION_TIMEOUT);
|
|
968
946
|
const connectedPeripheral = peripheral;
|
|
969
947
|
connectedPeripheral.connect((error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
970
948
|
clearTimeout(timeout);
|
|
971
|
-
if (connectionTimedOut) {
|
|
972
|
-
if (!error) {
|
|
973
|
-
try {
|
|
974
|
-
connectedPeripheral.disconnect(() => undefined);
|
|
975
|
-
}
|
|
976
|
-
catch (_a) {
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
949
|
if (error) {
|
|
982
950
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection failed:', error);
|
|
983
951
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, error.message));
|
|
@@ -1096,7 +1064,7 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1096
1064
|
timeoutBehavior: 'resolve',
|
|
1097
1065
|
});
|
|
1098
1066
|
yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1099
|
-
timeoutMs:
|
|
1067
|
+
timeoutMs: CONNECTION_TIMEOUT,
|
|
1100
1068
|
timeoutBehavior: 'reject',
|
|
1101
1069
|
});
|
|
1102
1070
|
notifyCharacteristic.on('data', (data) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AA46ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAyJpE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-electron",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.67",
|
|
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.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
30
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.67",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.67",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.67",
|
|
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": "5fea66e8c65a1fab2ccc099b2811c8749b2487e0"
|
|
40
40
|
}
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
createKnownBleUuidAliases,
|
|
16
16
|
hasOnekeyCommunicationService,
|
|
17
17
|
isOnekeyBluetoothDevice,
|
|
18
|
-
isPro2FindMyAdvertisementName,
|
|
19
18
|
matchesKnownBleUuid,
|
|
20
19
|
wait,
|
|
21
20
|
} from '@onekeyfe/hd-shared';
|
|
@@ -23,10 +22,6 @@ import pRetry from 'p-retry';
|
|
|
23
22
|
|
|
24
23
|
import { safeLog } from './types/noble-extended';
|
|
25
24
|
import { runBleCallbackOperation, softRefreshSubscription } from './ble-ops';
|
|
26
|
-
import {
|
|
27
|
-
NOBLE_BLE_CONNECTION_TIMEOUT_MS,
|
|
28
|
-
NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS,
|
|
29
|
-
} from './noble-ble-timeouts';
|
|
30
25
|
|
|
31
26
|
import type { IpcMainInvokeEvent, WebContents } from 'electron';
|
|
32
27
|
import type { Characteristic, Peripheral, Service } from '@stoprocent/noble';
|
|
@@ -80,8 +75,10 @@ const ONEKEY_NOTIFY_UUID_ALIASES = createKnownBleUuidAliases(ONEKEY_NOTIFY_CHARA
|
|
|
80
75
|
|
|
81
76
|
// Timeout and interval constants
|
|
82
77
|
const BLUETOOTH_INIT_TIMEOUT = 10000; // 10 seconds for Bluetooth initialization
|
|
83
|
-
const DEVICE_SCAN_TIMEOUT =
|
|
78
|
+
const DEVICE_SCAN_TIMEOUT = 8000; // 8 seconds for device scanning (Pro2 has longer advertising interval)
|
|
79
|
+
const FAST_SCAN_TIMEOUT = 8000; // 8 seconds for targeted scanning (Pro2 has longer advertising interval)
|
|
84
80
|
const DEVICE_CHECK_INTERVAL = 500; // 500ms interval for periodic device checks
|
|
81
|
+
const CONNECTION_TIMEOUT = 8000; // 8 seconds for device connection (BLE reconnect after release can be slow)
|
|
85
82
|
const SERVICE_DISCOVERY_TIMEOUT = 10000; // 10 seconds for service discovery
|
|
86
83
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
87
84
|
|
|
@@ -96,19 +93,11 @@ const ABORTABLE_WRITE_ERROR_PATTERNS = [
|
|
|
96
93
|
|
|
97
94
|
function isOneKeyPeripheral(peripheral: Peripheral) {
|
|
98
95
|
const serviceUuids = peripheral.advertisement?.serviceUuids;
|
|
99
|
-
const localName = peripheral.advertisement?.localName;
|
|
100
|
-
|
|
101
|
-
// Noble localName is the current advertisement name, so reject the Pro2
|
|
102
|
-
// Find My endpoint before the communication-service fast path accepts it.
|
|
103
|
-
if (!localName?.trim() || isPro2FindMyAdvertisementName(localName)) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
96
|
return (
|
|
108
97
|
hasOnekeyCommunicationService(serviceUuids) &&
|
|
109
98
|
isOnekeyBluetoothDevice({
|
|
110
99
|
id: peripheral.id,
|
|
111
|
-
localName,
|
|
100
|
+
localName: peripheral.advertisement?.localName,
|
|
112
101
|
serviceUuids,
|
|
113
102
|
})
|
|
114
103
|
);
|
|
@@ -652,13 +641,6 @@ function ensureDiscoverListener(): void {
|
|
|
652
641
|
}
|
|
653
642
|
}
|
|
654
643
|
|
|
655
|
-
async function waitForNobleScanStop(nobleInstance: NobleModule): Promise<void> {
|
|
656
|
-
await runBleCallbackOperation(callback => nobleInstance.stopScanning(() => callback()), {
|
|
657
|
-
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
658
|
-
timeoutBehavior: 'resolve',
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
|
|
662
644
|
// Perform targeted scan for a specific device ID
|
|
663
645
|
// Uses self-contained local listener pattern - no global state needed
|
|
664
646
|
async function performTargetedScan(targetDeviceId: string): Promise<Peripheral | null> {
|
|
@@ -672,26 +654,6 @@ async function performTargetedScan(targetDeviceId: string): Promise<Peripheral |
|
|
|
672
654
|
logger?.info('[NobleBLE] Starting targeted scan for device:', targetDeviceId);
|
|
673
655
|
|
|
674
656
|
return new Promise((resolve, reject) => {
|
|
675
|
-
let settled = false;
|
|
676
|
-
|
|
677
|
-
const finish = async (peripheral: Peripheral | null, error?: Error) => {
|
|
678
|
-
if (settled) return;
|
|
679
|
-
settled = true;
|
|
680
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
681
|
-
nobleInstance.removeListener('discover', onDiscover);
|
|
682
|
-
await waitForNobleScanStop(nobleInstance);
|
|
683
|
-
|
|
684
|
-
if (error) {
|
|
685
|
-
logger?.error('[NobleBLE] Failed to start targeted scan:', error);
|
|
686
|
-
reject(ERRORS.TypedError(HardwareErrorCode.BleScanError, error.message));
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
if (peripheral) {
|
|
690
|
-
discoveredDevices.set(peripheral.id, peripheral);
|
|
691
|
-
}
|
|
692
|
-
resolve(peripheral);
|
|
693
|
-
};
|
|
694
|
-
|
|
695
657
|
// Local discover listener - only matches target device
|
|
696
658
|
const onDiscover = (peripheral: Peripheral) => {
|
|
697
659
|
if (peripheral.id === targetDeviceId && isOneKeyPeripheral(peripheral)) {
|
|
@@ -699,14 +661,21 @@ async function performTargetedScan(targetDeviceId: string): Promise<Peripheral |
|
|
|
699
661
|
id: peripheral.id,
|
|
700
662
|
name: peripheral.advertisement?.localName,
|
|
701
663
|
});
|
|
702
|
-
|
|
664
|
+
clearTimeout(timeoutId);
|
|
665
|
+
nobleInstance.removeListener('discover', onDiscover);
|
|
666
|
+
nobleInstance.stopScanning();
|
|
667
|
+
discoveredDevices.set(peripheral.id, peripheral);
|
|
668
|
+
resolve(peripheral);
|
|
703
669
|
}
|
|
704
670
|
};
|
|
705
671
|
|
|
672
|
+
// Timeout handler - must be after onDiscover so it can reference it
|
|
706
673
|
const timeoutId = setTimeout(() => {
|
|
674
|
+
nobleInstance.removeListener('discover', onDiscover);
|
|
675
|
+
nobleInstance.stopScanning();
|
|
707
676
|
logger?.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
|
|
708
|
-
|
|
709
|
-
},
|
|
677
|
+
resolve(null);
|
|
678
|
+
}, FAST_SCAN_TIMEOUT);
|
|
710
679
|
|
|
711
680
|
// Add local listener for this scan
|
|
712
681
|
nobleInstance.on('discover', onDiscover);
|
|
@@ -714,7 +683,10 @@ async function performTargetedScan(targetDeviceId: string): Promise<Peripheral |
|
|
|
714
683
|
// Start scanning — no service UUID filter (Pro2 may use different service UUID)
|
|
715
684
|
nobleInstance.startScanning([], false, (error?: Error) => {
|
|
716
685
|
if (error) {
|
|
717
|
-
|
|
686
|
+
clearTimeout(timeoutId);
|
|
687
|
+
nobleInstance.removeListener('discover', onDiscover);
|
|
688
|
+
logger?.error('[NobleBLE] Failed to start targeted scan:', error);
|
|
689
|
+
reject(ERRORS.TypedError(HardwareErrorCode.BleScanError, error.message));
|
|
718
690
|
return;
|
|
719
691
|
}
|
|
720
692
|
logger?.info('[NobleBLE] Targeted scan started for device:', targetDeviceId);
|
|
@@ -748,13 +720,11 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
748
720
|
const devices: DeviceInfo[] = [];
|
|
749
721
|
let intervalId: ReturnType<typeof setInterval> | undefined;
|
|
750
722
|
|
|
751
|
-
// Cleanup function: clears
|
|
752
|
-
|
|
753
|
-
// an immediately-following connection attempt.
|
|
754
|
-
const cleanup = async () => {
|
|
723
|
+
// Cleanup function: clears both timeout and interval
|
|
724
|
+
const cleanup = () => {
|
|
755
725
|
clearTimeout(timeoutId);
|
|
756
726
|
if (intervalId) clearInterval(intervalId);
|
|
757
|
-
|
|
727
|
+
nobleInstance.stopScanning();
|
|
758
728
|
};
|
|
759
729
|
|
|
760
730
|
// Collect discovered devices into the devices array
|
|
@@ -774,10 +744,10 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
774
744
|
};
|
|
775
745
|
|
|
776
746
|
// Set timeout for scanning — use longer timeout to catch slow-advertising devices like Pro2
|
|
777
|
-
const timeoutId = setTimeout(
|
|
747
|
+
const timeoutId = setTimeout(() => {
|
|
778
748
|
// Final collection before resolving — catches devices discovered near the deadline
|
|
779
749
|
checkDevices();
|
|
780
|
-
|
|
750
|
+
cleanup();
|
|
781
751
|
logger?.info('[NobleBLE] Scan completed, found devices:', devices.length);
|
|
782
752
|
resolve(devices);
|
|
783
753
|
}, DEVICE_SCAN_TIMEOUT);
|
|
@@ -785,9 +755,9 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
785
755
|
// Start scanning without a service UUID filter so Pro2 advertisements with
|
|
786
756
|
// short vendor UUIDs can be found, but only OneKey candidates are logged/returned.
|
|
787
757
|
logger?.info('[NobleBLE] Scanning for OneKey BLE devices');
|
|
788
|
-
nobleInstance.startScanning([], false,
|
|
758
|
+
nobleInstance.startScanning([], false, (error?: Error) => {
|
|
789
759
|
if (error) {
|
|
790
|
-
|
|
760
|
+
cleanup();
|
|
791
761
|
logger?.error('[NobleBLE] Failed to start scanning:', error);
|
|
792
762
|
reject(ERRORS.TypedError(HardwareErrorCode.BleScanError, error.message));
|
|
793
763
|
return;
|
|
@@ -805,7 +775,10 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
805
775
|
async function stopScanning(): Promise<void> {
|
|
806
776
|
if (!noble) return;
|
|
807
777
|
const nobleInstance = noble;
|
|
808
|
-
await
|
|
778
|
+
await runBleCallbackOperation(callback => nobleInstance.stopScanning(() => callback()), {
|
|
779
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
780
|
+
timeoutBehavior: 'resolve',
|
|
781
|
+
});
|
|
809
782
|
logger?.info('[NobleBLE] Scanning stopped');
|
|
810
783
|
}
|
|
811
784
|
|
|
@@ -1023,7 +996,7 @@ async function forceReconnectPeripheral(peripheral: Peripheral, deviceId: string
|
|
|
1023
996
|
|
|
1024
997
|
// Step 3: Re-establish connection
|
|
1025
998
|
await runBleCallbackOperation(callback => peripheral.connect(callback), {
|
|
1026
|
-
timeoutMs:
|
|
999
|
+
timeoutMs: CONNECTION_TIMEOUT,
|
|
1027
1000
|
timeoutBehavior: 'reject',
|
|
1028
1001
|
});
|
|
1029
1002
|
logger?.info('[NobleBLE] Force reconnect successful');
|
|
@@ -1295,30 +1268,15 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
|
|
|
1295
1268
|
}
|
|
1296
1269
|
|
|
1297
1270
|
return new Promise((resolve, reject) => {
|
|
1298
|
-
let connectionTimedOut = false;
|
|
1299
1271
|
const timeout = setTimeout(() => {
|
|
1300
|
-
connectionTimedOut = true;
|
|
1301
1272
|
reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, 'Connection timeout'));
|
|
1302
|
-
},
|
|
1273
|
+
}, CONNECTION_TIMEOUT);
|
|
1303
1274
|
|
|
1304
1275
|
// TypeScript type assertion - peripheral is guaranteed to be defined at this point
|
|
1305
1276
|
const connectedPeripheral = peripheral as Peripheral;
|
|
1306
1277
|
connectedPeripheral.connect(async (error: Error | undefined) => {
|
|
1307
1278
|
clearTimeout(timeout);
|
|
1308
1279
|
|
|
1309
|
-
// Noble may invoke the callback after the SDK timed out and released the request.
|
|
1310
|
-
// Ignore it to avoid initializing disposed commands or leaving an orphaned connection.
|
|
1311
|
-
if (connectionTimedOut) {
|
|
1312
|
-
if (!error) {
|
|
1313
|
-
try {
|
|
1314
|
-
connectedPeripheral.disconnect(() => undefined);
|
|
1315
|
-
} catch {
|
|
1316
|
-
// Best-effort cleanup only.
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
return;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
1280
|
if (error) {
|
|
1323
1281
|
logger?.error('[NobleBLE] Connection failed:', error);
|
|
1324
1282
|
reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, error.message));
|
|
@@ -1492,7 +1450,7 @@ async function subscribeNotifications(
|
|
|
1492
1450
|
timeoutBehavior: 'resolve',
|
|
1493
1451
|
});
|
|
1494
1452
|
await runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1495
|
-
timeoutMs:
|
|
1453
|
+
timeoutMs: CONNECTION_TIMEOUT,
|
|
1496
1454
|
timeoutBehavior: 'reject',
|
|
1497
1455
|
});
|
|
1498
1456
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM,+BAA+B,QAAS,CAAC"}
|
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import { EOneKeyBleMessageKeys } from '@onekeyfe/hd-shared';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
NOBLE_BLE_CONNECTION_TIMEOUT_MS,
|
|
6
|
-
NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS,
|
|
7
|
-
} from '../noble-ble-timeouts';
|
|
8
|
-
|
|
9
|
-
import type { WebContents } from 'electron';
|
|
10
|
-
|
|
11
|
-
type IpcHandler = (...args: unknown[]) => Promise<unknown> | unknown;
|
|
12
|
-
|
|
13
|
-
const createPeripheral = (id: string, localName?: string) => ({
|
|
14
|
-
id,
|
|
15
|
-
state: 'disconnected',
|
|
16
|
-
advertisement: {
|
|
17
|
-
localName,
|
|
18
|
-
serviceUuids: ['0001', 'fffd'],
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
describe('Electron Noble BLE device discovery', () => {
|
|
23
|
-
afterEach(() => {
|
|
24
|
-
jest.useRealTimers();
|
|
25
|
-
jest.resetModules();
|
|
26
|
-
jest.clearAllMocks();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('allows enough time for a slow targeted scan and connection', () => {
|
|
30
|
-
expect(NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS).toBe(5_000);
|
|
31
|
-
expect(NOBLE_BLE_CONNECTION_TIMEOUT_MS).toBe(10_000);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test('waits for Noble to stop scanning before enumeration resolves', async () => {
|
|
35
|
-
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
36
|
-
|
|
37
|
-
const handlers = new Map<string, IpcHandler>();
|
|
38
|
-
const ipcMain = {
|
|
39
|
-
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
40
|
-
handlers.set(channel, handler);
|
|
41
|
-
}),
|
|
42
|
-
};
|
|
43
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
44
|
-
state: string;
|
|
45
|
-
startScanning: jest.Mock;
|
|
46
|
-
stopScanning: jest.Mock;
|
|
47
|
-
};
|
|
48
|
-
let resolveScanStarted = () => undefined;
|
|
49
|
-
const scanStarted = new Promise<void>(resolve => {
|
|
50
|
-
resolveScanStarted = resolve;
|
|
51
|
-
});
|
|
52
|
-
let stopScanningCallback: (() => void) | undefined;
|
|
53
|
-
noble.state = 'poweredOn';
|
|
54
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
55
|
-
callback?.();
|
|
56
|
-
noble.emit('discover', createPeripheral('onekey-device', 'Pro2 A1B2'));
|
|
57
|
-
resolveScanStarted();
|
|
58
|
-
});
|
|
59
|
-
noble.stopScanning = jest.fn(callback => {
|
|
60
|
-
stopScanningCallback = callback;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
64
|
-
jest.doMock('electron', () => ({ ipcMain }));
|
|
65
|
-
jest.doMock('electron-log', () => ({
|
|
66
|
-
info: jest.fn(),
|
|
67
|
-
debug: jest.fn(),
|
|
68
|
-
error: jest.fn(),
|
|
69
|
-
}));
|
|
70
|
-
|
|
71
|
-
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
72
|
-
setupNobleBleHandlers({
|
|
73
|
-
on: jest.fn(),
|
|
74
|
-
send: jest.fn(),
|
|
75
|
-
} as unknown as WebContents);
|
|
76
|
-
|
|
77
|
-
const enumerate = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE);
|
|
78
|
-
if (!enumerate) {
|
|
79
|
-
throw new Error('Electron Noble BLE enumerate handler was not registered');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let enumerationResolved = false;
|
|
83
|
-
const devicesPromise = Promise.resolve(enumerate()).then(devices => {
|
|
84
|
-
enumerationResolved = true;
|
|
85
|
-
return devices;
|
|
86
|
-
});
|
|
87
|
-
await scanStarted;
|
|
88
|
-
jest.advanceTimersByTime(5_000);
|
|
89
|
-
await Promise.resolve();
|
|
90
|
-
|
|
91
|
-
expect(noble.stopScanning).toHaveBeenCalledTimes(1);
|
|
92
|
-
expect(enumerationResolved).toBe(false);
|
|
93
|
-
|
|
94
|
-
stopScanningCallback?.();
|
|
95
|
-
await expect(devicesPromise).resolves.toEqual([
|
|
96
|
-
expect.objectContaining({ id: 'onekey-device' }),
|
|
97
|
-
]);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('waits for a targeted scan to stop before connecting', async () => {
|
|
101
|
-
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
102
|
-
|
|
103
|
-
const handlers = new Map<string, IpcHandler>();
|
|
104
|
-
const ipcMain = {
|
|
105
|
-
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
106
|
-
handlers.set(channel, handler);
|
|
107
|
-
}),
|
|
108
|
-
};
|
|
109
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
110
|
-
state: string;
|
|
111
|
-
startScanning: jest.Mock;
|
|
112
|
-
stopScanning: jest.Mock;
|
|
113
|
-
};
|
|
114
|
-
let resolveScanStarted = () => undefined;
|
|
115
|
-
const scanStarted = new Promise<void>(resolve => {
|
|
116
|
-
resolveScanStarted = resolve;
|
|
117
|
-
});
|
|
118
|
-
let stopScanningCallback: (() => void) | undefined;
|
|
119
|
-
const peripheral = Object.assign(
|
|
120
|
-
new EventEmitter(),
|
|
121
|
-
createPeripheral('target-device', 'Pro2 A1B2'),
|
|
122
|
-
{
|
|
123
|
-
connect: jest.fn((callback: (error?: Error) => void) => {
|
|
124
|
-
callback(new Error('expected test connection failure'));
|
|
125
|
-
}),
|
|
126
|
-
}
|
|
127
|
-
);
|
|
128
|
-
noble.state = 'poweredOn';
|
|
129
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
130
|
-
callback?.();
|
|
131
|
-
noble.emit('discover', peripheral);
|
|
132
|
-
resolveScanStarted();
|
|
133
|
-
});
|
|
134
|
-
noble.stopScanning = jest.fn(callback => {
|
|
135
|
-
stopScanningCallback = callback;
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
139
|
-
jest.doMock('electron', () => ({ ipcMain }));
|
|
140
|
-
jest.doMock('electron-log', () => ({
|
|
141
|
-
info: jest.fn(),
|
|
142
|
-
debug: jest.fn(),
|
|
143
|
-
error: jest.fn(),
|
|
144
|
-
}));
|
|
145
|
-
|
|
146
|
-
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
147
|
-
setupNobleBleHandlers({
|
|
148
|
-
on: jest.fn(),
|
|
149
|
-
send: jest.fn(),
|
|
150
|
-
} as unknown as WebContents);
|
|
151
|
-
|
|
152
|
-
const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
|
|
153
|
-
if (!connect) {
|
|
154
|
-
throw new Error('Electron Noble BLE connect handler was not registered');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const connectPromise = Promise.resolve(connect(undefined, 'target-device'));
|
|
158
|
-
await scanStarted;
|
|
159
|
-
|
|
160
|
-
expect(noble.stopScanning).toHaveBeenCalledTimes(1);
|
|
161
|
-
expect(peripheral.connect).not.toHaveBeenCalled();
|
|
162
|
-
|
|
163
|
-
stopScanningCallback?.();
|
|
164
|
-
await expect(connectPromise).rejects.toThrow('expected test connection failure');
|
|
165
|
-
expect(peripheral.connect).toHaveBeenCalledTimes(1);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test('disconnects a connection callback that arrives after timeout', async () => {
|
|
169
|
-
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
170
|
-
|
|
171
|
-
const handlers = new Map<string, IpcHandler>();
|
|
172
|
-
const ipcMain = {
|
|
173
|
-
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
174
|
-
handlers.set(channel, handler);
|
|
175
|
-
}),
|
|
176
|
-
};
|
|
177
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
178
|
-
state: string;
|
|
179
|
-
startScanning: jest.Mock;
|
|
180
|
-
stopScanning: jest.Mock;
|
|
181
|
-
};
|
|
182
|
-
let connectCallback: ((error?: Error) => void) | undefined;
|
|
183
|
-
let resolveConnectStarted = () => undefined;
|
|
184
|
-
const connectStarted = new Promise<void>(resolve => {
|
|
185
|
-
resolveConnectStarted = resolve;
|
|
186
|
-
});
|
|
187
|
-
const peripheral = Object.assign(
|
|
188
|
-
new EventEmitter(),
|
|
189
|
-
createPeripheral('slow-device', 'Pro2 A1B2'),
|
|
190
|
-
{
|
|
191
|
-
connect: jest.fn((callback: (error?: Error) => void) => {
|
|
192
|
-
connectCallback = callback;
|
|
193
|
-
resolveConnectStarted();
|
|
194
|
-
}),
|
|
195
|
-
disconnect: jest.fn((callback: () => void) => callback()),
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
noble.state = 'poweredOn';
|
|
199
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
200
|
-
callback?.();
|
|
201
|
-
noble.emit('discover', peripheral);
|
|
202
|
-
});
|
|
203
|
-
noble.stopScanning = jest.fn(callback => callback?.());
|
|
204
|
-
|
|
205
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
206
|
-
jest.doMock('electron', () => ({ ipcMain }));
|
|
207
|
-
jest.doMock('electron-log', () => ({
|
|
208
|
-
info: jest.fn(),
|
|
209
|
-
debug: jest.fn(),
|
|
210
|
-
error: jest.fn(),
|
|
211
|
-
}));
|
|
212
|
-
|
|
213
|
-
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
214
|
-
setupNobleBleHandlers({
|
|
215
|
-
on: jest.fn(),
|
|
216
|
-
send: jest.fn(),
|
|
217
|
-
} as unknown as WebContents);
|
|
218
|
-
|
|
219
|
-
const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
|
|
220
|
-
if (!connect) {
|
|
221
|
-
throw new Error('Electron Noble BLE connect handler was not registered');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const connectPromise = Promise.resolve(connect(undefined, 'slow-device'));
|
|
225
|
-
await connectStarted;
|
|
226
|
-
expect(peripheral.connect).toHaveBeenCalledTimes(1);
|
|
227
|
-
|
|
228
|
-
jest.advanceTimersByTime(NOBLE_BLE_CONNECTION_TIMEOUT_MS);
|
|
229
|
-
await expect(connectPromise).rejects.toThrow('Connection timeout');
|
|
230
|
-
|
|
231
|
-
connectCallback?.();
|
|
232
|
-
await Promise.resolve();
|
|
233
|
-
expect(peripheral.disconnect).toHaveBeenCalledTimes(1);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test('does not enumerate a Pro2 Find My advertisement with the communication service', async () => {
|
|
237
|
-
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
238
|
-
|
|
239
|
-
const handlers = new Map<string, IpcHandler>();
|
|
240
|
-
const ipcMain = {
|
|
241
|
-
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
242
|
-
handlers.set(channel, handler);
|
|
243
|
-
}),
|
|
244
|
-
};
|
|
245
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
246
|
-
state: string;
|
|
247
|
-
startScanning: jest.Mock;
|
|
248
|
-
stopScanning: jest.Mock;
|
|
249
|
-
};
|
|
250
|
-
let resolveScanStarted = () => undefined;
|
|
251
|
-
const scanStarted = new Promise<void>(resolve => {
|
|
252
|
-
resolveScanStarted = resolve;
|
|
253
|
-
});
|
|
254
|
-
noble.state = 'poweredOn';
|
|
255
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
256
|
-
callback?.();
|
|
257
|
-
noble.emit('discover', createPeripheral('find-my-device', 'Pro2 A1B2 - Find My'));
|
|
258
|
-
noble.emit('discover', createPeripheral('onekey-device', 'Pro2 A1B2'));
|
|
259
|
-
resolveScanStarted();
|
|
260
|
-
});
|
|
261
|
-
noble.stopScanning = jest.fn(callback => callback?.());
|
|
262
|
-
|
|
263
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
264
|
-
jest.doMock('electron', () => ({ ipcMain }));
|
|
265
|
-
jest.doMock('electron-log', () => ({
|
|
266
|
-
info: jest.fn(),
|
|
267
|
-
debug: jest.fn(),
|
|
268
|
-
error: jest.fn(),
|
|
269
|
-
}));
|
|
270
|
-
|
|
271
|
-
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
272
|
-
setupNobleBleHandlers({
|
|
273
|
-
on: jest.fn(),
|
|
274
|
-
send: jest.fn(),
|
|
275
|
-
} as unknown as WebContents);
|
|
276
|
-
|
|
277
|
-
const enumerate = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE);
|
|
278
|
-
if (!enumerate) {
|
|
279
|
-
throw new Error('Electron Noble BLE enumerate handler was not registered');
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const devicesPromise = Promise.resolve(enumerate());
|
|
283
|
-
await scanStarted;
|
|
284
|
-
jest.advanceTimersByTime(5000);
|
|
285
|
-
|
|
286
|
-
await expect(devicesPromise).resolves.toEqual([
|
|
287
|
-
expect.objectContaining({
|
|
288
|
-
id: 'onekey-device',
|
|
289
|
-
name: 'Pro2 A1B2',
|
|
290
|
-
}),
|
|
291
|
-
]);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
test('does not enumerate a Find My peripheral first discovered without a name', async () => {
|
|
295
|
-
jest.useFakeTimers({ doNotFake: ['performance'] });
|
|
296
|
-
|
|
297
|
-
const handlers = new Map<string, IpcHandler>();
|
|
298
|
-
const ipcMain = {
|
|
299
|
-
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
300
|
-
handlers.set(channel, handler);
|
|
301
|
-
}),
|
|
302
|
-
};
|
|
303
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
304
|
-
state: string;
|
|
305
|
-
startScanning: jest.Mock;
|
|
306
|
-
stopScanning: jest.Mock;
|
|
307
|
-
};
|
|
308
|
-
let resolveScanStarted = () => undefined;
|
|
309
|
-
const scanStarted = new Promise<void>(resolve => {
|
|
310
|
-
resolveScanStarted = resolve;
|
|
311
|
-
});
|
|
312
|
-
const findMyPeripheral = createPeripheral('find-my-device');
|
|
313
|
-
noble.state = 'poweredOn';
|
|
314
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
315
|
-
callback?.();
|
|
316
|
-
noble.emit('discover', findMyPeripheral);
|
|
317
|
-
findMyPeripheral.advertisement.localName = 'Pro2 A1B2 - Find My';
|
|
318
|
-
noble.emit('discover', findMyPeripheral);
|
|
319
|
-
noble.emit('discover', createPeripheral('onekey-device', 'Pro2 A1B2'));
|
|
320
|
-
resolveScanStarted();
|
|
321
|
-
});
|
|
322
|
-
noble.stopScanning = jest.fn(callback => callback?.());
|
|
323
|
-
|
|
324
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
325
|
-
jest.doMock('electron', () => ({ ipcMain }));
|
|
326
|
-
jest.doMock('electron-log', () => ({
|
|
327
|
-
info: jest.fn(),
|
|
328
|
-
debug: jest.fn(),
|
|
329
|
-
error: jest.fn(),
|
|
330
|
-
}));
|
|
331
|
-
|
|
332
|
-
const { setupNobleBleHandlers } = await import('../noble-ble-handler');
|
|
333
|
-
setupNobleBleHandlers({
|
|
334
|
-
on: jest.fn(),
|
|
335
|
-
send: jest.fn(),
|
|
336
|
-
} as unknown as WebContents);
|
|
337
|
-
|
|
338
|
-
const enumerate = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE);
|
|
339
|
-
if (!enumerate) {
|
|
340
|
-
throw new Error('Electron Noble BLE enumerate handler was not registered');
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const devicesPromise = Promise.resolve(enumerate());
|
|
344
|
-
await scanStarted;
|
|
345
|
-
jest.advanceTimersByTime(5000);
|
|
346
|
-
|
|
347
|
-
await expect(devicesPromise).resolves.toEqual([
|
|
348
|
-
expect.objectContaining({
|
|
349
|
-
id: 'onekey-device',
|
|
350
|
-
name: 'Pro2 A1B2',
|
|
351
|
-
}),
|
|
352
|
-
]);
|
|
353
|
-
});
|
|
354
|
-
});
|