@onekeyfe/hd-transport-electron 1.2.0-alpha.161 → 1.2.0-alpha.162
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-fea7f7d5.js → index-b37d926c.js} +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-e87ba8bc.js → noble-ble-handler-e8b87173.js} +19 -23
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/dist/types/noble-extended.d.ts +0 -1
- package/dist/types/noble-extended.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/noble-ble-handler.ts +25 -65
- package/src/types/noble-extended.ts +0 -1
|
@@ -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-e8b87173.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
package/dist/index.d.ts
CHANGED
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-b37d926c.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -116,8 +116,7 @@ const DEVICE_SCAN_TIMEOUT = 5000;
|
|
|
116
116
|
const DEVICE_CHECK_INTERVAL = 500;
|
|
117
117
|
const SERVICE_DISCOVERY_TIMEOUT = 10000;
|
|
118
118
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
119
|
-
const
|
|
120
|
-
const BLE_IDLE_DISCONNECT_MS = 20000;
|
|
119
|
+
const BLE_IDLE_DISCONNECT_MS = 3 * 60000;
|
|
121
120
|
const BLE_BUSY_BACKSTOP_MS = 10 * 60000;
|
|
122
121
|
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
123
122
|
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
@@ -243,7 +242,6 @@ function initializeNoble() {
|
|
|
243
242
|
try {
|
|
244
243
|
noble = require('@stoprocent/noble');
|
|
245
244
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Noble library loaded');
|
|
246
|
-
setupPersistentStateListener();
|
|
247
245
|
yield new Promise((resolve, reject) => {
|
|
248
246
|
if (!noble) {
|
|
249
247
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not initialized'));
|
|
@@ -253,6 +251,7 @@ function initializeNoble() {
|
|
|
253
251
|
resolve();
|
|
254
252
|
return;
|
|
255
253
|
}
|
|
254
|
+
setupPersistentStateListener();
|
|
256
255
|
const timeout = setTimeout(() => {
|
|
257
256
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout'));
|
|
258
257
|
}, BLUETOOTH_INIT_TIMEOUT);
|
|
@@ -337,14 +336,7 @@ function armIdleDisconnect(deviceId, ms = BLE_IDLE_DISCONNECT_MS, reason = 'idle
|
|
|
337
336
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
|
|
338
337
|
const peripheral = connectedDevices.get(deviceId);
|
|
339
338
|
const deviceName = ((_a = peripheral === null || peripheral === void 0 ? void 0 : peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
340
|
-
const pending =
|
|
341
|
-
.catch(error => {
|
|
342
|
-
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Keep-alive unsubscribe failed, disconnecting anyway', {
|
|
343
|
-
deviceId,
|
|
344
|
-
error: error instanceof Error ? error.message : String(error),
|
|
345
|
-
});
|
|
346
|
-
})
|
|
347
|
-
.then(() => disconnectDevice(deviceId))
|
|
339
|
+
const pending = disconnectDevice(deviceId)
|
|
348
340
|
.then(() => {
|
|
349
341
|
broadcastToAllWebContents(hdShared.EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, {
|
|
350
342
|
id: deviceId,
|
|
@@ -417,7 +409,6 @@ function handleDeviceDisconnect(deviceId, webContents) {
|
|
|
417
409
|
});
|
|
418
410
|
cleanupDevice(deviceId, webContents, {
|
|
419
411
|
cleanupConnection: true,
|
|
420
|
-
cleanupDiscoveredCache: true,
|
|
421
412
|
sendDisconnectEvent: true,
|
|
422
413
|
cancelOperations: true,
|
|
423
414
|
reason: 'auto-disconnect',
|
|
@@ -975,18 +966,23 @@ function discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId) {
|
|
|
975
966
|
}
|
|
976
967
|
function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
|
|
977
968
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
969
|
+
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
978
970
|
try {
|
|
979
|
-
yield
|
|
971
|
+
return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
980
972
|
}
|
|
981
|
-
catch (
|
|
982
|
-
logger === null || logger === void 0 ? void 0 : logger.
|
|
973
|
+
catch (initialError) {
|
|
974
|
+
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Direct service discovery failed, retrying after reconnect', {
|
|
975
|
+
deviceId,
|
|
976
|
+
error: initialError,
|
|
977
|
+
});
|
|
983
978
|
}
|
|
979
|
+
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
984
980
|
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
985
981
|
try {
|
|
986
982
|
return yield discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
987
983
|
}
|
|
988
|
-
catch (
|
|
989
|
-
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed, attempting fresh scan...',
|
|
984
|
+
catch (reconnectError) {
|
|
985
|
+
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Service discovery failed after reconnect, attempting fresh scan...', reconnectError);
|
|
990
986
|
return freshScanAndDiscover(deviceId, webContents);
|
|
991
987
|
}
|
|
992
988
|
});
|
|
@@ -1180,15 +1176,11 @@ function disconnectDevice(deviceId) {
|
|
|
1180
1176
|
deviceDisconnectListeners.delete(deviceId);
|
|
1181
1177
|
}
|
|
1182
1178
|
yield runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1183
|
-
timeoutMs:
|
|
1179
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1184
1180
|
timeoutBehavior: 'resolve',
|
|
1185
1181
|
});
|
|
1186
|
-
if (peripheral.state === 'connected') {
|
|
1187
|
-
logger === null || logger === void 0 ? void 0 : logger.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
|
|
1188
|
-
}
|
|
1189
1182
|
cleanupDevice(deviceId, undefined, {
|
|
1190
1183
|
cleanupConnection: true,
|
|
1191
|
-
cleanupDiscoveredCache: true,
|
|
1192
1184
|
sendDisconnectEvent: false,
|
|
1193
1185
|
cancelOperations: true,
|
|
1194
1186
|
reason: 'manual-disconnect',
|
|
@@ -1399,6 +1391,10 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1399
1391
|
yield disconnectDevice(deviceId).catch(() => undefined);
|
|
1400
1392
|
}
|
|
1401
1393
|
yield stopScanning().catch(() => undefined);
|
|
1394
|
+
if (noble && persistentStateListener) {
|
|
1395
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1396
|
+
persistentStateListener = null;
|
|
1397
|
+
}
|
|
1402
1398
|
cleanupNobleListeners();
|
|
1403
1399
|
discoveredDevices.clear();
|
|
1404
1400
|
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AA0EhE,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AA2mDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAgMpE"}
|
|
@@ -22,7 +22,6 @@ export interface NobleModule {
|
|
|
22
22
|
export interface Logger {
|
|
23
23
|
info(message: string, ...args: any[]): void;
|
|
24
24
|
debug(message: string, ...args: any[]): void;
|
|
25
|
-
warn(message: string, ...args: any[]): void;
|
|
26
25
|
error(message: string, ...args: any[]): void;
|
|
27
26
|
}
|
|
28
27
|
export declare function safeLog(logger: Logger | null, level: 'info' | 'debug' | 'error', message: string, ...args: any[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-extended.d.ts","sourceRoot":"","sources":["../../src/types/noble-extended.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;CACxB;AAGD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CACX,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC1C,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;CACrF;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,
|
|
1
|
+
{"version":3,"file":"noble-extended.d.ts","sourceRoot":"","sources":["../../src/types/noble-extended.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,cAAc,CAAC;CACxB;AAGD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CACX,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC1C,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC9E,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;CACrF;AAGD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC9C;AAGD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,IAAI,CAMN"}
|
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.162",
|
|
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.162",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.162",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.162",
|
|
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": "f4aa654b350931d68ed9ba3f77c4cc8faa161218"
|
|
40
40
|
}
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -90,18 +90,8 @@ const DEVICE_SCAN_TIMEOUT = 5000; // 5 seconds for device scanning
|
|
|
90
90
|
const DEVICE_CHECK_INTERVAL = 500; // 500ms interval for periodic device checks
|
|
91
91
|
const SERVICE_DISCOVERY_TIMEOUT = 10000; // 10 seconds for service discovery
|
|
92
92
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
93
|
-
// A physical teardown must actually reach the OS before the device can return
|
|
94
|
-
// to a clean state; 250ms routinely declared success while CoreBluetooth was
|
|
95
|
-
// still disconnecting, leaving no trace when the teardown never completed.
|
|
96
|
-
const BLE_DISCONNECT_CONFIRM_TIMEOUT_MS = 3000;
|
|
97
93
|
// Renderer release is logical only; this timer physically frees the device.
|
|
98
|
-
|
|
99
|
-
// after sitting idle for minutes (field logs 2026-08-19: every deaf window
|
|
100
|
-
// followed a 3-minute-idle disconnect, while disconnects right after traffic
|
|
101
|
-
// have never produced one across 6.5.0's per-call teardown history). A hot
|
|
102
|
-
// disconnect ~20s after the last operation stays inside the proven-safe
|
|
103
|
-
// pattern and also shrinks the window in which phones cannot see the device.
|
|
104
|
-
const BLE_IDLE_DISCONNECT_MS = 20_000;
|
|
94
|
+
const BLE_IDLE_DISCONNECT_MS = 3 * 60_000;
|
|
105
95
|
// Ceiling while a call is in flight: no outstanding write, but not forever.
|
|
106
96
|
const BLE_BUSY_BACKSTOP_MS = 10 * 60_000;
|
|
107
97
|
|
|
@@ -267,11 +257,6 @@ async function initializeNoble(): Promise<void> {
|
|
|
267
257
|
noble = require('@stoprocent/noble') as NobleModule;
|
|
268
258
|
logger?.info('[NobleBLE] Noble library loaded');
|
|
269
259
|
|
|
270
|
-
// Register the process-lifetime state listener before any early return:
|
|
271
|
-
// the poweredOn fast path below would otherwise skip it for the whole
|
|
272
|
-
// session, leaving poweredOff cache/state reconciliation dead.
|
|
273
|
-
setupPersistentStateListener();
|
|
274
|
-
|
|
275
260
|
// Wait for Bluetooth to be ready
|
|
276
261
|
await new Promise<void>((resolve, reject) => {
|
|
277
262
|
if (!noble) {
|
|
@@ -284,6 +269,9 @@ async function initializeNoble(): Promise<void> {
|
|
|
284
269
|
return;
|
|
285
270
|
}
|
|
286
271
|
|
|
272
|
+
// Setup persistent state listener before initialization
|
|
273
|
+
setupPersistentStateListener();
|
|
274
|
+
|
|
287
275
|
const timeout = setTimeout(() => {
|
|
288
276
|
reject(
|
|
289
277
|
ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Bluetooth initialization timeout')
|
|
@@ -410,21 +398,7 @@ function armIdleDisconnect(
|
|
|
410
398
|
logger?.info('[NobleBLE] Keep-alive timeout, disconnecting device', { deviceId, reason });
|
|
411
399
|
const peripheral = connectedDevices.get(deviceId);
|
|
412
400
|
const deviceName = peripheral?.advertisement?.localName || 'Unknown Device';
|
|
413
|
-
|
|
414
|
-
// teardown path: the 1S leaves its notify session half-open when the
|
|
415
|
-
// link drops without an unsubscribe and then ignores application
|
|
416
|
-
// protocol traffic on NEW links for tens of minutes (field log
|
|
417
|
-
// 2026-08-19: the lone unsubscribe-skipping idle teardown caused a
|
|
418
|
-
// 6-attempt reconnect loop; unsubscribe-first teardowns reconnected
|
|
419
|
-
// instantly).
|
|
420
|
-
const pending = unsubscribeNotifications(deviceId)
|
|
421
|
-
.catch(error => {
|
|
422
|
-
logger?.warn('[NobleBLE] Keep-alive unsubscribe failed, disconnecting anyway', {
|
|
423
|
-
deviceId,
|
|
424
|
-
error: error instanceof Error ? error.message : String(error),
|
|
425
|
-
});
|
|
426
|
-
})
|
|
427
|
-
.then(() => disconnectDevice(deviceId))
|
|
401
|
+
const pending = disconnectDevice(deviceId)
|
|
428
402
|
.then(() => {
|
|
429
403
|
// A call is still in flight here; it must reject, not hang.
|
|
430
404
|
// Both 'idle' and 'busy-backstop' report IdleKeepAlive on purpose:
|
|
@@ -534,9 +508,6 @@ function handleDeviceDisconnect(deviceId: string, webContents: WebContents): voi
|
|
|
534
508
|
|
|
535
509
|
cleanupDevice(deviceId, webContents, {
|
|
536
510
|
cleanupConnection: true,
|
|
537
|
-
// Same stale-object hazard as manual disconnect: an externally dropped
|
|
538
|
-
// link invalidates the cached peripheral for the next reconnect.
|
|
539
|
-
cleanupDiscoveredCache: true,
|
|
540
511
|
sendDisconnectEvent: true,
|
|
541
512
|
cancelOperations: true,
|
|
542
513
|
reason: 'auto-disconnect',
|
|
@@ -1334,28 +1305,26 @@ async function setupConnectionAndDiscoverServices(
|
|
|
1334
1305
|
deviceId: string,
|
|
1335
1306
|
webContents: WebContents
|
|
1336
1307
|
): Promise<CharacteristicPair> {
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
// (control log 2026-08-20: 16/16 links answered within ~1s, including after
|
|
1340
|
-
// a 15-minute idle). Demoting it to a discovery-failure fallback removed the
|
|
1341
|
-
// reset entirely for this device, because discovery always succeeds: the link
|
|
1342
|
-
// comes up, GATT resolves from cache, and the device then answers nothing on
|
|
1343
|
-
// a session it no longer serves. Costs ~1.3s per cold setup; a kept-alive
|
|
1344
|
-
// link with an intact subscription returns before reaching here, so reuse
|
|
1345
|
-
// inside a workflow is unaffected.
|
|
1308
|
+
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
1309
|
+
|
|
1346
1310
|
try {
|
|
1347
|
-
await
|
|
1348
|
-
} catch (
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1311
|
+
return await discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
1312
|
+
} catch (initialError) {
|
|
1313
|
+
logger?.info('[NobleBLE] Direct service discovery failed, retrying after reconnect', {
|
|
1314
|
+
deviceId,
|
|
1315
|
+
error: initialError,
|
|
1316
|
+
});
|
|
1352
1317
|
}
|
|
1353
|
-
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
1354
1318
|
|
|
1319
|
+
await forceReconnectPeripheral(peripheral, deviceId);
|
|
1320
|
+
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
1355
1321
|
try {
|
|
1356
1322
|
return await discoverServicesAndCharacteristicsWithRetry(peripheral, deviceId);
|
|
1357
|
-
} catch (
|
|
1358
|
-
logger?.error(
|
|
1323
|
+
} catch (reconnectError) {
|
|
1324
|
+
logger?.error(
|
|
1325
|
+
'[NobleBLE] Service discovery failed after reconnect, attempting fresh scan...',
|
|
1326
|
+
reconnectError
|
|
1327
|
+
);
|
|
1359
1328
|
return freshScanAndDiscover(deviceId, webContents);
|
|
1360
1329
|
}
|
|
1361
1330
|
}
|
|
@@ -1628,18 +1597,11 @@ async function disconnectDevice(deviceId: string): Promise<void> {
|
|
|
1628
1597
|
}
|
|
1629
1598
|
|
|
1630
1599
|
await runBleCallbackOperation(callback => peripheral.disconnect(() => callback()), {
|
|
1631
|
-
timeoutMs:
|
|
1600
|
+
timeoutMs: BLE_CLEANUP_TIMEOUT,
|
|
1632
1601
|
timeoutBehavior: 'resolve',
|
|
1633
1602
|
});
|
|
1634
|
-
if (peripheral.state === 'connected') {
|
|
1635
|
-
logger?.warn('[NobleBLE] Physical disconnect did not confirm in time', { deviceId });
|
|
1636
|
-
}
|
|
1637
1603
|
cleanupDevice(deviceId, undefined, {
|
|
1638
1604
|
cleanupConnection: true,
|
|
1639
|
-
// macOS returns zero GATT services when a previously-disconnected
|
|
1640
|
-
// peripheral object is reconnected; drop the discovery cache so the next
|
|
1641
|
-
// connect resolves a fresh peripheral (direct connect by id, or scan).
|
|
1642
|
-
cleanupDiscoveredCache: true,
|
|
1643
1605
|
sendDisconnectEvent: false,
|
|
1644
1606
|
cancelOperations: true,
|
|
1645
1607
|
reason: 'manual-disconnect',
|
|
@@ -1965,12 +1927,10 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
|
|
|
1965
1927
|
}
|
|
1966
1928
|
|
|
1967
1929
|
await stopScanning().catch(() => undefined);
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
// initializeNoble early-returns once noble is loaded). The null-guard
|
|
1973
|
-
// in setupPersistentStateListener keeps it deduped to one instance.
|
|
1930
|
+
if (noble && persistentStateListener) {
|
|
1931
|
+
noble.removeListener('stateChange', persistentStateListener);
|
|
1932
|
+
persistentStateListener = null;
|
|
1933
|
+
}
|
|
1974
1934
|
cleanupNobleListeners();
|
|
1975
1935
|
discoveredDevices.clear();
|
|
1976
1936
|
safeLog(logger, 'info', 'Noble BLE cleanup completed');
|