@onekeyfe/hd-transport-electron 1.2.0-alpha.7 → 1.2.0-alpha.70
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/ble-ops.d.ts +6 -0
- package/dist/ble-ops.d.ts.map +1 -1
- package/dist/{index-02fc07fe.js → index-84fea839.js} +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-94c42077.js → noble-ble-handler-a0b2f06d.js} +232 -204
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/dist/noble-ble-timeouts.d.ts +3 -0
- package/dist/noble-ble-timeouts.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/__tests__/ble-ops.test.ts +21 -0
- package/src/__tests__/noble-ble-handler.test.ts +354 -0
- package/src/ble-ops.ts +40 -10
- package/src/noble-ble-handler.ts +224 -235
- package/src/noble-ble-timeouts.ts +2 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-84fea839.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -17,6 +17,37 @@ function safeLog(logger, level, message, ...args) {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function runBleCallbackOperation(operation, options) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
let settled = false;
|
|
23
|
+
const settle = (error) => {
|
|
24
|
+
if (settled)
|
|
25
|
+
return;
|
|
26
|
+
settled = true;
|
|
27
|
+
clearTimeout(timeout);
|
|
28
|
+
if (error) {
|
|
29
|
+
reject(error);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
resolve();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const timeout = setTimeout(() => {
|
|
36
|
+
if (options.timeoutBehavior === 'reject') {
|
|
37
|
+
settle(new Error(`BLE operation timed out after ${options.timeoutMs}ms`));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
settle();
|
|
41
|
+
}
|
|
42
|
+
}, options.timeoutMs);
|
|
43
|
+
try {
|
|
44
|
+
operation(settle);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
settle(error instanceof Error ? error : new Error(String(error)));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
20
51
|
function softRefreshSubscription(params) {
|
|
21
52
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
22
53
|
const { deviceId, notifyCharacteristic, subscriptionOperations, subscribedDevices, pairedDevices, onNotificationData, logger, } = params;
|
|
@@ -25,17 +56,13 @@ function softRefreshSubscription(params) {
|
|
|
25
56
|
}
|
|
26
57
|
logger === null || logger === void 0 ? void 0 : logger.info('[BLE-OPS] Starting subscription refresh', { deviceId });
|
|
27
58
|
subscriptionOperations.set(deviceId, 'subscribing');
|
|
28
|
-
yield
|
|
29
|
-
|
|
59
|
+
yield runBleCallbackOperation(callback => notifyCharacteristic.unsubscribe(callback), {
|
|
60
|
+
timeoutMs: 250,
|
|
61
|
+
timeoutBehavior: 'resolve',
|
|
30
62
|
});
|
|
31
|
-
yield
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
reject(error);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
resolve();
|
|
38
|
-
});
|
|
63
|
+
yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
64
|
+
timeoutMs: 8000,
|
|
65
|
+
timeoutBehavior: 'reject',
|
|
39
66
|
});
|
|
40
67
|
notifyCharacteristic.removeAllListeners('data');
|
|
41
68
|
notifyCharacteristic.on('data', (data) => {
|
|
@@ -51,6 +78,9 @@ function softRefreshSubscription(params) {
|
|
|
51
78
|
});
|
|
52
79
|
}
|
|
53
80
|
|
|
81
|
+
const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5000;
|
|
82
|
+
const NOBLE_BLE_CONNECTION_TIMEOUT_MS = 10000;
|
|
83
|
+
|
|
54
84
|
let noble = null;
|
|
55
85
|
let logger = null;
|
|
56
86
|
const bluetoothState = {
|
|
@@ -59,6 +89,7 @@ const bluetoothState = {
|
|
|
59
89
|
initialized: false,
|
|
60
90
|
};
|
|
61
91
|
let persistentStateListener = null;
|
|
92
|
+
let persistentDiscoverListener = null;
|
|
62
93
|
const discoveredDevices = new Map();
|
|
63
94
|
const connectedDevices = new Map();
|
|
64
95
|
const pairedDevices = new Set();
|
|
@@ -66,16 +97,16 @@ const deviceCharacteristics = new Map();
|
|
|
66
97
|
const notificationCallbacks = new Map();
|
|
67
98
|
const subscribedDevices = new Map();
|
|
68
99
|
const subscriptionOperations = new Map();
|
|
100
|
+
const deviceDisconnectListeners = new Map();
|
|
69
101
|
const ONEKEY_SERVICE_UUIDS = [hdShared.ONEKEY_SERVICE_UUID];
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
102
|
+
const ONEKEY_SERVICE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_SERVICE_UUID);
|
|
103
|
+
const ONEKEY_WRITE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_WRITE_CHARACTERISTIC_UUID);
|
|
104
|
+
const ONEKEY_NOTIFY_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_NOTIFY_CHARACTERISTIC_UUID);
|
|
73
105
|
const BLUETOOTH_INIT_TIMEOUT = 10000;
|
|
74
|
-
const DEVICE_SCAN_TIMEOUT =
|
|
75
|
-
const FAST_SCAN_TIMEOUT = 8000;
|
|
106
|
+
const DEVICE_SCAN_TIMEOUT = 5000;
|
|
76
107
|
const DEVICE_CHECK_INTERVAL = 500;
|
|
77
|
-
const CONNECTION_TIMEOUT = 8000;
|
|
78
108
|
const SERVICE_DISCOVERY_TIMEOUT = 10000;
|
|
109
|
+
const BLE_CLEANUP_TIMEOUT = 250;
|
|
79
110
|
const BLE_PACKET_SIZE = 192;
|
|
80
111
|
const UNIFIED_WRITE_DELAY = 5;
|
|
81
112
|
const RETRY_CONFIG = { MAX_ATTEMPTS: 15, WRITE_TIMEOUT: 2000 };
|
|
@@ -83,37 +114,21 @@ const IS_WINDOWS = process.platform === 'win32';
|
|
|
83
114
|
const ABORTABLE_WRITE_ERROR_PATTERNS = [
|
|
84
115
|
/status:\s*3/i,
|
|
85
116
|
];
|
|
86
|
-
function getBleUuidKey(uuid) {
|
|
87
|
-
const normalized = (uuid !== null && uuid !== void 0 ? uuid : '').replace(/-/g, '').toLowerCase();
|
|
88
|
-
return normalized.length >= 8 ? normalized.substring(4, 8) : normalized;
|
|
89
|
-
}
|
|
90
|
-
const NORMALIZED_ONEKEY_SERVICE_UUIDS = new Set([
|
|
91
|
-
...ONEKEY_SERVICE_UUIDS.map(uuid => getBleUuidKey(uuid)),
|
|
92
|
-
'0001',
|
|
93
|
-
]);
|
|
94
|
-
function isGenericBleService(uuid) {
|
|
95
|
-
return ['1800', '1801', '180a', '180f'].includes(getBleUuidKey(uuid));
|
|
96
|
-
}
|
|
97
|
-
function hasOneKeyAdvertisementService(peripheral) {
|
|
98
|
-
var _a, _b;
|
|
99
|
-
const serviceUuids = (_b = (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.serviceUuids) !== null && _b !== void 0 ? _b : [];
|
|
100
|
-
return serviceUuids.some(uuid => {
|
|
101
|
-
const uuidKey = getBleUuidKey(uuid);
|
|
102
|
-
return (NORMALIZED_ONEKEY_SERVICE_UUIDS.has(uuidKey) ||
|
|
103
|
-
PRO2_ADVERTISEMENT_SERVICE_UUID_KEYS.has(uuidKey));
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
117
|
function isOneKeyPeripheral(peripheral) {
|
|
107
|
-
var _a;
|
|
108
|
-
const
|
|
109
|
-
|
|
118
|
+
var _a, _b;
|
|
119
|
+
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
|
+
return (hdShared.hasOnekeyCommunicationService(serviceUuids) &&
|
|
125
|
+
hdShared.isOnekeyBluetoothDevice({
|
|
126
|
+
id: peripheral.id,
|
|
127
|
+
localName,
|
|
128
|
+
serviceUuids,
|
|
129
|
+
}));
|
|
110
130
|
}
|
|
111
131
|
function emitRawNotification(deviceId, data) {
|
|
112
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Raw notification', {
|
|
113
|
-
deviceId,
|
|
114
|
-
dataLength: data.length,
|
|
115
|
-
firstBytes: data.subarray(0, 8).toString('hex'),
|
|
116
|
-
});
|
|
117
132
|
const appCb = notificationCallbacks.get(deviceId);
|
|
118
133
|
if (appCb)
|
|
119
134
|
appCb(data.toString('hex'));
|
|
@@ -250,9 +265,12 @@ function initializeNoble() {
|
|
|
250
265
|
};
|
|
251
266
|
noble.on('stateChange', onStateChange);
|
|
252
267
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
268
|
+
if (!persistentDiscoverListener) {
|
|
269
|
+
persistentDiscoverListener = (peripheral) => {
|
|
270
|
+
handleDeviceDiscovered(peripheral);
|
|
271
|
+
};
|
|
272
|
+
noble.on('discover', persistentDiscoverListener);
|
|
273
|
+
}
|
|
256
274
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Noble initialized successfully');
|
|
257
275
|
}
|
|
258
276
|
catch (error) {
|
|
@@ -277,6 +295,11 @@ function cleanupDevice(deviceId, webContents, options = {}) {
|
|
|
277
295
|
const peripheral = connectedDevices.get(deviceId);
|
|
278
296
|
const deviceName = ((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
279
297
|
if (cleanupConnection) {
|
|
298
|
+
const disconnectEntry = deviceDisconnectListeners.get(deviceId);
|
|
299
|
+
if (disconnectEntry) {
|
|
300
|
+
disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
|
|
301
|
+
deviceDisconnectListeners.delete(deviceId);
|
|
302
|
+
}
|
|
280
303
|
connectedDevices.delete(deviceId);
|
|
281
304
|
deviceCharacteristics.delete(deviceId);
|
|
282
305
|
notificationCallbacks.delete(deviceId);
|
|
@@ -311,10 +334,15 @@ function handleDeviceDisconnect(deviceId, webContents) {
|
|
|
311
334
|
});
|
|
312
335
|
}
|
|
313
336
|
function setupDisconnectListener(peripheral, deviceId, webContents) {
|
|
314
|
-
|
|
315
|
-
|
|
337
|
+
const existing = deviceDisconnectListeners.get(deviceId);
|
|
338
|
+
if (existing) {
|
|
339
|
+
existing.peripheral.removeListener('disconnect', existing.listener);
|
|
340
|
+
}
|
|
341
|
+
const listener = () => {
|
|
316
342
|
handleDeviceDisconnect(deviceId, webContents);
|
|
317
|
-
}
|
|
343
|
+
};
|
|
344
|
+
deviceDisconnectListeners.set(deviceId, { peripheral, listener });
|
|
345
|
+
peripheral.on('disconnect', listener);
|
|
318
346
|
}
|
|
319
347
|
function writeCharacteristicWithAck(deviceId, writeCharacteristic, buffer) {
|
|
320
348
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -415,11 +443,6 @@ function transmitHexDataToDevice(deviceId, hexData) {
|
|
|
415
443
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, `Device ${deviceId} not connected or characteristics not available`);
|
|
416
444
|
}
|
|
417
445
|
const toBuffer = Buffer.from(hexData, 'hex');
|
|
418
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Writing data:', {
|
|
419
|
-
deviceId,
|
|
420
|
-
dataLength: toBuffer.length,
|
|
421
|
-
firstBytes: toBuffer.subarray(0, 8).toString('hex'),
|
|
422
|
-
});
|
|
423
446
|
const doGetWriteCharacteristic = () => { var _a; return (_a = deviceCharacteristics.get(deviceId)) === null || _a === void 0 ? void 0 : _a.write; };
|
|
424
447
|
if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
|
|
425
448
|
const writeCharacteristic = doGetWriteCharacteristic();
|
|
@@ -464,35 +487,41 @@ function transmitHexDataToDevice(deviceId, hexData) {
|
|
|
464
487
|
}
|
|
465
488
|
function handleDeviceDiscovered(peripheral) {
|
|
466
489
|
var _a, _b;
|
|
467
|
-
const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
468
|
-
const serviceUuids = ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.serviceUuids) || [];
|
|
469
490
|
if (!isOneKeyPeripheral(peripheral)) {
|
|
470
491
|
return;
|
|
471
492
|
}
|
|
472
493
|
const isNewDevice = !discoveredDevices.has(peripheral.id);
|
|
473
494
|
discoveredDevices.set(peripheral.id, peripheral);
|
|
474
495
|
if (isNewDevice) {
|
|
475
|
-
logger === null || logger === void 0 ? void 0 : logger.
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
serviceUUIDs: serviceUuids,
|
|
496
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] OneKey BLE device discovered', {
|
|
497
|
+
deviceId: peripheral.id,
|
|
498
|
+
name: ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device',
|
|
499
|
+
serviceUUIDs: ((_b = peripheral.advertisement) === null || _b === void 0 ? void 0 : _b.serviceUuids) || [],
|
|
479
500
|
});
|
|
480
501
|
}
|
|
481
502
|
}
|
|
482
503
|
function ensureDiscoverListener() {
|
|
483
504
|
if (!noble)
|
|
484
505
|
return;
|
|
485
|
-
|
|
486
|
-
if (listenerCount === 0) {
|
|
506
|
+
if (!persistentDiscoverListener) {
|
|
487
507
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discover listener missing, re-adding it');
|
|
488
|
-
|
|
508
|
+
persistentDiscoverListener = (peripheral) => {
|
|
489
509
|
handleDeviceDiscovered(peripheral);
|
|
490
|
-
}
|
|
510
|
+
};
|
|
511
|
+
noble.on('discover', persistentDiscoverListener);
|
|
491
512
|
}
|
|
492
513
|
else {
|
|
493
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] Discover listener already
|
|
514
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] Discover listener already registered');
|
|
494
515
|
}
|
|
495
516
|
}
|
|
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
|
+
}
|
|
496
525
|
function performTargetedScan(targetDeviceId) {
|
|
497
526
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
498
527
|
if (!noble) {
|
|
@@ -501,33 +530,43 @@ function performTargetedScan(targetDeviceId) {
|
|
|
501
530
|
const nobleInstance = noble;
|
|
502
531
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting targeted scan for device:', targetDeviceId);
|
|
503
532
|
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
|
+
});
|
|
504
552
|
const onDiscover = (peripheral) => {
|
|
505
553
|
var _a;
|
|
506
|
-
if (peripheral.id === targetDeviceId) {
|
|
554
|
+
if (peripheral.id === targetDeviceId && isOneKeyPeripheral(peripheral)) {
|
|
507
555
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Target device found during targeted scan:', {
|
|
508
556
|
id: peripheral.id,
|
|
509
557
|
name: (_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName,
|
|
510
558
|
});
|
|
511
|
-
|
|
512
|
-
nobleInstance.removeListener('discover', onDiscover);
|
|
513
|
-
nobleInstance.stopScanning();
|
|
514
|
-
discoveredDevices.set(peripheral.id, peripheral);
|
|
515
|
-
resolve(peripheral);
|
|
559
|
+
finish(peripheral).catch(reject);
|
|
516
560
|
}
|
|
517
561
|
};
|
|
518
562
|
const timeoutId = setTimeout(() => {
|
|
519
|
-
nobleInstance.removeListener('discover', onDiscover);
|
|
520
|
-
nobleInstance.stopScanning();
|
|
521
563
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
|
|
522
|
-
|
|
523
|
-
},
|
|
564
|
+
finish(null).catch(reject);
|
|
565
|
+
}, NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS);
|
|
524
566
|
nobleInstance.on('discover', onDiscover);
|
|
525
567
|
nobleInstance.startScanning([], false, (error) => {
|
|
526
568
|
if (error) {
|
|
527
|
-
|
|
528
|
-
nobleInstance.removeListener('discover', onDiscover);
|
|
529
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start targeted scan:', error);
|
|
530
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, error.message));
|
|
569
|
+
finish(null, error).catch(reject);
|
|
531
570
|
return;
|
|
532
571
|
}
|
|
533
572
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan started for device:', targetDeviceId);
|
|
@@ -550,12 +589,12 @@ function enumerateDevices() {
|
|
|
550
589
|
return new Promise((resolve, reject) => {
|
|
551
590
|
const devices = [];
|
|
552
591
|
let intervalId;
|
|
553
|
-
const cleanup = () => {
|
|
592
|
+
const cleanup = () => index.__awaiter(this, void 0, void 0, function* () {
|
|
554
593
|
clearTimeout(timeoutId);
|
|
555
594
|
if (intervalId)
|
|
556
595
|
clearInterval(intervalId);
|
|
557
|
-
nobleInstance
|
|
558
|
-
};
|
|
596
|
+
yield waitForNobleScanStop(nobleInstance);
|
|
597
|
+
});
|
|
559
598
|
const checkDevices = () => {
|
|
560
599
|
discoveredDevices.forEach((peripheral, id) => {
|
|
561
600
|
var _a;
|
|
@@ -571,23 +610,23 @@ function enumerateDevices() {
|
|
|
571
610
|
}
|
|
572
611
|
});
|
|
573
612
|
};
|
|
574
|
-
const timeoutId = setTimeout(() => {
|
|
613
|
+
const timeoutId = setTimeout(() => index.__awaiter(this, void 0, void 0, function* () {
|
|
575
614
|
checkDevices();
|
|
576
|
-
cleanup();
|
|
615
|
+
yield cleanup();
|
|
577
616
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scan completed, found devices:', devices.length);
|
|
578
617
|
resolve(devices);
|
|
579
|
-
}, DEVICE_SCAN_TIMEOUT);
|
|
618
|
+
}), DEVICE_SCAN_TIMEOUT);
|
|
580
619
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning for OneKey BLE devices');
|
|
581
|
-
nobleInstance.startScanning([], false, (error) => {
|
|
620
|
+
nobleInstance.startScanning([], false, (error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
582
621
|
if (error) {
|
|
583
|
-
cleanup();
|
|
622
|
+
yield cleanup();
|
|
584
623
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start scanning:', error);
|
|
585
624
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, error.message));
|
|
586
625
|
return;
|
|
587
626
|
}
|
|
588
627
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning started for OneKey devices');
|
|
589
628
|
intervalId = setInterval(checkDevices, DEVICE_CHECK_INTERVAL);
|
|
590
|
-
});
|
|
629
|
+
}));
|
|
591
630
|
});
|
|
592
631
|
});
|
|
593
632
|
}
|
|
@@ -595,25 +634,20 @@ function stopScanning() {
|
|
|
595
634
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
596
635
|
if (!noble)
|
|
597
636
|
return;
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
noble.stopScanning(() => {
|
|
604
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning stopped');
|
|
605
|
-
resolve();
|
|
606
|
-
});
|
|
607
|
-
});
|
|
637
|
+
const nobleInstance = noble;
|
|
638
|
+
yield waitForNobleScanStop(nobleInstance);
|
|
639
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning stopped');
|
|
608
640
|
});
|
|
609
641
|
}
|
|
610
642
|
function cleanupNobleListeners() {
|
|
611
643
|
if (!noble)
|
|
612
644
|
return;
|
|
613
645
|
try {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
646
|
+
if (persistentDiscoverListener) {
|
|
647
|
+
noble.removeListener('discover', persistentDiscoverListener);
|
|
648
|
+
persistentDiscoverListener = null;
|
|
649
|
+
}
|
|
650
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Owned Noble listeners cleaned up');
|
|
617
651
|
}
|
|
618
652
|
catch (error) {
|
|
619
653
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to clean up some listeners:', error);
|
|
@@ -683,23 +717,22 @@ function discoverServicesAndCharacteristics(peripheral) {
|
|
|
683
717
|
}
|
|
684
718
|
});
|
|
685
719
|
});
|
|
686
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] All services:', services === null || services === void 0 ? void 0 : services.map(s => s.uuid));
|
|
687
720
|
if (!services || services.length === 0) {
|
|
688
721
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No services found');
|
|
689
722
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
services.find(s => !isGenericBleService(s.uuid)) ||
|
|
696
|
-
services[0];
|
|
697
|
-
}
|
|
723
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] services discovered', {
|
|
724
|
+
deviceId: peripheral.id,
|
|
725
|
+
serviceUUIDs: services.map(service => service.uuid),
|
|
726
|
+
});
|
|
727
|
+
const service = services.find(s => hdShared.matchesKnownBleUuid(s.uuid, ONEKEY_SERVICE_UUID_ALIASES));
|
|
698
728
|
if (!service) {
|
|
699
729
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
700
730
|
}
|
|
701
731
|
const selectedService = service;
|
|
702
|
-
logger === null || logger === void 0 ? void 0 : logger.
|
|
732
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] service selected', {
|
|
733
|
+
deviceId: peripheral.id,
|
|
734
|
+
serviceUuid: selectedService.uuid,
|
|
735
|
+
});
|
|
703
736
|
const characteristics = yield new Promise((resolve, reject) => {
|
|
704
737
|
selectedService.discoverCharacteristics([], (error, chars) => {
|
|
705
738
|
if (error) {
|
|
@@ -711,30 +744,26 @@ function discoverServicesAndCharacteristics(peripheral) {
|
|
|
711
744
|
}
|
|
712
745
|
});
|
|
713
746
|
});
|
|
714
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Discovered characteristics:', {
|
|
715
|
-
count: (characteristics === null || characteristics === void 0 ? void 0 : characteristics.length) || 0,
|
|
716
|
-
uuids: (characteristics === null || characteristics === void 0 ? void 0 : characteristics.map(c => c.uuid)) || [],
|
|
717
|
-
});
|
|
718
747
|
let writeCharacteristic = null;
|
|
719
748
|
let notifyCharacteristic = null;
|
|
720
749
|
for (const characteristic of characteristics) {
|
|
721
|
-
|
|
722
|
-
const uuidKey = uuid.length >= 8 ? uuid.substring(4, 8) : uuid;
|
|
723
|
-
if (uuidKey === NORMALIZED_WRITE_UUID) {
|
|
750
|
+
if (hdShared.matchesKnownBleUuid(characteristic.uuid, ONEKEY_WRITE_UUID_ALIASES)) {
|
|
724
751
|
writeCharacteristic = characteristic;
|
|
725
752
|
}
|
|
726
|
-
else if (
|
|
753
|
+
else if (hdShared.matchesKnownBleUuid(characteristic.uuid, ONEKEY_NOTIFY_UUID_ALIASES)) {
|
|
727
754
|
notifyCharacteristic = characteristic;
|
|
728
755
|
}
|
|
729
756
|
}
|
|
730
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Characteristic discovery result:', {
|
|
731
|
-
writeFound: !!writeCharacteristic,
|
|
732
|
-
notifyFound: !!notifyCharacteristic,
|
|
733
|
-
});
|
|
734
757
|
if (!writeCharacteristic || !notifyCharacteristic) {
|
|
735
758
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Missing characteristics - write:', !!writeCharacteristic, 'notify:', !!notifyCharacteristic);
|
|
736
759
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, 'Required characteristics not found');
|
|
737
760
|
}
|
|
761
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('[NobleBLE] characteristics selected', {
|
|
762
|
+
deviceId: peripheral.id,
|
|
763
|
+
serviceUuid: selectedService.uuid,
|
|
764
|
+
writeUuid: writeCharacteristic.uuid,
|
|
765
|
+
notifyUuid: notifyCharacteristic.uuid,
|
|
766
|
+
});
|
|
738
767
|
return { write: writeCharacteristic, notify: notifyCharacteristic };
|
|
739
768
|
}))();
|
|
740
769
|
try {
|
|
@@ -755,27 +784,17 @@ function forceReconnectPeripheral(peripheral, deviceId) {
|
|
|
755
784
|
reason: 'force-reconnect',
|
|
756
785
|
});
|
|
757
786
|
if (peripheral.state === 'connected') {
|
|
758
|
-
peripheral.
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
resolve();
|
|
763
|
-
});
|
|
764
|
-
});
|
|
787
|
+
yield runBleCallbackOperation(callback => peripheral.disconnect(() => {
|
|
788
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force disconnect completed');
|
|
789
|
+
callback();
|
|
790
|
+
}), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
|
|
765
791
|
}
|
|
766
|
-
yield
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Force reconnect failed:', error);
|
|
770
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, error.message));
|
|
771
|
-
}
|
|
772
|
-
else {
|
|
773
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
|
|
774
|
-
connectedDevices.set(deviceId, peripheral);
|
|
775
|
-
resolve();
|
|
776
|
-
}
|
|
777
|
-
});
|
|
792
|
+
yield runBleCallbackOperation(callback => peripheral.connect(callback), {
|
|
793
|
+
timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
|
|
794
|
+
timeoutBehavior: 'reject',
|
|
778
795
|
});
|
|
796
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
|
|
797
|
+
connectedDevices.set(deviceId, peripheral);
|
|
779
798
|
yield hdShared.wait(500);
|
|
780
799
|
});
|
|
781
800
|
}
|
|
@@ -852,13 +871,23 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
|
|
|
852
871
|
}
|
|
853
872
|
function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
|
|
854
873
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
874
|
+
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
875
|
+
try {
|
|
876
|
+
return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
877
|
+
}
|
|
878
|
+
catch (initialError) {
|
|
879
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Direct service discovery failed, retrying after reconnect', {
|
|
880
|
+
deviceId,
|
|
881
|
+
error: initialError,
|
|
882
|
+
});
|
|
883
|
+
}
|
|
855
884
|
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
856
885
|
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
857
886
|
try {
|
|
858
887
|
return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
859
888
|
}
|
|
860
|
-
catch (
|
|
861
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed, attempting fresh scan...',
|
|
889
|
+
catch (reconnectError) {
|
|
890
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed after reconnect, attempting fresh scan...', reconnectError);
|
|
862
891
|
return freshScanAndDiscover(deviceId, webContents);
|
|
863
892
|
}
|
|
864
893
|
});
|
|
@@ -931,12 +960,24 @@ function connectDevice(deviceId, webContents) {
|
|
|
931
960
|
return;
|
|
932
961
|
}
|
|
933
962
|
return new Promise((resolve, reject) => {
|
|
963
|
+
let connectionTimedOut = false;
|
|
934
964
|
const timeout = setTimeout(() => {
|
|
965
|
+
connectionTimedOut = true;
|
|
935
966
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'Connection timeout'));
|
|
936
|
-
},
|
|
967
|
+
}, NOBLE_BLE_CONNECTION_TIMEOUT_MS);
|
|
937
968
|
const connectedPeripheral = peripheral;
|
|
938
969
|
connectedPeripheral.connect((error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
939
970
|
clearTimeout(timeout);
|
|
971
|
+
if (connectionTimedOut) {
|
|
972
|
+
if (!error) {
|
|
973
|
+
try {
|
|
974
|
+
connectedPeripheral.disconnect(() => undefined);
|
|
975
|
+
}
|
|
976
|
+
catch (_a) {
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
940
981
|
if (error) {
|
|
941
982
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection failed:', error);
|
|
942
983
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, error.message));
|
|
@@ -966,17 +1007,20 @@ function disconnectDevice(deviceId) {
|
|
|
966
1007
|
if (!peripheral) {
|
|
967
1008
|
return;
|
|
968
1009
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
peripheral.disconnect
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1010
|
+
const disconnectEntry = deviceDisconnectListeners.get(deviceId);
|
|
1011
|
+
if (disconnectEntry) {
|
|
1012
|
+
disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
|
|
1013
|
+
deviceDisconnectListeners.delete(deviceId);
|
|
1014
|
+
}
|
|
1015
|
+
yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1016
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1017
|
+
timeoutBehavior: 'resolve',
|
|
1018
|
+
});
|
|
1019
|
+
cleanupDevice(deviceId, undefined, {
|
|
1020
|
+
cleanupConnection: true,
|
|
1021
|
+
sendDisconnectEvent: false,
|
|
1022
|
+
cancelOperations: true,
|
|
1023
|
+
reason: 'manual-disconnect',
|
|
980
1024
|
});
|
|
981
1025
|
});
|
|
982
1026
|
}
|
|
@@ -991,18 +1035,11 @@ function unsubscribeNotifications(deviceId) {
|
|
|
991
1035
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Unsubscribing from notifications for device:', deviceId);
|
|
992
1036
|
subscriptionOperations.set(deviceId, 'unsubscribing');
|
|
993
1037
|
try {
|
|
994
|
-
yield
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Notification unsubscription failed:', error);
|
|
998
|
-
reject(error);
|
|
999
|
-
}
|
|
1000
|
-
else {
|
|
1001
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification unsubscription successful');
|
|
1002
|
-
resolve();
|
|
1003
|
-
}
|
|
1004
|
-
});
|
|
1038
|
+
yield runBleCallbackOperation(callback => notifyCharacteristic.unsubscribe(callback), {
|
|
1039
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1040
|
+
timeoutBehavior: 'resolve',
|
|
1005
1041
|
});
|
|
1042
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification unsubscription completed');
|
|
1006
1043
|
notifyCharacteristic.removeAllListeners('data');
|
|
1007
1044
|
notificationCallbacks.delete(deviceId);
|
|
1008
1045
|
subscribedDevices.delete(deviceId);
|
|
@@ -1054,19 +1091,13 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1054
1091
|
notificationCallbacks.set(deviceId, callback);
|
|
1055
1092
|
function rebuildAppSubscription(deviceId, notifyCharacteristic) {
|
|
1056
1093
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
1057
|
-
yield
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
});
|
|
1094
|
+
yield runBleCallbackOperation(callback => notifyCharacteristic.unsubscribe(callback), {
|
|
1095
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1096
|
+
timeoutBehavior: 'resolve',
|
|
1061
1097
|
});
|
|
1062
|
-
yield
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
reject(error);
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
resolve();
|
|
1069
|
-
});
|
|
1098
|
+
yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1099
|
+
timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
|
|
1100
|
+
timeoutBehavior: 'reject',
|
|
1070
1101
|
});
|
|
1071
1102
|
notifyCharacteristic.on('data', (data) => {
|
|
1072
1103
|
if (!pairedDevices.has(deviceId)) {
|
|
@@ -1087,19 +1118,17 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1087
1118
|
});
|
|
1088
1119
|
}
|
|
1089
1120
|
function setupNobleBleHandlers(webContents) {
|
|
1090
|
-
console.log('[NobleBLE] Attempting to set up Noble BLE handlers.');
|
|
1091
1121
|
try {
|
|
1092
|
-
console.log('[NobleBLE] NOBLE_VERSION_771');
|
|
1093
1122
|
logger = require('electron-log');
|
|
1094
|
-
console.log('[NobleBLE] electron-log loaded successfully.');
|
|
1095
1123
|
const { ipcMain } = require('electron');
|
|
1096
|
-
console.log('[NobleBLE] electron.ipcMain loaded successfully.');
|
|
1097
1124
|
safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
|
|
1098
|
-
console.log(`[NobleBLE] Registering handler for: ${hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE}`);
|
|
1099
1125
|
ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, () => index.__awaiter(this, void 0, void 0, function* () {
|
|
1100
1126
|
try {
|
|
1101
1127
|
const devices = yield enumerateDevices();
|
|
1102
|
-
safeLog(logger, '
|
|
1128
|
+
safeLog(logger, 'debug', 'Enumeration completed', {
|
|
1129
|
+
count: devices.length,
|
|
1130
|
+
devices: devices.map(device => ({ id: device.id, name: device.name })),
|
|
1131
|
+
});
|
|
1103
1132
|
return devices;
|
|
1104
1133
|
}
|
|
1105
1134
|
catch (error) {
|
|
@@ -1124,7 +1153,6 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1124
1153
|
yield disconnectDevice(deviceId);
|
|
1125
1154
|
}));
|
|
1126
1155
|
ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_WRITE, (_event, deviceId, hexData) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1127
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] IPC WRITE', { deviceId, len: hexData.length });
|
|
1128
1156
|
yield transmitHexDataToDevice(deviceId, hexData);
|
|
1129
1157
|
}));
|
|
1130
1158
|
ipcMain.handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_SUBSCRIBE, (_event, deviceId) => index.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1169,23 +1197,23 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1169
1197
|
}));
|
|
1170
1198
|
webContents.on('destroyed', () => {
|
|
1171
1199
|
safeLog(logger, 'info', 'Cleaning up Noble BLE handlers');
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1200
|
+
(() => index.__awaiter(this, void 0, void 0, function* () {
|
|
1201
|
+
const deviceIds = Array.from(connectedDevices.keys());
|
|
1202
|
+
for (const deviceId of deviceIds) {
|
|
1203
|
+
yield unsubscribeNotifications(deviceId).catch(() => undefined);
|
|
1204
|
+
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1205
|
+
}
|
|
1206
|
+
yield stopScanning().catch(() => undefined);
|
|
1207
|
+
if (noble && persistentStateListener) {
|
|
1208
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1209
|
+
persistentStateListener = null;
|
|
1210
|
+
}
|
|
1211
|
+
cleanupNobleListeners();
|
|
1212
|
+
discoveredDevices.clear();
|
|
1213
|
+
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|
|
1214
|
+
}))().catch(error => {
|
|
1215
|
+
safeLog(logger, 'error', 'Noble BLE cleanup failed', error);
|
|
1180
1216
|
});
|
|
1181
|
-
stopScanning();
|
|
1182
|
-
if (noble && persistentStateListener) {
|
|
1183
|
-
noble.removeListener('stateChange', persistentStateListener);
|
|
1184
|
-
persistentStateListener = null;
|
|
1185
|
-
}
|
|
1186
|
-
cleanupNobleListeners();
|
|
1187
|
-
discoveredDevices.clear();
|
|
1188
|
-
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|
|
1189
1217
|
});
|
|
1190
1218
|
safeLog(logger, 'info', 'Noble BLE IPC handlers setup completed');
|
|
1191
1219
|
}
|