@onekeyfe/hd-transport-electron 1.2.2-alpha.11 → 1.2.2-alpha.13
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-00297050.js → index-ef6298f9.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-95c5cf0d.js → noble-ble-handler-de8d60e9.js} +27 -24
- package/dist/noble-ble-handler.d.ts +1 -0
- 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/package.json +5 -5
- package/src/__tests__/noble-ble-handler.test.ts +58 -69
- package/src/noble-ble-handler.ts +34 -33
- package/src/noble-ble-timeouts.ts +1 -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-de8d60e9.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-ef6298f9.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -96,10 +96,20 @@ 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
|
+
function createNobleBleConnectionError(error, messagePrefix = '') {
|
|
104
|
+
const errorMessage = error.message;
|
|
105
|
+
if (hdShared.isBleStaleBondErrorText(errorMessage)) {
|
|
106
|
+
const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
|
|
107
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid, `${hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`, {
|
|
108
|
+
nativeErrorMessage,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
|
|
112
|
+
}
|
|
103
113
|
const bluetoothState = {
|
|
104
114
|
available: false,
|
|
105
115
|
unsupported: false,
|
|
@@ -924,9 +934,14 @@ function forceReconnectPeripheral(peripheral, deviceId) {
|
|
|
924
934
|
callback();
|
|
925
935
|
}), { timeoutMs: BLE_CLEANUP_TIMEOUT, timeoutBehavior: 'resolve' });
|
|
926
936
|
}
|
|
927
|
-
yield
|
|
928
|
-
|
|
929
|
-
|
|
937
|
+
yield new Promise((resolve, reject) => {
|
|
938
|
+
peripheral.connect(error => {
|
|
939
|
+
if (error) {
|
|
940
|
+
reject(createNobleBleConnectionError(error));
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
resolve();
|
|
944
|
+
});
|
|
930
945
|
});
|
|
931
946
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Force reconnect successful');
|
|
932
947
|
connectedDevices.set(deviceId, peripheral);
|
|
@@ -949,7 +964,7 @@ function freshScanAndDiscover(deviceId, webContents) {
|
|
|
949
964
|
yield new Promise((resolve, reject) => {
|
|
950
965
|
freshPeripheral.connect((error) => {
|
|
951
966
|
if (error) {
|
|
952
|
-
reject(
|
|
967
|
+
reject(createNobleBleConnectionError(error, 'Fresh peripheral connection failed: '));
|
|
953
968
|
}
|
|
954
969
|
else {
|
|
955
970
|
connectedDevices.set(deviceId, freshPeripheral);
|
|
@@ -1010,6 +1025,9 @@ function setupConnectionAndDiscoverServices(peripheral, deviceId, webContents) {
|
|
|
1010
1025
|
yield forceReconnectPeripheral(peripheral, deviceId);
|
|
1011
1026
|
}
|
|
1012
1027
|
catch (resetError) {
|
|
1028
|
+
if (hdShared.isBleStaleBondHardwareError(resetError)) {
|
|
1029
|
+
throw resetError;
|
|
1030
|
+
}
|
|
1013
1031
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
|
|
1014
1032
|
}
|
|
1015
1033
|
setupDisconnectListener(peripheral, deviceId, webContents);
|
|
@@ -1177,27 +1195,11 @@ function connectDevice(deviceId, webContents) {
|
|
|
1177
1195
|
return;
|
|
1178
1196
|
}
|
|
1179
1197
|
return new Promise((resolve, reject) => {
|
|
1180
|
-
let connectionTimedOut = false;
|
|
1181
|
-
const timeout = setTimeout(() => {
|
|
1182
|
-
connectionTimedOut = true;
|
|
1183
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'Connection timeout'));
|
|
1184
|
-
}, NOBLE_BLE_CONNECTION_TIMEOUT_MS);
|
|
1185
1198
|
const connectedPeripheral = peripheral;
|
|
1186
1199
|
connectedPeripheral.connect((error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
1187
|
-
clearTimeout(timeout);
|
|
1188
|
-
if (connectionTimedOut) {
|
|
1189
|
-
if (!error) {
|
|
1190
|
-
try {
|
|
1191
|
-
connectedPeripheral.disconnect(() => undefined);
|
|
1192
|
-
}
|
|
1193
|
-
catch (_a) {
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
return;
|
|
1197
|
-
}
|
|
1198
1200
|
if (error) {
|
|
1199
1201
|
logger === null || logger === void 0 ? void 0 : logger.error('[NobleBLE] Connection failed:', error);
|
|
1200
|
-
reject(
|
|
1202
|
+
reject(createNobleBleConnectionError(error));
|
|
1201
1203
|
return;
|
|
1202
1204
|
}
|
|
1203
1205
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Connected to device:', deviceId);
|
|
@@ -1317,7 +1319,7 @@ function subscribeNotifications(deviceId, callback) {
|
|
|
1317
1319
|
timeoutBehavior: 'resolve',
|
|
1318
1320
|
});
|
|
1319
1321
|
yield runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1320
|
-
timeoutMs:
|
|
1322
|
+
timeoutMs: NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
|
|
1321
1323
|
timeoutBehavior: 'reject',
|
|
1322
1324
|
});
|
|
1323
1325
|
notifyCharacteristic.on('data', (data) => {
|
|
@@ -1469,5 +1471,6 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1469
1471
|
}
|
|
1470
1472
|
}
|
|
1471
1473
|
|
|
1474
|
+
exports.createNobleBleConnectionError = createNobleBleConnectionError;
|
|
1472
1475
|
exports.resolveNobleBleWritePacingDelay = resolveNobleBleWritePacingDelay;
|
|
1473
1476
|
exports.setupNobleBleHandlers = setupNobleBleHandlers;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { WebContents } from 'electron';
|
|
2
2
|
import type { NobleBleWriteOptions } from './types/desktop-api';
|
|
3
|
+
export declare function createNobleBleConnectionError(error: Error, messagePrefix?: string): import("@onekeyfe/hd-shared").HardwareError;
|
|
3
4
|
export declare function resolveNobleBleWritePacingDelay(options?: NobleBleWriteOptions): number;
|
|
4
5
|
export declare function setupNobleBleHandlers(webContents: WebContents): void;
|
|
5
6
|
//# sourceMappingURL=noble-ble-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAOhE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,SAAK,+CAc7E;AA+ED,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAuuDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkMpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM
|
|
1
|
+
{"version":3,"file":"noble-ble-timeouts.d.ts","sourceRoot":"","sources":["../src/noble-ble-timeouts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kCAAkC,OAAQ,CAAC;AACxD,eAAO,MAAM,8BAA8B,QAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-electron",
|
|
3
|
-
"version": "1.2.2-alpha.
|
|
3
|
+
"version": "1.2.2-alpha.13",
|
|
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.2-alpha.
|
|
29
|
-
"@onekeyfe/hd-shared": "1.2.2-alpha.
|
|
30
|
-
"@onekeyfe/hd-transport": "1.2.2-alpha.
|
|
28
|
+
"@onekeyfe/hd-core": "1.2.2-alpha.13",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.13",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.13",
|
|
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": "c901cdc6b474d015c7f50390fc5dc3db0ca4fbdb"
|
|
40
40
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { EOneKeyBleMessageKeys } from '@onekeyfe/hd-shared';
|
|
2
|
+
import { EOneKeyBleMessageKeys, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
|
|
6
6
|
NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS,
|
|
7
7
|
} from '../noble-ble-timeouts';
|
|
8
8
|
|
|
@@ -26,9 +26,40 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
26
26
|
jest.clearAllMocks();
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
test('
|
|
29
|
+
test('bounds targeted scans and subscription callbacks independently', () => {
|
|
30
30
|
expect(NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS).toBe(5_000);
|
|
31
|
-
expect(
|
|
31
|
+
expect(NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS).toBe(10_000);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('maps macOS stale pairing failures without reclassifying generic connection errors', async () => {
|
|
35
|
+
const { createNobleBleConnectionError } = await import('../noble-ble-handler');
|
|
36
|
+
|
|
37
|
+
const staleBondError = createNobleBleConnectionError(
|
|
38
|
+
new Error('CBErrorDomain:14 Peer removed pairing information on the device side')
|
|
39
|
+
);
|
|
40
|
+
expect(staleBondError).toMatchObject({
|
|
41
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
42
|
+
params: {
|
|
43
|
+
nativeErrorMessage: 'CBErrorDomain:14 Peer removed pairing information on the device side',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
expect(staleBondError.message).toContain(
|
|
47
|
+
'CBErrorDomain:14 Peer removed pairing information on the device side'
|
|
48
|
+
);
|
|
49
|
+
expect(createNobleBleConnectionError(new Error('Encryption is insufficient'))).toMatchObject({
|
|
50
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
51
|
+
params: {
|
|
52
|
+
nativeErrorMessage: 'Encryption is insufficient',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
expect(
|
|
56
|
+
createNobleBleConnectionError(new Error('CBATTErrorDomain:14 localized native message'))
|
|
57
|
+
).toMatchObject({
|
|
58
|
+
errorCode: HardwareErrorCode.BleBondInvalid,
|
|
59
|
+
});
|
|
60
|
+
expect(createNobleBleConnectionError(new Error('connection failed'))).toMatchObject({
|
|
61
|
+
errorCode: HardwareErrorCode.BleConnectedError,
|
|
62
|
+
});
|
|
32
63
|
});
|
|
33
64
|
|
|
34
65
|
test('keeps safe pacing by default and allows an explicit high-throughput bypass', async () => {
|
|
@@ -180,75 +211,33 @@ describe('Electron Noble BLE device discovery', () => {
|
|
|
180
211
|
expect(peripheral.connect).toHaveBeenCalledTimes(1);
|
|
181
212
|
});
|
|
182
213
|
|
|
183
|
-
test('
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
handle: jest.fn((channel: string, handler: IpcHandler) => {
|
|
189
|
-
handlers.set(channel, handler);
|
|
190
|
-
}),
|
|
191
|
-
removeHandler: jest.fn((channel: string) => {
|
|
192
|
-
handlers.delete(channel);
|
|
193
|
-
}),
|
|
194
|
-
};
|
|
195
|
-
const noble = new EventEmitter() as EventEmitter & {
|
|
196
|
-
state: string;
|
|
197
|
-
startScanning: jest.Mock;
|
|
198
|
-
stopScanning: jest.Mock;
|
|
199
|
-
};
|
|
200
|
-
let connectCallback: ((error?: Error) => void) | undefined;
|
|
201
|
-
let resolveConnectStarted = () => undefined;
|
|
202
|
-
const connectStarted = new Promise<void>(resolve => {
|
|
203
|
-
resolveConnectStarted = resolve;
|
|
214
|
+
test('settles a pending Noble connect with the native disconnect error', () => {
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
|
|
216
|
+
const Noble = require('@stoprocent/noble/lib/noble');
|
|
217
|
+
const bindings = Object.assign(new EventEmitter(), {
|
|
218
|
+
connect: jest.fn(),
|
|
204
219
|
});
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
220
|
+
const noble = new Noble(bindings);
|
|
221
|
+
noble._registerListeners();
|
|
222
|
+
const peripheral = noble._createPeripheral(
|
|
223
|
+
'aabbccdd',
|
|
224
|
+
'',
|
|
225
|
+
'unknown',
|
|
226
|
+
true,
|
|
227
|
+
{ localName: 'Pro2 A1B2', serviceUuids: ['0001'] },
|
|
228
|
+
-50,
|
|
229
|
+
false
|
|
215
230
|
);
|
|
216
|
-
|
|
217
|
-
noble.startScanning = jest.fn((_services, _duplicates, callback) => {
|
|
218
|
-
callback?.();
|
|
219
|
-
noble.emit('discover', peripheral);
|
|
220
|
-
});
|
|
221
|
-
noble.stopScanning = jest.fn(callback => callback?.());
|
|
222
|
-
|
|
223
|
-
jest.doMock('@stoprocent/noble', () => noble);
|
|
224
|
-
jest.doMock('electron', () => ({ ipcMain }));
|
|
225
|
-
jest.doMock('electron-log', () => ({
|
|
226
|
-
info: jest.fn(),
|
|
227
|
-
debug: jest.fn(),
|
|
228
|
-
error: jest.fn(),
|
|
229
|
-
}));
|
|
231
|
+
const connectCallback = jest.fn();
|
|
230
232
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const connect = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_CONNECT);
|
|
238
|
-
if (!connect) {
|
|
239
|
-
throw new Error('Electron Noble BLE connect handler was not registered');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const connectPromise = Promise.resolve(connect(undefined, 'slow-device'));
|
|
243
|
-
await connectStarted;
|
|
244
|
-
expect(peripheral.connect).toHaveBeenCalledTimes(1);
|
|
245
|
-
|
|
246
|
-
jest.advanceTimersByTime(NOBLE_BLE_CONNECTION_TIMEOUT_MS);
|
|
247
|
-
await expect(connectPromise).rejects.toThrow('Connection timeout');
|
|
233
|
+
peripheral.connect(connectCallback);
|
|
234
|
+
const nativeError = new Error(
|
|
235
|
+
'CBATTErrorDomain:14 Peer removed pairing information on the device side'
|
|
236
|
+
);
|
|
237
|
+
bindings.emit('disconnect', 'aabbccdd', nativeError);
|
|
248
238
|
|
|
249
|
-
connectCallback
|
|
250
|
-
|
|
251
|
-
expect(peripheral.disconnect).toHaveBeenCalledTimes(1);
|
|
239
|
+
expect(connectCallback).toHaveBeenCalledWith(nativeError);
|
|
240
|
+
expect(peripheral.state).toBe('disconnected');
|
|
252
241
|
});
|
|
253
242
|
|
|
254
243
|
test('enumerates a Pro2 communication advertisement after Find My changes its name', async () => {
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -10,11 +10,14 @@ import {
|
|
|
10
10
|
EOneKeyBleMessageKeys,
|
|
11
11
|
ERRORS,
|
|
12
12
|
HardwareErrorCode,
|
|
13
|
+
HardwareErrorCodeMessage,
|
|
13
14
|
ONEKEY_NOTIFY_CHARACTERISTIC_UUID,
|
|
14
15
|
ONEKEY_SERVICE_UUID,
|
|
15
16
|
ONEKEY_WRITE_CHARACTERISTIC_UUID,
|
|
16
17
|
createKnownBleUuidAliases,
|
|
17
18
|
hasOnekeyCommunicationService,
|
|
19
|
+
isBleStaleBondErrorText,
|
|
20
|
+
isBleStaleBondHardwareError,
|
|
18
21
|
isOnekeyBluetoothDevice,
|
|
19
22
|
isPro2FamilyBleName,
|
|
20
23
|
matchesKnownBleUuid,
|
|
@@ -26,7 +29,7 @@ import { resolveBlePacketCapacity, resolveNobleAttMtu } from './ble-packet-capac
|
|
|
26
29
|
import { safeLog } from './types/noble-extended';
|
|
27
30
|
import { runBleCallbackOperation, softRefreshSubscription } from './ble-ops';
|
|
28
31
|
import {
|
|
29
|
-
|
|
32
|
+
NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
|
|
30
33
|
NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS,
|
|
31
34
|
} from './noble-ble-timeouts';
|
|
32
35
|
|
|
@@ -39,6 +42,22 @@ import type { CharacteristicPair, DeviceInfo, Logger, NobleModule } from './type
|
|
|
39
42
|
let noble: NobleModule | null = null;
|
|
40
43
|
let logger: Logger | null = null;
|
|
41
44
|
|
|
45
|
+
export function createNobleBleConnectionError(error: Error, messagePrefix = '') {
|
|
46
|
+
const errorMessage = error.message;
|
|
47
|
+
if (isBleStaleBondErrorText(errorMessage)) {
|
|
48
|
+
const nativeErrorMessage = `${messagePrefix}${errorMessage}`;
|
|
49
|
+
return ERRORS.TypedError(
|
|
50
|
+
HardwareErrorCode.BleBondInvalid,
|
|
51
|
+
`${HardwareErrorCodeMessage[HardwareErrorCode.BleBondInvalid]} (${nativeErrorMessage})`,
|
|
52
|
+
{
|
|
53
|
+
nativeErrorMessage,
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return ERRORS.TypedError(HardwareErrorCode.BleConnectedError, `${messagePrefix}${errorMessage}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
42
61
|
// Bluetooth state management
|
|
43
62
|
const bluetoothState: {
|
|
44
63
|
available: boolean;
|
|
@@ -1252,9 +1271,14 @@ async function forceReconnectPeripheral(peripheral: Peripheral, deviceId: string
|
|
|
1252
1271
|
}
|
|
1253
1272
|
|
|
1254
1273
|
// Step 3: Re-establish connection
|
|
1255
|
-
await
|
|
1256
|
-
|
|
1257
|
-
|
|
1274
|
+
await new Promise<void>((resolve, reject) => {
|
|
1275
|
+
peripheral.connect(error => {
|
|
1276
|
+
if (error) {
|
|
1277
|
+
reject(createNobleBleConnectionError(error));
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
resolve();
|
|
1281
|
+
});
|
|
1258
1282
|
});
|
|
1259
1283
|
logger?.info('[NobleBLE] Force reconnect successful');
|
|
1260
1284
|
connectedDevices.set(deviceId, peripheral);
|
|
@@ -1296,12 +1320,7 @@ async function freshScanAndDiscover(
|
|
|
1296
1320
|
await new Promise<void>((resolve, reject) => {
|
|
1297
1321
|
freshPeripheral.connect((error: Error | undefined) => {
|
|
1298
1322
|
if (error) {
|
|
1299
|
-
reject(
|
|
1300
|
-
ERRORS.TypedError(
|
|
1301
|
-
HardwareErrorCode.BleConnectedError,
|
|
1302
|
-
`Fresh peripheral connection failed: ${error.message}`
|
|
1303
|
-
)
|
|
1304
|
-
);
|
|
1323
|
+
reject(createNobleBleConnectionError(error, 'Fresh peripheral connection failed: '));
|
|
1305
1324
|
} else {
|
|
1306
1325
|
connectedDevices.set(deviceId, freshPeripheral);
|
|
1307
1326
|
resolve();
|
|
@@ -1414,6 +1433,9 @@ async function setupConnectionAndDiscoverServices(
|
|
|
1414
1433
|
try {
|
|
1415
1434
|
await forceReconnectPeripheral(peripheral, deviceId);
|
|
1416
1435
|
} catch (resetError) {
|
|
1436
|
+
if (isBleStaleBondHardwareError(resetError)) {
|
|
1437
|
+
throw resetError;
|
|
1438
|
+
}
|
|
1417
1439
|
// A failed reset must not abort the attempt: discovery on the existing
|
|
1418
1440
|
// link, then the fresh-scan fallback, still have a chance to recover.
|
|
1419
1441
|
logger?.error('[NobleBLE] Connection reset before discovery failed, continuing', resetError);
|
|
@@ -1666,33 +1688,12 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis
|
|
|
1666
1688
|
}
|
|
1667
1689
|
|
|
1668
1690
|
return new Promise((resolve, reject) => {
|
|
1669
|
-
let connectionTimedOut = false;
|
|
1670
|
-
const timeout = setTimeout(() => {
|
|
1671
|
-
connectionTimedOut = true;
|
|
1672
|
-
reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, 'Connection timeout'));
|
|
1673
|
-
}, NOBLE_BLE_CONNECTION_TIMEOUT_MS);
|
|
1674
|
-
|
|
1675
1691
|
// TypeScript type assertion - peripheral is guaranteed to be defined at this point
|
|
1676
1692
|
const connectedPeripheral = peripheral as Peripheral;
|
|
1677
1693
|
connectedPeripheral.connect(async (error: Error | undefined) => {
|
|
1678
|
-
clearTimeout(timeout);
|
|
1679
|
-
|
|
1680
|
-
// Noble may invoke the callback after the SDK timed out and released the request.
|
|
1681
|
-
// Ignore it to avoid initializing disposed commands or leaving an orphaned connection.
|
|
1682
|
-
if (connectionTimedOut) {
|
|
1683
|
-
if (!error) {
|
|
1684
|
-
try {
|
|
1685
|
-
connectedPeripheral.disconnect(() => undefined);
|
|
1686
|
-
} catch {
|
|
1687
|
-
// Best-effort cleanup only.
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
return;
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
1694
|
if (error) {
|
|
1694
1695
|
logger?.error('[NobleBLE] Connection failed:', error);
|
|
1695
|
-
reject(
|
|
1696
|
+
reject(createNobleBleConnectionError(error));
|
|
1696
1697
|
return;
|
|
1697
1698
|
}
|
|
1698
1699
|
|
|
@@ -1875,7 +1876,7 @@ async function subscribeNotifications(
|
|
|
1875
1876
|
timeoutBehavior: 'resolve',
|
|
1876
1877
|
});
|
|
1877
1878
|
await runBleCallbackOperation(callback => notifyCharacteristic.subscribe(callback), {
|
|
1878
|
-
timeoutMs:
|
|
1879
|
+
timeoutMs: NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS,
|
|
1879
1880
|
timeoutBehavior: 'reject',
|
|
1880
1881
|
});
|
|
1881
1882
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const NOBLE_BLE_TARGETED_SCAN_TIMEOUT_MS = 5_000;
|
|
2
|
-
export const
|
|
2
|
+
export const NOBLE_BLE_SUBSCRIBE_TIMEOUT_MS = 10_000;
|