@onekeyfe/hd-transport-electron 1.2.2-alpha.103 → 1.2.2-alpha.104
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-052b4b5b.js → index-985e2bf3.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-eff26dd3.js → noble-ble-handler-263d4736.js} +24 -14
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/noble-ble-handler.test.ts +68 -0
- package/src/noble-ble-handler.ts +21 -11
|
@@ -55,13 +55,13 @@ function invokeNobleBleIpc(request) {
|
|
|
55
55
|
|
|
56
56
|
function initNobleBleSupport(webContents) {
|
|
57
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
58
|
+
const { setupNobleBleHandlers } = yield Promise.resolve().then(function () { return require('./noble-ble-handler-263d4736.js'); });
|
|
59
59
|
setupNobleBleHandlers(webContents);
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
function disposeNobleBleSupport(releaseNoble) {
|
|
63
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-
|
|
64
|
+
const handler = yield Promise.resolve().then(function () { return require('./noble-ble-handler-263d4736.js'); });
|
|
65
65
|
yield handler.disposeNobleBleSupport(releaseNoble);
|
|
66
66
|
});
|
|
67
67
|
}
|
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-985e2bf3.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -106,6 +106,7 @@ let disposePromise;
|
|
|
106
106
|
let windowCleanup;
|
|
107
107
|
let removeIpcHandlers;
|
|
108
108
|
const pendingCancellations = new Set();
|
|
109
|
+
const pendingEnumerations = new Set();
|
|
109
110
|
const nativeConnections = new Set();
|
|
110
111
|
function trackNativeConnection(operation, cancel) {
|
|
111
112
|
const connection = {
|
|
@@ -873,7 +874,7 @@ function performTargetedScan(targetDeviceId, timeoutMs = NOBLE_BLE_TARGETED_SCAN
|
|
|
873
874
|
});
|
|
874
875
|
});
|
|
875
876
|
}
|
|
876
|
-
function enumerateDevices() {
|
|
877
|
+
function enumerateDevices(isWindowDestroyed) {
|
|
877
878
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
878
879
|
if (!noble) {
|
|
879
880
|
yield initializeNoble();
|
|
@@ -882,6 +883,8 @@ function enumerateDevices() {
|
|
|
882
883
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble not available');
|
|
883
884
|
}
|
|
884
885
|
assertBleActive();
|
|
886
|
+
if (isWindowDestroyed())
|
|
887
|
+
return [];
|
|
885
888
|
const nobleInstance = noble;
|
|
886
889
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Starting device enumeration');
|
|
887
890
|
discoveredDevices.clear();
|
|
@@ -890,14 +893,20 @@ function enumerateDevices() {
|
|
|
890
893
|
const devices = [];
|
|
891
894
|
let settled = false;
|
|
892
895
|
let intervalId;
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
896
|
+
let cleanupPromise;
|
|
897
|
+
const cleanup = () => {
|
|
898
|
+
if (!cleanupPromise) {
|
|
899
|
+
settled = true;
|
|
900
|
+
pendingCancellations.delete(cancel);
|
|
901
|
+
clearTimeout(timeoutId);
|
|
902
|
+
if (intervalId)
|
|
903
|
+
clearInterval(intervalId);
|
|
904
|
+
cleanupPromise = waitForNobleScanStop(nobleInstance).finally(() => {
|
|
905
|
+
pendingEnumerations.delete(cancel);
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
return cleanupPromise;
|
|
909
|
+
};
|
|
901
910
|
const pushDevice = (peripheral, id) => {
|
|
902
911
|
var _a;
|
|
903
912
|
if (devices.some(d => d.id === id))
|
|
@@ -921,10 +930,9 @@ function enumerateDevices() {
|
|
|
921
930
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scan completed, found devices:', devices.length);
|
|
922
931
|
resolve(devices);
|
|
923
932
|
}), DEVICE_SCAN_TIMEOUT);
|
|
924
|
-
const cancel = () =>
|
|
925
|
-
cleanup().then(() => resolve([]), reject);
|
|
926
|
-
};
|
|
933
|
+
const cancel = () => cleanup().then(() => resolve([]), reject);
|
|
927
934
|
pendingCancellations.add(cancel);
|
|
935
|
+
pendingEnumerations.add(cancel);
|
|
928
936
|
logger === null || logger === void 0 ? void 0 : logger.info('[NobleBLE] Scanning for OneKey BLE devices');
|
|
929
937
|
nobleInstance.startScanning([], true, (error) => index.__awaiter(this, void 0, void 0, function* () {
|
|
930
938
|
if (settled)
|
|
@@ -1545,7 +1553,7 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1545
1553
|
safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers');
|
|
1546
1554
|
handle(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, () => index.__awaiter(this, void 0, void 0, function* () {
|
|
1547
1555
|
try {
|
|
1548
|
-
const devices = yield enumerateDevices();
|
|
1556
|
+
const devices = yield enumerateDevices(() => windowDestroyed);
|
|
1549
1557
|
safeLog(logger, 'debug', 'Enumeration completed', {
|
|
1550
1558
|
count: devices.length,
|
|
1551
1559
|
devices: devices.map(device => ({ id: device.id, name: device.name })),
|
|
@@ -1642,9 +1650,11 @@ function setupNobleBleHandlers(webContents) {
|
|
|
1642
1650
|
return;
|
|
1643
1651
|
safeLog(logger, 'info', 'Cleaning up Noble BLE handlers');
|
|
1644
1652
|
const previousCleanup = windowCleanup;
|
|
1653
|
+
const enumerations = Array.from(pendingEnumerations, cancel => cancel());
|
|
1645
1654
|
windowCleanup = (() => index.__awaiter(this, void 0, void 0, function* () {
|
|
1646
1655
|
if (previousCleanup)
|
|
1647
1656
|
yield previousCleanup;
|
|
1657
|
+
yield Promise.allSettled(enumerations);
|
|
1648
1658
|
if (disposing)
|
|
1649
1659
|
return;
|
|
1650
1660
|
const deviceIds = Array.from(connectedDevices.keys());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"noble-ble-handler.d.ts","sourceRoot":"","sources":["../src/noble-ble-handler.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAA+B,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAiC1F,KAAK,mBAAmB,GAAG,KAAK,GAAG;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,mBAAmB,EAAE,aAAa,SAAK,+CAiB3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAgCvF;AA+KD,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE,oBAAoB,UAI7E;AAkyDD,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkOpE;AAOD,wBAAgB,sBAAsB,CACpC,YAAY,GAAE,CAAC,QAAQ,EAAE;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,KAAK,IAAkC,GAC/E,OAAO,CAAC,IAAI,CAAC,CAiEf"}
|
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.104",
|
|
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.104",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.104",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.104",
|
|
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": "67835939d9f779ffd50cd8b482d8c5b53bd580bd"
|
|
40
40
|
}
|
|
@@ -947,4 +947,72 @@ describe('Noble BLE process shutdown', () => {
|
|
|
947
947
|
await sdk.disposeNobleBleSupport();
|
|
948
948
|
expect(native.stop).toHaveBeenCalledTimes(1);
|
|
949
949
|
});
|
|
950
|
+
|
|
951
|
+
test.each(['started', 'late-start-callback'])(
|
|
952
|
+
'retires an old enumeration before a shared native scan resumes: %s',
|
|
953
|
+
async scanState => {
|
|
954
|
+
jest.useFakeTimers({ doNotFake: ['performance', 'setImmediate'] });
|
|
955
|
+
const { sdk, native, handlers, window } = await setup();
|
|
956
|
+
let lateStart: (() => void) | undefined;
|
|
957
|
+
if (scanState === 'late-start-callback') {
|
|
958
|
+
native.startScanning.mockImplementationOnce((_uuids, _duplicates, callback) => {
|
|
959
|
+
lateStart = callback;
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
let oldScanSettled = false;
|
|
963
|
+
const oldScan = Promise.resolve(
|
|
964
|
+
handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE)?.({})
|
|
965
|
+
).then(result => {
|
|
966
|
+
oldScanSettled = true;
|
|
967
|
+
return result;
|
|
968
|
+
});
|
|
969
|
+
await flushCallbacks();
|
|
970
|
+
jest.advanceTimersByTime(1000);
|
|
971
|
+
|
|
972
|
+
let finishOldScan: (() => void) | undefined;
|
|
973
|
+
native.stopScanning.mockImplementationOnce(callback => {
|
|
974
|
+
finishOldScan = callback;
|
|
975
|
+
});
|
|
976
|
+
window.emit('destroyed');
|
|
977
|
+
sdk.setupNobleBleHandlers(new EventEmitter() as unknown as WebContents);
|
|
978
|
+
const replacementReady = handlers.get(EOneKeyBleMessageKeys.BLE_AVAILABILITY_CHECK)?.({});
|
|
979
|
+
let replacementSettled = false;
|
|
980
|
+
Promise.resolve(replacementReady).then(() => {
|
|
981
|
+
replacementSettled = true;
|
|
982
|
+
});
|
|
983
|
+
await flushCallbacks();
|
|
984
|
+
expect(replacementSettled).toBe(false);
|
|
985
|
+
finishOldScan?.();
|
|
986
|
+
await replacementReady;
|
|
987
|
+
await flushCallbacks();
|
|
988
|
+
expect(oldScanSettled).toBe(true);
|
|
989
|
+
expect(await oldScan).toEqual([]);
|
|
990
|
+
|
|
991
|
+
// Another transport can now scan on the same process-wide Noble instance.
|
|
992
|
+
native.startScanning([], true, () => undefined);
|
|
993
|
+
const stopCount = native.stopScanning.mock.calls.length;
|
|
994
|
+
lateStart?.();
|
|
995
|
+
jest.advanceTimersByTime(5000);
|
|
996
|
+
await flushCallbacks();
|
|
997
|
+
expect(native.stopScanning).toHaveBeenCalledTimes(stopCount);
|
|
998
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
999
|
+
expect(native.stop).not.toHaveBeenCalled();
|
|
1000
|
+
await sdk.disposeNobleBleSupport();
|
|
1001
|
+
}
|
|
1002
|
+
);
|
|
1003
|
+
|
|
1004
|
+
test('does not start an old window enumeration after Bluetooth becomes ready', async () => {
|
|
1005
|
+
const { sdk, native, handlers, window } = await setup('unknown');
|
|
1006
|
+
const oldScan = handlers.get(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE)?.({});
|
|
1007
|
+
await flushCallbacks();
|
|
1008
|
+
window.emit('destroyed');
|
|
1009
|
+
sdk.setupNobleBleHandlers(new EventEmitter() as unknown as WebContents);
|
|
1010
|
+
await handlers.get(EOneKeyBleMessageKeys.BLE_AVAILABILITY_CHECK)?.({});
|
|
1011
|
+
|
|
1012
|
+
native.state = 'poweredOn';
|
|
1013
|
+
native.emit('stateChange', 'poweredOn');
|
|
1014
|
+
expect(await oldScan).toEqual([]);
|
|
1015
|
+
expect(native.startScanning).not.toHaveBeenCalled();
|
|
1016
|
+
await sdk.disposeNobleBleSupport();
|
|
1017
|
+
});
|
|
950
1018
|
});
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -46,6 +46,7 @@ let disposePromise: Promise<void> | undefined;
|
|
|
46
46
|
let windowCleanup: Promise<void> | undefined;
|
|
47
47
|
let removeIpcHandlers: (() => void) | undefined;
|
|
48
48
|
const pendingCancellations = new Set<() => void>();
|
|
49
|
+
const pendingEnumerations = new Set<() => Promise<void>>();
|
|
49
50
|
const nativeConnections = new Set<{ cancel: () => void; settled: Promise<void> }>();
|
|
50
51
|
|
|
51
52
|
function trackNativeConnection(operation: Promise<unknown>, cancel: () => void): void {
|
|
@@ -1150,7 +1151,7 @@ async function performTargetedScan(
|
|
|
1150
1151
|
}
|
|
1151
1152
|
|
|
1152
1153
|
// Enumerate devices
|
|
1153
|
-
async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
1154
|
+
async function enumerateDevices(isWindowDestroyed: () => boolean): Promise<DeviceInfo[]> {
|
|
1154
1155
|
if (!noble) {
|
|
1155
1156
|
await initializeNoble();
|
|
1156
1157
|
}
|
|
@@ -1160,6 +1161,7 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
1160
1161
|
}
|
|
1161
1162
|
|
|
1162
1163
|
assertBleActive();
|
|
1164
|
+
if (isWindowDestroyed()) return [];
|
|
1163
1165
|
// Capture noble reference for use in closures (TypeScript narrowing)
|
|
1164
1166
|
const nobleInstance = noble;
|
|
1165
1167
|
|
|
@@ -1176,16 +1178,22 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
1176
1178
|
const devices: DeviceInfo[] = [];
|
|
1177
1179
|
let settled = false;
|
|
1178
1180
|
let intervalId: ReturnType<typeof setInterval> | undefined;
|
|
1181
|
+
let cleanupPromise: Promise<void> | undefined;
|
|
1179
1182
|
|
|
1180
1183
|
// Cleanup function: clears timers and waits until Noble confirms scanning
|
|
1181
1184
|
// has stopped. Resolving enumerate before this callback creates a race with
|
|
1182
1185
|
// an immediately-following connection attempt.
|
|
1183
|
-
const cleanup =
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1186
|
+
const cleanup = () => {
|
|
1187
|
+
if (!cleanupPromise) {
|
|
1188
|
+
settled = true;
|
|
1189
|
+
pendingCancellations.delete(cancel);
|
|
1190
|
+
clearTimeout(timeoutId);
|
|
1191
|
+
if (intervalId) clearInterval(intervalId);
|
|
1192
|
+
cleanupPromise = waitForNobleScanStop(nobleInstance).finally(() => {
|
|
1193
|
+
pendingEnumerations.delete(cancel);
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
return cleanupPromise;
|
|
1189
1197
|
};
|
|
1190
1198
|
|
|
1191
1199
|
// Collect discovered devices into the devices array
|
|
@@ -1214,10 +1222,9 @@ async function enumerateDevices(): Promise<DeviceInfo[]> {
|
|
|
1214
1222
|
resolve(devices);
|
|
1215
1223
|
}, DEVICE_SCAN_TIMEOUT);
|
|
1216
1224
|
|
|
1217
|
-
const cancel = () =>
|
|
1218
|
-
cleanup().then(() => resolve([]), reject);
|
|
1219
|
-
};
|
|
1225
|
+
const cancel = () => cleanup().then(() => resolve([]), reject);
|
|
1220
1226
|
pendingCancellations.add(cancel);
|
|
1227
|
+
pendingEnumerations.add(cancel);
|
|
1221
1228
|
|
|
1222
1229
|
// Start scanning without a service UUID filter so Pro2 advertisements with
|
|
1223
1230
|
// short vendor UUIDs can be found. Repeated advertisements are required when
|
|
@@ -2163,7 +2170,7 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
|
|
|
2163
2170
|
// Handle enumerate request
|
|
2164
2171
|
handle(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, async () => {
|
|
2165
2172
|
try {
|
|
2166
|
-
const devices = await enumerateDevices();
|
|
2173
|
+
const devices = await enumerateDevices(() => windowDestroyed);
|
|
2167
2174
|
safeLog(logger, 'debug', 'Enumeration completed', {
|
|
2168
2175
|
count: devices.length,
|
|
2169
2176
|
devices: devices.map(device => ({ id: device.id, name: device.name })),
|
|
@@ -2312,8 +2319,11 @@ export function setupNobleBleHandlers(webContents: WebContents): void {
|
|
|
2312
2319
|
if (disposing) return;
|
|
2313
2320
|
safeLog(logger, 'info', 'Cleaning up Noble BLE handlers');
|
|
2314
2321
|
const previousCleanup = windowCleanup;
|
|
2322
|
+
// Cancel before yielding so old timers cannot stop a replacement renderer's scan.
|
|
2323
|
+
const enumerations = Array.from(pendingEnumerations, cancel => cancel());
|
|
2315
2324
|
windowCleanup = (async () => {
|
|
2316
2325
|
if (previousCleanup) await previousCleanup;
|
|
2326
|
+
await Promise.allSettled(enumerations);
|
|
2317
2327
|
if (disposing) return;
|
|
2318
2328
|
const deviceIds = Array.from(connectedDevices.keys());
|
|
2319
2329
|
for (const deviceId of deviceIds) {
|