@onekeyfe/hd-transport-electron 1.2.2-alpha.12 → 1.2.2-alpha.122
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-eea100c1.js → index-474dbbae.js} +33 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/{noble-ble-handler-e4eaea92.js → noble-ble-handler-23c86603.js} +373 -99
- package/dist/noble-ble-handler.d.ts +11 -2
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/dist/noble-ble-timeouts.d.ts +1 -1
- package/dist/noble-ble-timeouts.d.ts.map +1 -1
- package/dist/types/desktop-api.d.ts +13 -0
- package/dist/types/desktop-api.d.ts.map +1 -1
- package/dist/types/noble-extended.d.ts +2 -0
- package/dist/types/noble-extended.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/noble-ble-handler.test.ts +775 -22
- package/src/index.ts +14 -1
- package/src/noble-ble-handler.ts +440 -119
- package/src/noble-ble-timeouts.ts +1 -1
- package/src/types/desktop-api.ts +44 -0
- package/src/types/noble-extended.ts +2 -0
|
@@ -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
|
|
|
@@ -96,22 +96,65 @@ function softRefreshSubscription(params) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5000;
|
|
99
|
-
const
|
|
99
|
+
const NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS = 10000;
|
|
100
100
|
|
|
101
101
|
let noble = null;
|
|
102
102
|
let logger = null;
|
|
103
|
+
let disposing = false;
|
|
104
|
+
let nativeReleased = false;
|
|
105
|
+
let disposePromise;
|
|
106
|
+
let windowCleanup;
|
|
107
|
+
let removeIpcHandlers;
|
|
108
|
+
const pendingCancellations = new Set();
|
|
109
|
+
const pendingEnumerations = new Set();
|
|
110
|
+
const nativeConnections = new Set();
|
|
111
|
+
function trackNativeConnection(operation, cancel) {
|
|
112
|
+
const connection = {
|
|
113
|
+
cancel,
|
|
114
|
+
settled: operation.then(() => undefined, () => undefined),
|
|
115
|
+
};
|
|
116
|
+
nativeConnections.add(connection);
|
|
117
|
+
connection.settled = connection.settled.finally(() => nativeConnections.delete(connection));
|
|
118
|
+
}
|
|
119
|
+
function assertBleActive() {
|
|
120
|
+
if (disposing) {
|
|
121
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, 'Noble BLE is shutting down');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
103
124
|
function createNobleBleConnectionError(error, messagePrefix = '') {
|
|
104
125
|
const errorMessage = error.message;
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
126
|
+
const isInvalidMacOsBond = (error.nativeErrorCode === 14 && error.nativeErrorDomain === 'CBErrorDomain') ||
|
|
127
|
+
(error.nativeErrorCode === 15 && error.nativeErrorDomain === 'CBATTErrorDomain');
|
|
128
|
+
if (isInvalidMacOsBond) {
|
|
129
|
+
const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
|
|
130
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, `${hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`, {
|
|
131
|
+
nativeErrorMessage,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
|
|
135
|
+
}
|
|
136
|
+
function createNobleBleIpcErrorResponse(error) {
|
|
137
|
+
const candidate = error;
|
|
138
|
+
const errorCode = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.errorCode) === 'number' ? candidate.errorCode : hdShared.HardwareErrorCode.UnknownError;
|
|
139
|
+
const message = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.message) === 'string' ? candidate.message : String(error !== null && error !== void 0 ? error : 'Unknown error');
|
|
140
|
+
const name = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.name) === 'string' ? candidate.name : 'Error';
|
|
141
|
+
let params;
|
|
142
|
+
if ((candidate === null || candidate === void 0 ? void 0 : candidate.params) !== undefined) {
|
|
143
|
+
try {
|
|
144
|
+
const serializedParams = JSON.stringify(candidate.params);
|
|
145
|
+
params = serializedParams === undefined ? undefined : JSON.parse(serializedParams);
|
|
146
|
+
}
|
|
147
|
+
catch (_a) {
|
|
148
|
+
params = undefined;
|
|
149
|
+
}
|
|
113
150
|
}
|
|
114
|
-
return
|
|
151
|
+
return {
|
|
152
|
+
type: 'NobleBleIpcError',
|
|
153
|
+
success: false,
|
|
154
|
+
error: Object.assign({ name,
|
|
155
|
+
message,
|
|
156
|
+
errorCode }, (params !== undefined ? { params } : {})),
|
|
157
|
+
};
|
|
115
158
|
}
|
|
116
159
|
const bluetoothState = {
|
|
117
160
|
available: false,
|
|
@@ -122,6 +165,86 @@ let persistentStateListener = null;
|
|
|
122
165
|
let persistentDiscoverListener = null;
|
|
123
166
|
const discoveredDevices = new Map();
|
|
124
167
|
const connectedDevices = new Map();
|
|
168
|
+
const connectingDevices = new Map();
|
|
169
|
+
let nextConnectionGeneration = 0;
|
|
170
|
+
function connectPeripheralWithCancellation(peripheral, deviceId, messagePrefix = '') {
|
|
171
|
+
assertBleActive();
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
var _a;
|
|
174
|
+
const generation = ++nextConnectionGeneration;
|
|
175
|
+
let settled = false;
|
|
176
|
+
const settle = (settler) => {
|
|
177
|
+
var _a;
|
|
178
|
+
if (settled)
|
|
179
|
+
return false;
|
|
180
|
+
settled = true;
|
|
181
|
+
if (((_a = connectingDevices.get(deviceId)) === null || _a === void 0 ? void 0 : _a.generation) === generation) {
|
|
182
|
+
connectingDevices.delete(deviceId);
|
|
183
|
+
}
|
|
184
|
+
settler();
|
|
185
|
+
return true;
|
|
186
|
+
};
|
|
187
|
+
const pendingConnection = {
|
|
188
|
+
peripheral,
|
|
189
|
+
generation,
|
|
190
|
+
cancel: error => {
|
|
191
|
+
settle(() => reject(error));
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
(_a = connectingDevices
|
|
195
|
+
.get(deviceId)) === null || _a === void 0 ? void 0 : _a.cancel(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, `Device ${deviceId} connect attempt was superseded`));
|
|
196
|
+
connectingDevices.set(deviceId, pendingConnection);
|
|
197
|
+
let completeNative;
|
|
198
|
+
trackNativeConnection(new Promise(resolve => {
|
|
199
|
+
completeNative = resolve;
|
|
200
|
+
}), () => {
|
|
201
|
+
var _a;
|
|
202
|
+
if (typeof peripheral.cancelConnect === 'function')
|
|
203
|
+
peripheral.cancelConnect();
|
|
204
|
+
else
|
|
205
|
+
(_a = noble === null || noble === void 0 ? void 0 : noble.cancelConnect) === null || _a === void 0 ? void 0 : _a.call(noble, deviceId);
|
|
206
|
+
});
|
|
207
|
+
const onConnect = (error) => {
|
|
208
|
+
if (nativeReleased) {
|
|
209
|
+
completeNative();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (error) {
|
|
213
|
+
settle(() => reject(createNobleBleConnectionError(error, messagePrefix)));
|
|
214
|
+
completeNative();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (!settle(() => {
|
|
218
|
+
connectedDevices.set(deviceId, peripheral);
|
|
219
|
+
resolve();
|
|
220
|
+
})) {
|
|
221
|
+
const activeConnection = connectingDevices.get(deviceId);
|
|
222
|
+
if (!activeConnection || activeConnection.peripheral !== peripheral) {
|
|
223
|
+
try {
|
|
224
|
+
peripheral.removeAllListeners('disconnect');
|
|
225
|
+
runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
226
|
+
timeoutMs: BLE_DISCONNECT_CONFIRM_TIMEOUT_MS,
|
|
227
|
+
timeoutBehavior: 'resolve',
|
|
228
|
+
})
|
|
229
|
+
.catch(() => undefined)
|
|
230
|
+
.finally(completeNative);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
catch (_a) {
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
completeNative();
|
|
238
|
+
};
|
|
239
|
+
try {
|
|
240
|
+
peripheral.connect(onConnect);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
completeNative();
|
|
244
|
+
settle(() => reject(error));
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
125
248
|
const pairedDevices = new Set();
|
|
126
249
|
const deviceCharacteristics = new Map();
|
|
127
250
|
const notificationCallbacks = new Map();
|
|
@@ -260,6 +383,7 @@ function updateBluetoothState(state) {
|
|
|
260
383
|
}
|
|
261
384
|
function initializeNoble() {
|
|
262
385
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
386
|
+
assertBleActive();
|
|
263
387
|
if (noble)
|
|
264
388
|
return;
|
|
265
389
|
try {
|
|
@@ -276,9 +400,11 @@ function initializeNoble() {
|
|
|
276
400
|
return;
|
|
277
401
|
}
|
|
278
402
|
const timeout = setTimeout(() => {
|
|
403
|
+
cleanup();
|
|
279
404
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout'));
|
|
280
405
|
}, BLUETOOTH_INIT_TIMEOUT);
|
|
281
406
|
const cleanup = () => {
|
|
407
|
+
pendingCancellations.delete(cancel);
|
|
282
408
|
clearTimeout(timeout);
|
|
283
409
|
if (noble) {
|
|
284
410
|
noble.removeListener('stateChange', onStateChange);
|
|
@@ -303,8 +429,14 @@ function initializeNoble() {
|
|
|
303
429
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
304
430
|
}
|
|
305
431
|
};
|
|
432
|
+
const cancel = () => {
|
|
433
|
+
cleanup();
|
|
434
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, 'Noble BLE is shutting down'));
|
|
435
|
+
};
|
|
436
|
+
pendingCancellations.add(cancel);
|
|
306
437
|
noble.on('stateChange', onStateChange);
|
|
307
438
|
});
|
|
439
|
+
assertBleActive();
|
|
308
440
|
if (!persistentDiscoverListener) {
|
|
309
441
|
persistentDiscoverListener = (peripheral) => {
|
|
310
442
|
handleDeviceDiscovered(peripheral);
|
|
@@ -351,6 +483,8 @@ function broadcastToAllWebContents(channel, payload) {
|
|
|
351
483
|
}
|
|
352
484
|
function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle') {
|
|
353
485
|
clearIdleDisconnect(deviceId);
|
|
486
|
+
if (disposing)
|
|
487
|
+
return;
|
|
354
488
|
idleDisconnectTimers.set(deviceId, setTimeout(() => {
|
|
355
489
|
var _a;
|
|
356
490
|
idleDisconnectTimers.delete(deviceId);
|
|
@@ -386,7 +520,7 @@ function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle
|
|
|
386
520
|
}, ms));
|
|
387
521
|
}
|
|
388
522
|
function cleanupDevice(deviceId, webContents, options = {}) {
|
|
389
|
-
var _a;
|
|
523
|
+
var _a, _b;
|
|
390
524
|
const { cleanupConnection = true, cleanupDiscoveredCache = false, sendDisconnectEvent = false, cancelOperations = true, reason = 'unknown', disconnectReason = hdShared.EBleDisconnectReason.DeviceDisconnected, } = options;
|
|
391
525
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting device cleanup', {
|
|
392
526
|
deviceId,
|
|
@@ -400,6 +534,8 @@ function cleanupDevice(deviceId, webContents, options = {}) {
|
|
|
400
534
|
const peripheral = connectedDevices.get(deviceId);
|
|
401
535
|
const deviceName = ((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
402
536
|
if (cleanupConnection) {
|
|
537
|
+
(_b = connectingDevices
|
|
538
|
+
.get(deviceId)) === null || _b === void 0 ? void 0 : _b.cancel(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, `Device ${deviceId} disconnected while connecting`));
|
|
403
539
|
const disconnectEntry = deviceDisconnectListeners.get(deviceId);
|
|
404
540
|
if (disconnectEntry) {
|
|
405
541
|
disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
|
|
@@ -478,6 +614,7 @@ function setupMtuListener(peripheral, deviceId, webContents) {
|
|
|
478
614
|
}
|
|
479
615
|
function writeCharacteristicWithoutResponse(deviceId, writeCharacteristic, buffer) {
|
|
480
616
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
617
|
+
assertBleActive();
|
|
481
618
|
return new Promise((resolve, reject) => {
|
|
482
619
|
writeCharacteristic.write(buffer, true, (error) => {
|
|
483
620
|
if (error) {
|
|
@@ -680,6 +817,7 @@ function waitForNobleScanStop(nobleInstance) {
|
|
|
680
817
|
}
|
|
681
818
|
function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS) {
|
|
682
819
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
820
|
+
assertBleActive();
|
|
683
821
|
if (!noble) {
|
|
684
822
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
|
|
685
823
|
}
|
|
@@ -691,6 +829,7 @@ function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN
|
|
|
691
829
|
if (settled)
|
|
692
830
|
return;
|
|
693
831
|
settled = true;
|
|
832
|
+
pendingCancellations.delete(cancel);
|
|
694
833
|
if (timeoutId)
|
|
695
834
|
clearTimeout(timeoutId);
|
|
696
835
|
nobleInstance.removeListener('discover', onDiscover);
|
|
@@ -700,6 +839,7 @@ function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN
|
|
|
700
839
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, error.message));
|
|
701
840
|
return;
|
|
702
841
|
}
|
|
842
|
+
assertBleActive();
|
|
703
843
|
if (peripheral) {
|
|
704
844
|
discoveredDevices.set(peripheral.id, peripheral);
|
|
705
845
|
}
|
|
@@ -719,6 +859,10 @@ function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN
|
|
|
719
859
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Targeted scan timeout for device:', targetDeviceId);
|
|
720
860
|
finish(null).catch(reject);
|
|
721
861
|
}, timeoutMs);
|
|
862
|
+
const cancel = () => {
|
|
863
|
+
finish(null, new Error('Noble BLE is shutting down')).catch(reject);
|
|
864
|
+
};
|
|
865
|
+
pendingCancellations.add(cancel);
|
|
722
866
|
nobleInstance.on('discover', onDiscover);
|
|
723
867
|
nobleInstance.startScanning([], true, (error) => {
|
|
724
868
|
if (error) {
|
|
@@ -730,7 +874,7 @@ function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN
|
|
|
730
874
|
});
|
|
731
875
|
});
|
|
732
876
|
}
|
|
733
|
-
function enumerateDevices() {
|
|
877
|
+
function enumerateDevices(isWindowDestroyed) {
|
|
734
878
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
735
879
|
if (!noble) {
|
|
736
880
|
yield initializeNoble();
|
|
@@ -738,19 +882,30 @@ function enumerateDevices() {
|
|
|
738
882
|
if (!noble) {
|
|
739
883
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
|
|
740
884
|
}
|
|
885
|
+
assertBleActive();
|
|
886
|
+
if (isWindowDestroyed())
|
|
887
|
+
return [];
|
|
741
888
|
const nobleInstance = noble;
|
|
742
889
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting device enumeration');
|
|
743
|
-
discoveredDevices.clear();
|
|
744
890
|
ensureDiscoverListener();
|
|
745
891
|
return new Promise((resolve, reject) => {
|
|
746
892
|
const devices = [];
|
|
893
|
+
let settled = false;
|
|
747
894
|
let intervalId;
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
if (
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
895
|
+
let cleanupPromise;
|
|
896
|
+
const cleanup = () => {
|
|
897
|
+
if (!cleanupPromise) {
|
|
898
|
+
settled = true;
|
|
899
|
+
pendingCancellations.delete(cancel);
|
|
900
|
+
clearTimeout(timeoutId);
|
|
901
|
+
if (intervalId)
|
|
902
|
+
clearInterval(intervalId);
|
|
903
|
+
cleanupPromise = waitForNobleScanStop(nobleInstance).finally(() => {
|
|
904
|
+
pendingEnumerations.delete(cancel);
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
return cleanupPromise;
|
|
908
|
+
};
|
|
754
909
|
const pushDevice = (peripheral, id) => {
|
|
755
910
|
var _a;
|
|
756
911
|
if (devices.some(d => d.id === id))
|
|
@@ -767,13 +922,20 @@ function enumerateDevices() {
|
|
|
767
922
|
connectedDevices.forEach(pushDevice);
|
|
768
923
|
};
|
|
769
924
|
const timeoutId = setTimeout(() => index.__awaiter(this, void 0, void 0, function* () {
|
|
925
|
+
if (settled)
|
|
926
|
+
return;
|
|
770
927
|
checkDevices();
|
|
771
928
|
yield cleanup();
|
|
772
929
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scan completed, found devices:', devices.length);
|
|
773
930
|
resolve(devices);
|
|
774
931
|
}), DEVICE_SCAN_TIMEOUT);
|
|
932
|
+
const cancel = () => cleanup().then(() => resolve([]), reject);
|
|
933
|
+
pendingCancellations.add(cancel);
|
|
934
|
+
pendingEnumerations.add(cancel);
|
|
775
935
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning for OneKey BLE devices');
|
|
776
936
|
nobleInstance.startScanning([], true, (error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
937
|
+
if (settled)
|
|
938
|
+
return;
|
|
777
939
|
if (error) {
|
|
778
940
|
yield cleanup();
|
|
779
941
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Failed to start scanning:', error);
|
|
@@ -788,7 +950,7 @@ function enumerateDevices() {
|
|
|
788
950
|
}
|
|
789
951
|
function stopScanning() {
|
|
790
952
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
791
|
-
if (!noble)
|
|
953
|
+
if (!noble || nativeReleased)
|
|
792
954
|
return;
|
|
793
955
|
const nobleInstance = noble;
|
|
794
956
|
yield waitForNobleScanStop(nobleInstance);
|
|
@@ -832,13 +994,16 @@ function getDevice(deviceId) {
|
|
|
832
994
|
}
|
|
833
995
|
function discoverServicesAndCharacteristics(peripheral) {
|
|
834
996
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
997
|
+
assertBleActive();
|
|
835
998
|
let timeoutId;
|
|
836
999
|
let onDisconnect;
|
|
837
1000
|
const cleanup = () => {
|
|
838
1001
|
if (timeoutId)
|
|
839
1002
|
clearTimeout(timeoutId);
|
|
840
|
-
if (onDisconnect)
|
|
1003
|
+
if (onDisconnect) {
|
|
841
1004
|
peripheral.removeListener('disconnect', onDisconnect);
|
|
1005
|
+
pendingCancellations.delete(onDisconnect);
|
|
1006
|
+
}
|
|
842
1007
|
};
|
|
843
1008
|
const timeoutPromise = new Promise((_, reject) => {
|
|
844
1009
|
timeoutId = setTimeout(() => {
|
|
@@ -851,6 +1016,7 @@ function discoverServicesAndCharacteristics(peripheral) {
|
|
|
851
1016
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Device disconnected during service discovery');
|
|
852
1017
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'Device disconnected during service discovery'));
|
|
853
1018
|
};
|
|
1019
|
+
pendingCancellations.add(onDisconnect);
|
|
854
1020
|
peripheral.once('disconnect', onDisconnect);
|
|
855
1021
|
});
|
|
856
1022
|
const discoveryPromise = (() => index.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -865,6 +1031,7 @@ function discoverServicesAndCharacteristics(peripheral) {
|
|
|
865
1031
|
}
|
|
866
1032
|
});
|
|
867
1033
|
});
|
|
1034
|
+
assertBleActive();
|
|
868
1035
|
if (!services || services.length === 0) {
|
|
869
1036
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound, 'No OneKey services found');
|
|
870
1037
|
}
|
|
@@ -937,12 +1104,8 @@ function forceReconnectPeripheral(peripheral, deviceId) {
|
|
|
937
1104
|
callback();
|
|
938
1105
|
}), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
|
|
939
1106
|
}
|
|
940
|
-
yield
|
|
941
|
-
timeoutMs: NOBLE_BLE_CONNECTION_TIMEOUT_MS,
|
|
942
|
-
timeoutBehavior: 'reject',
|
|
943
|
-
});
|
|
1107
|
+
yield connectPeripheralWithCancellation(peripheral, deviceId);
|
|
944
1108
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
|
|
945
|
-
connectedDevices.set(deviceId, peripheral);
|
|
946
1109
|
yield hdShared.wait(500);
|
|
947
1110
|
});
|
|
948
1111
|
}
|
|
@@ -959,17 +1122,7 @@ function freshScanAndDiscover(deviceId, webContents) {
|
|
|
959
1122
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${deviceId} not found in fresh scan`);
|
|
960
1123
|
}
|
|
961
1124
|
discoveredDevices.set(deviceId, freshPeripheral);
|
|
962
|
-
yield
|
|
963
|
-
freshPeripheral.connect((error) => {
|
|
964
|
-
if (error) {
|
|
965
|
-
reject(createNobleBleConnectionError(error, 'Fresh peripheral connection failed: '));
|
|
966
|
-
}
|
|
967
|
-
else {
|
|
968
|
-
connectedDevices.set(deviceId, freshPeripheral);
|
|
969
|
-
resolve();
|
|
970
|
-
}
|
|
971
|
-
});
|
|
972
|
-
});
|
|
1125
|
+
yield connectPeripheralWithCancellation(freshPeripheral, deviceId, 'Fresh peripheral connection failed: ');
|
|
973
1126
|
setupDisconnectListener(freshPeripheral, deviceId, webContents);
|
|
974
1127
|
yield hdShared.wait(500);
|
|
975
1128
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Attempting service discovery with fresh peripheral');
|
|
@@ -1008,6 +1161,7 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
|
|
|
1008
1161
|
minTimeout: 500,
|
|
1009
1162
|
maxTimeout: 3000,
|
|
1010
1163
|
onFailedAttempt: error => {
|
|
1164
|
+
assertBleActive();
|
|
1011
1165
|
logger === null || logger === void 0 ? void 0 : logger.error(`[NobleBLE] Service discovery attempt ${error.attemptNumber} failed:`, {
|
|
1012
1166
|
message: error.message,
|
|
1013
1167
|
retriesLeft: error.retriesLeft,
|
|
@@ -1023,8 +1177,13 @@ function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
|
|
|
1023
1177
|
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
1024
1178
|
}
|
|
1025
1179
|
catch (resetError) {
|
|
1180
|
+
if (hdShared.isBleStaleBondHardwareError(resetError) ||
|
|
1181
|
+
(resetError === null || resetError === void 0 ? void 0 : resetError.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
|
|
1182
|
+
throw resetError;
|
|
1183
|
+
}
|
|
1026
1184
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
|
|
1027
1185
|
}
|
|
1186
|
+
assertBleActive();
|
|
1028
1187
|
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
1029
1188
|
try {
|
|
1030
1189
|
return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
@@ -1047,36 +1206,46 @@ const directConnectCooldownUntil = new Map();
|
|
|
1047
1206
|
function tryDirectConnectById(deviceId) {
|
|
1048
1207
|
var _a;
|
|
1049
1208
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
1209
|
+
assertBleActive();
|
|
1050
1210
|
const nobleInstance = noble;
|
|
1051
1211
|
if (!(nobleInstance === null || nobleInstance === void 0 ? void 0 : nobleInstance.connectAsync))
|
|
1052
1212
|
return undefined;
|
|
1053
1213
|
const cooldownUntil = (_a = directConnectCooldownUntil.get(deviceId)) !== null && _a !== void 0 ? _a : 0;
|
|
1054
1214
|
if (Date.now() < cooldownUntil)
|
|
1055
1215
|
return undefined;
|
|
1216
|
+
let timer;
|
|
1217
|
+
let cancel;
|
|
1218
|
+
let abandoned = false;
|
|
1056
1219
|
try {
|
|
1057
1220
|
const directPromise = nobleInstance.connectAsync(deviceId);
|
|
1221
|
+
trackNativeConnection(directPromise.then((late) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1222
|
+
if ((!abandoned && !disposing) || nativeReleased)
|
|
1223
|
+
return;
|
|
1224
|
+
const peripheral = late !== null && late !== void 0 ? late : discoveredDevices.get(deviceId);
|
|
1225
|
+
if ((peripheral === null || peripheral === void 0 ? void 0 : peripheral.state) === 'connected' && !connectedDevices.has(deviceId)) {
|
|
1226
|
+
peripheral.removeAllListeners('disconnect');
|
|
1227
|
+
yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1228
|
+
timeoutMs: BLE_DISCONNECT_CONFIRM_TIMEOUT_MS,
|
|
1229
|
+
timeoutBehavior: 'resolve',
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
})), () => { var _a; return (_a = nobleInstance.cancelConnect) === null || _a === void 0 ? void 0 : _a.call(nobleInstance, deviceId); });
|
|
1058
1233
|
const raced = yield Promise.race([
|
|
1059
1234
|
directPromise,
|
|
1060
1235
|
new Promise(resolve => {
|
|
1061
|
-
|
|
1236
|
+
cancel = () => {
|
|
1237
|
+
abandoned = true;
|
|
1238
|
+
resolve('timeout');
|
|
1239
|
+
};
|
|
1240
|
+
pendingCancellations.add(cancel);
|
|
1241
|
+
timer = setTimeout(cancel, DIRECT_CONNECT_TIMEOUT_MS);
|
|
1062
1242
|
}),
|
|
1063
1243
|
]);
|
|
1064
|
-
if (raced === 'timeout') {
|
|
1244
|
+
if (raced === 'timeout' || disposing) {
|
|
1065
1245
|
directConnectCooldownUntil.set(deviceId, Date.now() + DIRECT_CONNECT_COOLDOWN_MS);
|
|
1066
1246
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Direct connect-by-id timed out, falling back to scan', {
|
|
1067
1247
|
deviceId,
|
|
1068
1248
|
});
|
|
1069
|
-
directPromise
|
|
1070
|
-
.then(late => {
|
|
1071
|
-
const latePeripheral = late !== null && late !== void 0 ? late : discoveredDevices.get(deviceId);
|
|
1072
|
-
if (latePeripheral &&
|
|
1073
|
-
latePeripheral.state === 'connected' &&
|
|
1074
|
-
!connectedDevices.has(deviceId)) {
|
|
1075
|
-
latePeripheral.removeAllListeners('disconnect');
|
|
1076
|
-
latePeripheral.disconnect(() => undefined);
|
|
1077
|
-
}
|
|
1078
|
-
})
|
|
1079
|
-
.catch(() => undefined);
|
|
1080
1249
|
return undefined;
|
|
1081
1250
|
}
|
|
1082
1251
|
const peripheral = raced !== null && raced !== void 0 ? raced : discoveredDevices.get(deviceId);
|
|
@@ -1093,6 +1262,11 @@ function tryDirectConnectById(deviceId) {
|
|
|
1093
1262
|
});
|
|
1094
1263
|
return undefined;
|
|
1095
1264
|
}
|
|
1265
|
+
finally {
|
|
1266
|
+
clearTimeout(timer);
|
|
1267
|
+
if (cancel)
|
|
1268
|
+
pendingCancellations.delete(cancel);
|
|
1269
|
+
}
|
|
1096
1270
|
});
|
|
1097
1271
|
}
|
|
1098
1272
|
function connectDevice(deviceId, webContents) {
|
|
@@ -1106,7 +1280,10 @@ function connectDevice(deviceId, webContents) {
|
|
|
1106
1280
|
totalDiscovered: discoveredDevices.size,
|
|
1107
1281
|
totalConnected: connectedDevices.size,
|
|
1108
1282
|
});
|
|
1109
|
-
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
|
+
}
|
|
1110
1287
|
if (!peripheral) {
|
|
1111
1288
|
if (!noble) {
|
|
1112
1289
|
yield initializeNoble();
|
|
@@ -1145,6 +1322,7 @@ function connectDevice(deviceId, webContents) {
|
|
|
1145
1322
|
peripheral = byIdFirst ? yield scanForPeripheral() : yield connectById();
|
|
1146
1323
|
}
|
|
1147
1324
|
}
|
|
1325
|
+
assertBleActive();
|
|
1148
1326
|
if (!peripheral) {
|
|
1149
1327
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${deviceId} not found`);
|
|
1150
1328
|
}
|
|
@@ -1155,6 +1333,7 @@ function connectDevice(deviceId, webContents) {
|
|
|
1155
1333
|
if (!connectedDevices.has(deviceId)) {
|
|
1156
1334
|
connectedDevices.set(deviceId, peripheral);
|
|
1157
1335
|
}
|
|
1336
|
+
assertBleActive();
|
|
1158
1337
|
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
1159
1338
|
if (deviceCharacteristics.has(deviceId)) {
|
|
1160
1339
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device characteristics already available');
|
|
@@ -1179,6 +1358,7 @@ function connectDevice(deviceId, webContents) {
|
|
|
1179
1358
|
}
|
|
1180
1359
|
try {
|
|
1181
1360
|
const characteristics = yield setupConnectionAndDiscoverServices(peripheral, deviceId, webContents);
|
|
1361
|
+
assertBleActive();
|
|
1182
1362
|
deviceCharacteristics.set(deviceId, characteristics);
|
|
1183
1363
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device ready for communication:', deviceId);
|
|
1184
1364
|
}
|
|
@@ -1189,54 +1369,33 @@ function connectDevice(deviceId, webContents) {
|
|
|
1189
1369
|
}
|
|
1190
1370
|
return;
|
|
1191
1371
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
catch (_a) {
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
return;
|
|
1210
|
-
}
|
|
1211
|
-
if (error) {
|
|
1212
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection failed:', error);
|
|
1213
|
-
reject(createNobleBleConnectionError(error));
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connected to device:', deviceId);
|
|
1217
|
-
connectedDevices.set(deviceId, connectedPeripheral);
|
|
1218
|
-
try {
|
|
1219
|
-
const characteristics = yield setupConnectionAndDiscoverServices(connectedPeripheral, deviceId, webContents);
|
|
1220
|
-
deviceCharacteristics.set(deviceId, characteristics);
|
|
1221
|
-
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device ready for communication:', deviceId);
|
|
1222
|
-
resolve();
|
|
1223
|
-
}
|
|
1224
|
-
catch (setupError) {
|
|
1225
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection setup failed:', setupError);
|
|
1226
|
-
disconnectDevice(deviceId)
|
|
1227
|
-
.catch(() => undefined)
|
|
1228
|
-
.then(() => reject(setupError));
|
|
1229
|
-
}
|
|
1230
|
-
}));
|
|
1231
|
-
});
|
|
1372
|
+
const connectedPeripheral = peripheral;
|
|
1373
|
+
yield connectPeripheralWithCancellation(connectedPeripheral, deviceId);
|
|
1374
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connected to device:', deviceId);
|
|
1375
|
+
try {
|
|
1376
|
+
const characteristics = yield setupConnectionAndDiscoverServices(connectedPeripheral, deviceId, webContents);
|
|
1377
|
+
assertBleActive();
|
|
1378
|
+
deviceCharacteristics.set(deviceId, characteristics);
|
|
1379
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Device ready for communication:', deviceId);
|
|
1380
|
+
}
|
|
1381
|
+
catch (setupError) {
|
|
1382
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection setup failed:', setupError);
|
|
1383
|
+
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1384
|
+
throw setupError;
|
|
1385
|
+
}
|
|
1232
1386
|
});
|
|
1233
1387
|
}
|
|
1234
1388
|
function disconnectDevice(deviceId) {
|
|
1389
|
+
var _a;
|
|
1235
1390
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
1236
|
-
|
|
1391
|
+
if (nativeReleased)
|
|
1392
|
+
return;
|
|
1393
|
+
const pendingConnection = connectingDevices.get(deviceId);
|
|
1394
|
+
const peripheral = (_a = connectedDevices.get(deviceId)) !== null && _a !== void 0 ? _a : pendingConnection === null || pendingConnection === void 0 ? void 0 : pendingConnection.peripheral;
|
|
1237
1395
|
if (!peripheral) {
|
|
1238
1396
|
return;
|
|
1239
1397
|
}
|
|
1398
|
+
pendingConnection === null || pendingConnection === void 0 ? void 0 : pendingConnection.cancel(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, `Device ${deviceId} connection cancelled`));
|
|
1240
1399
|
const disconnectEntry = deviceDisconnectListeners.get(deviceId);
|
|
1241
1400
|
if (disconnectEntry) {
|
|
1242
1401
|
disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
|
|
@@ -1260,6 +1419,8 @@ function disconnectDevice(deviceId) {
|
|
|
1260
1419
|
}
|
|
1261
1420
|
function unsubscribeNotifications(deviceId) {
|
|
1262
1421
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
1422
|
+
if (nativeReleased)
|
|
1423
|
+
return;
|
|
1263
1424
|
const peripheral = connectedDevices.get(deviceId);
|
|
1264
1425
|
const characteristics = deviceCharacteristics.get(deviceId);
|
|
1265
1426
|
if (!peripheral || !characteristics) {
|
|
@@ -1279,7 +1440,8 @@ function unsubscribeNotifications(deviceId) {
|
|
|
1279
1440
|
subscribedDevices.delete(deviceId);
|
|
1280
1441
|
}
|
|
1281
1442
|
finally {
|
|
1282
|
-
|
|
1443
|
+
if (!disposing)
|
|
1444
|
+
subscriptionOperations.set(deviceId, 'idle');
|
|
1283
1445
|
}
|
|
1284
1446
|
});
|
|
1285
1447
|
}
|
|
@@ -1329,10 +1491,12 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1329
1491
|
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1330
1492
|
timeoutBehavior: 'resolve',
|
|
1331
1493
|
});
|
|
1494
|
+
assertBleActive();
|
|
1332
1495
|
yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1333
|
-
timeoutMs:
|
|
1496
|
+
timeoutMs: NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
|
|
1334
1497
|
timeoutBehavior: 'reject',
|
|
1335
1498
|
});
|
|
1499
|
+
assertBleActive();
|
|
1336
1500
|
notifyCharacteristic.on('data', (data) => {
|
|
1337
1501
|
if (!pairedDevices.has(deviceId)) {
|
|
1338
1502
|
pairedDevices.add(deviceId);
|
|
@@ -1345,29 +1509,53 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1345
1509
|
const subscribeStartedAt = Date.now();
|
|
1346
1510
|
try {
|
|
1347
1511
|
yield rebuildAppSubscription(deviceId, notifyCharacteristic);
|
|
1512
|
+
assertBleActive();
|
|
1348
1513
|
subscribedDevices.set(deviceId, true);
|
|
1349
1514
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Notification subscription active', {
|
|
1350
1515
|
deviceId,
|
|
1351
1516
|
ms: Date.now() - subscribeStartedAt,
|
|
1352
1517
|
});
|
|
1353
1518
|
}
|
|
1519
|
+
catch (error) {
|
|
1520
|
+
throw createNobleBleConnectionError(error, 'Notification subscription failed: ');
|
|
1521
|
+
}
|
|
1354
1522
|
finally {
|
|
1355
|
-
|
|
1523
|
+
if (!disposing)
|
|
1524
|
+
subscriptionOperations.set(deviceId, 'idle');
|
|
1356
1525
|
}
|
|
1357
1526
|
});
|
|
1358
1527
|
}
|
|
1359
1528
|
function setupNobleBleHandlers(webContents) {
|
|
1529
|
+
if (disposing)
|
|
1530
|
+
return;
|
|
1531
|
+
let windowDestroyed = false;
|
|
1360
1532
|
try {
|
|
1361
1533
|
logger = require('electron-log');
|
|
1362
1534
|
const { ipcMain } = require('electron');
|
|
1535
|
+
const channels = new Set();
|
|
1536
|
+
removeIpcHandlers = () => channels.forEach(channel => ipcMain.removeHandler(channel));
|
|
1363
1537
|
const handle = (channel, listener) => {
|
|
1538
|
+
channels.add(channel);
|
|
1364
1539
|
ipcMain.removeHandler(channel);
|
|
1365
|
-
ipcMain.handle(channel,
|
|
1540
|
+
ipcMain.handle(channel, (...args) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1541
|
+
try {
|
|
1542
|
+
if (windowCleanup)
|
|
1543
|
+
yield windowCleanup;
|
|
1544
|
+
assertBleActive();
|
|
1545
|
+
if (windowDestroyed) {
|
|
1546
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, 'BLE window destroyed');
|
|
1547
|
+
}
|
|
1548
|
+
return yield Promise.resolve(listener(...args));
|
|
1549
|
+
}
|
|
1550
|
+
catch (error) {
|
|
1551
|
+
return createNobleBleIpcErrorResponse(error);
|
|
1552
|
+
}
|
|
1553
|
+
}));
|
|
1366
1554
|
};
|
|
1367
1555
|
safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
|
|
1368
1556
|
handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, () => index.__awaiter(this, void 0, void 0, function* () {
|
|
1369
1557
|
try {
|
|
1370
|
-
const devices = yield enumerateDevices();
|
|
1558
|
+
const devices = yield enumerateDevices(() => windowDestroyed);
|
|
1371
1559
|
safeLog(logger, 'debug', 'Enumeration completed', {
|
|
1372
1560
|
count: devices.length,
|
|
1373
1561
|
devices: devices.map(device => ({ id: device.id, name: device.name })),
|
|
@@ -1459,13 +1647,29 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1459
1647
|
}
|
|
1460
1648
|
}));
|
|
1461
1649
|
webContents.on('destroyed', () => {
|
|
1650
|
+
windowDestroyed = true;
|
|
1651
|
+
if (disposing)
|
|
1652
|
+
return;
|
|
1462
1653
|
safeLog(logger, 'info', 'Cleaning up Noble BLE handlers');
|
|
1463
|
-
|
|
1654
|
+
const previousCleanup = windowCleanup;
|
|
1655
|
+
const enumerations = Array.from(pendingEnumerations, cancel => cancel());
|
|
1656
|
+
windowCleanup = (() => index.__awaiter(this, void 0, void 0, function* () {
|
|
1657
|
+
if (previousCleanup)
|
|
1658
|
+
yield previousCleanup;
|
|
1659
|
+
yield Promise.allSettled(enumerations);
|
|
1660
|
+
if (disposing)
|
|
1661
|
+
return;
|
|
1464
1662
|
const deviceIds = Array.from(connectedDevices.keys());
|
|
1465
1663
|
for (const deviceId of deviceIds) {
|
|
1664
|
+
if (disposing)
|
|
1665
|
+
return;
|
|
1466
1666
|
yield unsubscribeNotifications(deviceId).catch(() => undefined);
|
|
1667
|
+
if (disposing)
|
|
1668
|
+
return;
|
|
1467
1669
|
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1468
1670
|
}
|
|
1671
|
+
if (disposing)
|
|
1672
|
+
return;
|
|
1469
1673
|
yield stopScanning().catch(() => undefined);
|
|
1470
1674
|
cleanupNobleListeners();
|
|
1471
1675
|
discoveredDevices.clear();
|
|
@@ -1481,7 +1685,77 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1481
1685
|
throw error;
|
|
1482
1686
|
}
|
|
1483
1687
|
}
|
|
1688
|
+
function disposeNobleBleSupport(releaseNoble = instance => instance.stop()) {
|
|
1689
|
+
if (disposePromise)
|
|
1690
|
+
return disposePromise;
|
|
1691
|
+
disposing = true;
|
|
1692
|
+
removeIpcHandlers === null || removeIpcHandlers === void 0 ? void 0 : removeIpcHandlers();
|
|
1693
|
+
const instance = noble;
|
|
1694
|
+
const deviceIds = new Set([...connectedDevices.keys(), ...connectingDevices.keys()]);
|
|
1695
|
+
const pendingPeripherals = Array.from(connectingDevices.values(), pending => pending.peripheral);
|
|
1696
|
+
for (const cancel of pendingCancellations)
|
|
1697
|
+
cancel();
|
|
1698
|
+
for (const id of idleDisconnectTimers.keys())
|
|
1699
|
+
clearIdleDisconnect(id);
|
|
1700
|
+
for (const pending of connectingDevices.values()) {
|
|
1701
|
+
pending.cancel(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, 'Noble BLE is shutting down'));
|
|
1702
|
+
}
|
|
1703
|
+
const connections = Array.from(nativeConnections);
|
|
1704
|
+
for (const connection of connections) {
|
|
1705
|
+
try {
|
|
1706
|
+
connection.cancel();
|
|
1707
|
+
}
|
|
1708
|
+
catch (error) {
|
|
1709
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Native connect cancellation failed', error);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
let timeout;
|
|
1713
|
+
disposePromise = (() => index.__awaiter(this, void 0, void 0, function* () {
|
|
1714
|
+
try {
|
|
1715
|
+
yield Promise.race([
|
|
1716
|
+
Promise.allSettled([
|
|
1717
|
+
windowCleanup,
|
|
1718
|
+
...connections.map(connection => connection.settled),
|
|
1719
|
+
stopScanning(),
|
|
1720
|
+
...pendingPeripherals.map(peripheral => runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1721
|
+
timeoutMs: BLE_DISCONNECT_CONFIRM_TIMEOUT_MS,
|
|
1722
|
+
timeoutBehavior: 'resolve',
|
|
1723
|
+
})),
|
|
1724
|
+
...Array.from(deviceIds, (id) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1725
|
+
yield unsubscribeNotifications(id).catch(() => undefined);
|
|
1726
|
+
yield disconnectDevice(id).catch(() => undefined);
|
|
1727
|
+
})),
|
|
1728
|
+
]),
|
|
1729
|
+
new Promise(resolve => {
|
|
1730
|
+
timeout = setTimeout(() => {
|
|
1731
|
+
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Process dispose timed out; releasing native manager');
|
|
1732
|
+
resolve();
|
|
1733
|
+
}, 3500);
|
|
1734
|
+
}),
|
|
1735
|
+
]);
|
|
1736
|
+
}
|
|
1737
|
+
finally {
|
|
1738
|
+
clearTimeout(timeout);
|
|
1739
|
+
nativeReleased = true;
|
|
1740
|
+
cleanupNobleListeners();
|
|
1741
|
+
if (instance && persistentStateListener) {
|
|
1742
|
+
instance.removeListener('stateChange', persistentStateListener);
|
|
1743
|
+
persistentStateListener = null;
|
|
1744
|
+
}
|
|
1745
|
+
for (const id of deviceIds)
|
|
1746
|
+
cleanupDevice(id);
|
|
1747
|
+
discoveredDevices.clear();
|
|
1748
|
+
directConnectCooldownUntil.clear();
|
|
1749
|
+
if (instance)
|
|
1750
|
+
releaseNoble(instance);
|
|
1751
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Process dispose completed');
|
|
1752
|
+
}
|
|
1753
|
+
}))();
|
|
1754
|
+
return disposePromise;
|
|
1755
|
+
}
|
|
1484
1756
|
|
|
1485
1757
|
exports.createNobleBleConnectionError = createNobleBleConnectionError;
|
|
1758
|
+
exports.createNobleBleIpcErrorResponse = createNobleBleIpcErrorResponse;
|
|
1759
|
+
exports.disposeNobleBleSupport = disposeNobleBleSupport;
|
|
1486
1760
|
exports.resolveNobleBleWritePacingDelay = resolveNobleBleWritePacingDelay;
|
|
1487
1761
|
exports.setupNobleBleHandlers = setupNobleBleHandlers;
|