@onekeyfe/hd-transport-web-device 1.2.8-alpha.128 → 1.2.8-alpha.129
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.
|
@@ -286,6 +286,192 @@ describe('ElectronBleTransport protocol detection', () => {
|
|
|
286
286
|
expect(nobleBle.unsubscribe).not.toHaveBeenCalled();
|
|
287
287
|
});
|
|
288
288
|
|
|
289
|
+
test.each([false, true])(
|
|
290
|
+
'forwards the existing keepSession=%s release intent to native',
|
|
291
|
+
async keepSession => {
|
|
292
|
+
const device = { id: 'release-intent-pro2-id', name: 'OneKey Pro 2' };
|
|
293
|
+
const release = jest.fn().mockResolvedValue(undefined);
|
|
294
|
+
const nobleBle = { ...createNobleBle(device), release };
|
|
295
|
+
echoProtocolV2(nobleBle, device.id);
|
|
296
|
+
const bleTransport = configureTransport(nobleBle);
|
|
297
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
298
|
+
|
|
299
|
+
await bleTransport.release(device.id, false, keepSession);
|
|
300
|
+
|
|
301
|
+
expect(release).toHaveBeenCalledWith(device.id, keepSession);
|
|
302
|
+
expect(nobleBle.disconnect).not.toHaveBeenCalled();
|
|
303
|
+
expect(nobleBle.unsubscribe).not.toHaveBeenCalled();
|
|
304
|
+
}
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
test.each(['Pro 2', 'Neo'])(
|
|
308
|
+
'reuses the connection, subscription and V2 sequence for %s after release',
|
|
309
|
+
async name => {
|
|
310
|
+
const device = { id: 'retained-v2-id', name };
|
|
311
|
+
const release = jest.fn().mockResolvedValue(undefined);
|
|
312
|
+
const nobleBle = { ...createNobleBle(device), release };
|
|
313
|
+
echoProtocolV2(nobleBle, device.id);
|
|
314
|
+
const bleTransport = configureTransport(nobleBle);
|
|
315
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
316
|
+
await bleTransport.call(device.id, 'Ping', { message: 'before-release' });
|
|
317
|
+
const notifyCleanup = nobleBle.onNotification.mock.results[0].value;
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
await bleTransport.release(device.id, false, true);
|
|
321
|
+
expect(bleTransport.getProtocolType(device.id)).toBe('V2');
|
|
322
|
+
expect(notifyCleanup).not.toHaveBeenCalled();
|
|
323
|
+
await expect(
|
|
324
|
+
bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
|
|
325
|
+
).resolves.toMatchObject({ uuid: device.id, protocolType: 'V2' });
|
|
326
|
+
await expect(
|
|
327
|
+
bleTransport.call(device.id, 'Ping', { message: 'after-release' })
|
|
328
|
+
).resolves.toMatchObject({ type: 'Success' });
|
|
329
|
+
|
|
330
|
+
expect(nobleBle.connect).toHaveBeenCalledTimes(1);
|
|
331
|
+
expect(nobleBle.subscribe).toHaveBeenCalledTimes(1);
|
|
332
|
+
expect(nobleBle.onNotification).toHaveBeenCalledTimes(1);
|
|
333
|
+
expect(nobleBle.onMtuChanged).toHaveBeenCalledTimes(1);
|
|
334
|
+
expect(release).toHaveBeenCalledWith(device.id, true);
|
|
335
|
+
expect(
|
|
336
|
+
nobleBle.write.mock.calls.map(([, hex]) => Number.parseInt(hex.slice(12, 14), 16))
|
|
337
|
+
).toEqual([1, 2, 3]);
|
|
338
|
+
} finally {
|
|
339
|
+
await bleTransport.disconnect(device.id);
|
|
340
|
+
}
|
|
341
|
+
expect(notifyCleanup).toHaveBeenCalledTimes(1);
|
|
342
|
+
expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
test.each(['ordinary release', 'onclose', 'forced probe'])(
|
|
347
|
+
'does not retain renderer state for %s',
|
|
348
|
+
async mode => {
|
|
349
|
+
const device = { id: 'release-fallback-id', name: 'Pro 2' };
|
|
350
|
+
const nobleBle = createNobleBle(device);
|
|
351
|
+
echoProtocolV2(nobleBle, device.id);
|
|
352
|
+
const bleTransport = configureTransport(nobleBle);
|
|
353
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
354
|
+
const notifyCleanup = nobleBle.onNotification.mock.results[0].value;
|
|
355
|
+
await bleTransport.release(device.id, mode === 'onclose', mode !== 'ordinary release');
|
|
356
|
+
|
|
357
|
+
const input = {
|
|
358
|
+
uuid: device.id,
|
|
359
|
+
expectedProtocol: 'V2' as const,
|
|
360
|
+
forceProtocolDetection: mode === 'forced probe',
|
|
361
|
+
};
|
|
362
|
+
await bleTransport.acquire(input);
|
|
363
|
+
|
|
364
|
+
expect(notifyCleanup).toHaveBeenCalledTimes(1);
|
|
365
|
+
expect(nobleBle.connect).toHaveBeenCalledTimes(2);
|
|
366
|
+
expect(nobleBle.subscribe).toHaveBeenCalledTimes(2);
|
|
367
|
+
await bleTransport.disconnect(device.id);
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
test.each([false, true])(
|
|
372
|
+
'rebuilds a retained link after a disconnect, including during lookup: %s',
|
|
373
|
+
async duringLookup => {
|
|
374
|
+
const device = { id: 'retained-drop-id', name: 'Pro 2' };
|
|
375
|
+
const nobleBle = createNobleBle(device);
|
|
376
|
+
echoProtocolV2(nobleBle, device.id);
|
|
377
|
+
const bleTransport = configureTransport(nobleBle);
|
|
378
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
379
|
+
await bleTransport.release(device.id, false, true);
|
|
380
|
+
const disconnectHandler = nobleBle.onDeviceDisconnected.mock.calls[0][0];
|
|
381
|
+
const notifyCleanup = nobleBle.onNotification.mock.results[0].value;
|
|
382
|
+
const drop = () =>
|
|
383
|
+
disconnectHandler({ ...device, reason: EBleDisconnectReason.DeviceDisconnected });
|
|
384
|
+
if (duringLookup) {
|
|
385
|
+
nobleBle.getDevice.mockImplementationOnce(() => {
|
|
386
|
+
drop();
|
|
387
|
+
return Promise.resolve(device);
|
|
388
|
+
});
|
|
389
|
+
} else {
|
|
390
|
+
drop();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
394
|
+
await expect(bleTransport.call(device.id, 'Ping', {})).resolves.toMatchObject({
|
|
395
|
+
type: 'Success',
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(notifyCleanup).toHaveBeenCalledTimes(1);
|
|
399
|
+
expect(nobleBle.connect).toHaveBeenCalledTimes(2);
|
|
400
|
+
expect(nobleBle.subscribe).toHaveBeenCalledTimes(2);
|
|
401
|
+
await bleTransport.disconnect(device.id);
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
test('disconnects a reused link on timeout without replaying the call', async () => {
|
|
406
|
+
const device = { id: 'retained-timeout-id', name: 'Pro 2' };
|
|
407
|
+
const nobleBle = createNobleBle(device);
|
|
408
|
+
echoProtocolV2(nobleBle, device.id);
|
|
409
|
+
const bleTransport = configureTransport(nobleBle);
|
|
410
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
411
|
+
await bleTransport.release(device.id, false, true);
|
|
412
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
413
|
+
nobleBle.write.mockImplementationOnce(() => Promise.resolve());
|
|
414
|
+
|
|
415
|
+
await expect(bleTransport.call(device.id, 'Ping', {}, { timeoutMs: 10 })).rejects.toMatchObject(
|
|
416
|
+
{
|
|
417
|
+
errorCode: HardwareErrorCode.BleTimeoutError,
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
expect(nobleBle.write).toHaveBeenCalledTimes(2);
|
|
422
|
+
expect(nobleBle.unsubscribe).toHaveBeenCalledWith(device.id);
|
|
423
|
+
expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
|
|
424
|
+
expect(bleTransport.getProtocolType(device.id)).toBeUndefined();
|
|
425
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
426
|
+
expect(nobleBle.subscribe).toHaveBeenCalledTimes(2);
|
|
427
|
+
await bleTransport.disconnect(device.id);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test('invalidates a retained link when native release fails', async () => {
|
|
431
|
+
const device = { id: 'retained-release-failure-id', name: 'Pro 2' };
|
|
432
|
+
const release = jest.fn().mockRejectedValueOnce(new Error('IPC release failed'));
|
|
433
|
+
const nobleBle = { ...createNobleBle(device), release };
|
|
434
|
+
echoProtocolV2(nobleBle, device.id);
|
|
435
|
+
const bleTransport = configureTransport(nobleBle);
|
|
436
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
437
|
+
const notifyCleanup = nobleBle.onNotification.mock.results[0].value;
|
|
438
|
+
|
|
439
|
+
await bleTransport.release(device.id, false, true);
|
|
440
|
+
|
|
441
|
+
expect(bleTransport.getProtocolType(device.id)).toBeUndefined();
|
|
442
|
+
expect(notifyCleanup).toHaveBeenCalledTimes(1);
|
|
443
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
444
|
+
expect(nobleBle.subscribe).toHaveBeenCalledTimes(2);
|
|
445
|
+
await bleTransport.disconnect(device.id);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
test('still cancels an in-flight V2 write when release requests retention', async () => {
|
|
449
|
+
const device = { id: 'active-release-id', name: 'Pro 2' };
|
|
450
|
+
const nobleBle = createNobleBle(device);
|
|
451
|
+
echoProtocolV2(nobleBle, device.id);
|
|
452
|
+
const bleTransport = configureTransport(nobleBle);
|
|
453
|
+
await bleTransport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
454
|
+
const started = createDeferred<void>();
|
|
455
|
+
const write = createDeferred<void>();
|
|
456
|
+
nobleBle.write.mockImplementationOnce(() => {
|
|
457
|
+
started.resolve();
|
|
458
|
+
return write.promise;
|
|
459
|
+
});
|
|
460
|
+
const result = bleTransport.call(device.id, 'Ping', {}).catch(error => error);
|
|
461
|
+
await started.promise;
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
const releasing = bleTransport.release(device.id, false, true);
|
|
465
|
+
write.resolve();
|
|
466
|
+
await releasing;
|
|
467
|
+
await expect(result).resolves.toMatchObject({ message: 'Electron BLE transport released' });
|
|
468
|
+
expect(bleTransport.getProtocolType(device.id)).toBeUndefined();
|
|
469
|
+
} finally {
|
|
470
|
+
write.resolve();
|
|
471
|
+
await bleTransport.disconnect(device.id);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
|
|
289
475
|
test('forceNative disconnects a device the renderer no longer tracks', async () => {
|
|
290
476
|
const device = { id: 'presumed-dead-id', name: 'OneKey Pro 2' };
|
|
291
477
|
const nobleBle = createNobleBle(device);
|
|
@@ -488,6 +674,10 @@ describe('ElectronBleTransport protocol detection', () => {
|
|
|
488
674
|
})
|
|
489
675
|
);
|
|
490
676
|
expect(transport.getProtocolType(device.id)).toBe('V1');
|
|
677
|
+
const notifyCleanup = nobleBle.onNotification.mock.results[0].value;
|
|
678
|
+
await transport.release(device.id, false, true);
|
|
679
|
+
expect(transport.getProtocolType(device.id)).toBeUndefined();
|
|
680
|
+
expect(notifyCleanup).toHaveBeenCalledTimes(1);
|
|
491
681
|
await expect(transport.acquire({ uuid: device.id, expectedProtocol: 'V1' })).resolves.toEqual(
|
|
492
682
|
expect.objectContaining({
|
|
493
683
|
uuid: device.id,
|
|
@@ -25,6 +25,8 @@ export default class ElectronBleTransport {
|
|
|
25
25
|
Log?: any;
|
|
26
26
|
emitter?: EventEmitter;
|
|
27
27
|
private connectedDevices;
|
|
28
|
+
private retainedDevices;
|
|
29
|
+
private protocolV2CallCounts;
|
|
28
30
|
private acquiringDevices;
|
|
29
31
|
private deviceProtocol;
|
|
30
32
|
private deviceProtocolHints;
|
|
@@ -62,7 +64,7 @@ export default class ElectronBleTransport {
|
|
|
62
64
|
bleColorCode?: string | undefined;
|
|
63
65
|
protocolType?: ProtocolType | undefined;
|
|
64
66
|
}>;
|
|
65
|
-
release(id: string,
|
|
67
|
+
release(id: string, onclose?: boolean, keepSession?: boolean): Promise<void>;
|
|
66
68
|
disconnect(id: string): Promise<void>;
|
|
67
69
|
private releaseNative;
|
|
68
70
|
private releaseLogical;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAA4B,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -255,6 +255,8 @@ declare class ElectronBleTransport {
|
|
|
255
255
|
Log?: any;
|
|
256
256
|
emitter?: EventEmitter;
|
|
257
257
|
private connectedDevices;
|
|
258
|
+
private retainedDevices;
|
|
259
|
+
private protocolV2CallCounts;
|
|
258
260
|
/**
|
|
259
261
|
* Devices whose acquire() is still in flight.
|
|
260
262
|
*
|
|
@@ -313,7 +315,7 @@ declare class ElectronBleTransport {
|
|
|
313
315
|
bleColorCode?: string | undefined;
|
|
314
316
|
protocolType?: ProtocolType | undefined;
|
|
315
317
|
}>;
|
|
316
|
-
release(id: string,
|
|
318
|
+
release(id: string, onclose?: boolean, keepSession?: boolean): Promise<void>;
|
|
317
319
|
disconnect(id: string): Promise<void>;
|
|
318
320
|
private releaseNative;
|
|
319
321
|
private releaseLogical;
|
package/dist/index.js
CHANGED
|
@@ -1532,6 +1532,8 @@ class ElectronBleTransport {
|
|
|
1532
1532
|
this.runPromise = null;
|
|
1533
1533
|
this.runPromiseDeviceId = null;
|
|
1534
1534
|
this.connectedDevices = new Set();
|
|
1535
|
+
this.retainedDevices = new Set();
|
|
1536
|
+
this.protocolV2CallCounts = new Map();
|
|
1535
1537
|
this.acquiringDevices = new Set();
|
|
1536
1538
|
this.deviceProtocol = new Map();
|
|
1537
1539
|
this.deviceProtocolHints = new Map();
|
|
@@ -1611,6 +1613,7 @@ class ElectronBleTransport {
|
|
|
1611
1613
|
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
1612
1614
|
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
1613
1615
|
this.connectedDevices.delete(deviceId);
|
|
1616
|
+
this.retainedDevices.delete(deviceId);
|
|
1614
1617
|
this.deviceProtocol.delete(deviceId);
|
|
1615
1618
|
this.deviceMtus.delete(deviceId);
|
|
1616
1619
|
this.devicePacketCapacities.delete(deviceId);
|
|
@@ -1707,11 +1710,18 @@ class ElectronBleTransport {
|
|
|
1707
1710
|
acquire(input) {
|
|
1708
1711
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1709
1712
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1710
|
-
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
1713
|
+
const { uuid, forceCleanRunPromise, expectedProtocol, forceProtocolDetection } = input;
|
|
1711
1714
|
if (!uuid) {
|
|
1712
1715
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
1713
1716
|
}
|
|
1714
|
-
|
|
1717
|
+
const retainedToken = this.retainedDevices.has(uuid) &&
|
|
1718
|
+
!forceProtocolDetection &&
|
|
1719
|
+
(!expectedProtocol || expectedProtocol === 'V2') &&
|
|
1720
|
+
this.deviceProtocol.get(uuid) === 'V2'
|
|
1721
|
+
? this.notificationTokens.get(uuid)
|
|
1722
|
+
: undefined;
|
|
1723
|
+
this.retainedDevices.delete(uuid);
|
|
1724
|
+
if (this.connectedDevices.has(uuid) && retainedToken === undefined) {
|
|
1715
1725
|
yield this.release(uuid);
|
|
1716
1726
|
}
|
|
1717
1727
|
if (forceCleanRunPromise && this.runPromise) {
|
|
@@ -1729,6 +1739,12 @@ class ElectronBleTransport {
|
|
|
1729
1739
|
if (!device) {
|
|
1730
1740
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
|
|
1731
1741
|
}
|
|
1742
|
+
if (retainedToken !== undefined &&
|
|
1743
|
+
this.notificationTokens.get(uuid) === retainedToken &&
|
|
1744
|
+
this.connectedDevices.has(uuid) &&
|
|
1745
|
+
this.deviceProtocol.get(uuid) === 'V2') {
|
|
1746
|
+
return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, 'V2')), { uuid });
|
|
1747
|
+
}
|
|
1732
1748
|
const protocolHint = expectedProtocol
|
|
1733
1749
|
? undefined
|
|
1734
1750
|
: (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid);
|
|
@@ -1792,12 +1808,19 @@ class ElectronBleTransport {
|
|
|
1792
1808
|
}
|
|
1793
1809
|
});
|
|
1794
1810
|
}
|
|
1795
|
-
release(id,
|
|
1811
|
+
release(id, onclose, keepSession) {
|
|
1796
1812
|
var _a;
|
|
1797
1813
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1798
1814
|
try {
|
|
1799
|
-
|
|
1800
|
-
|
|
1815
|
+
const retainLink = keepSession === true &&
|
|
1816
|
+
!onclose &&
|
|
1817
|
+
this.connectedDevices.has(id) &&
|
|
1818
|
+
this.deviceProtocol.get(id) === 'V2' &&
|
|
1819
|
+
!this.protocolV2CallCounts.has(id);
|
|
1820
|
+
if (!retainLink) {
|
|
1821
|
+
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
1822
|
+
}
|
|
1823
|
+
yield this.releaseLogical(id, keepSession, retainLink);
|
|
1801
1824
|
}
|
|
1802
1825
|
catch (error) {
|
|
1803
1826
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] release failed:', error);
|
|
@@ -1834,13 +1857,18 @@ class ElectronBleTransport {
|
|
|
1834
1857
|
}
|
|
1835
1858
|
});
|
|
1836
1859
|
}
|
|
1837
|
-
releaseLogical(id, keepSession) {
|
|
1860
|
+
releaseLogical(id, keepSession, retainLink = false) {
|
|
1838
1861
|
var _a, _b, _c, _d;
|
|
1839
1862
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1840
1863
|
try {
|
|
1841
1864
|
if (!this.connectedDevices.has(id))
|
|
1842
1865
|
return;
|
|
1843
|
-
|
|
1866
|
+
if (retainLink) {
|
|
1867
|
+
this.retainedDevices.add(id);
|
|
1868
|
+
}
|
|
1869
|
+
else {
|
|
1870
|
+
this.cleanupDeviceState(id);
|
|
1871
|
+
}
|
|
1844
1872
|
const release = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.release;
|
|
1845
1873
|
if (!release) {
|
|
1846
1874
|
if (!this.warnedMissingRelease) {
|
|
@@ -2272,19 +2300,27 @@ class ElectronBleTransport {
|
|
|
2272
2300
|
});
|
|
2273
2301
|
}
|
|
2274
2302
|
callProtocolV2(uuid, name, data, options) {
|
|
2275
|
-
var _a;
|
|
2303
|
+
var _a, _b, _c;
|
|
2276
2304
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2277
2305
|
if (!this._messages || !this._messagesV2) {
|
|
2278
2306
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
2279
2307
|
}
|
|
2280
2308
|
const callOptions = options;
|
|
2309
|
+
this.protocolV2CallCounts.set(uuid, ((_a = this.protocolV2CallCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1);
|
|
2281
2310
|
try {
|
|
2282
2311
|
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
2283
2312
|
}
|
|
2284
2313
|
catch (e) {
|
|
2285
|
-
(
|
|
2314
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V2 call error:', e);
|
|
2286
2315
|
throw e;
|
|
2287
2316
|
}
|
|
2317
|
+
finally {
|
|
2318
|
+
const remaining = ((_c = this.protocolV2CallCounts.get(uuid)) !== null && _c !== void 0 ? _c : 1) - 1;
|
|
2319
|
+
if (remaining > 0)
|
|
2320
|
+
this.protocolV2CallCounts.set(uuid, remaining);
|
|
2321
|
+
else
|
|
2322
|
+
this.protocolV2CallCounts.delete(uuid);
|
|
2323
|
+
}
|
|
2288
2324
|
});
|
|
2289
2325
|
}
|
|
2290
2326
|
createProtocolV2Adapter(uuid) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-web-device",
|
|
3
|
-
"version": "1.2.8-alpha.
|
|
3
|
+
"version": "1.2.8-alpha.129",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
"lint:fix": "eslint . --fix"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.8-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.8-alpha.
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.8-alpha.129",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.8-alpha.129"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@onekeyfe/hd-transport-electron": "1.2.8-alpha.
|
|
28
|
+
"@onekeyfe/hd-transport-electron": "1.2.8-alpha.129",
|
|
29
29
|
"@types/w3c-web-usb": "^1.0.6",
|
|
30
30
|
"@types/web-bluetooth": "^0.0.17"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "e340d9447b375a9d79afd737bec50ff8c5a46aba"
|
|
33
33
|
}
|
|
@@ -26,6 +26,7 @@ import { resolveBlePacketCapacity } from './ble-packet-capacity';
|
|
|
26
26
|
import type { Deferred } from '@onekeyfe/hd-shared';
|
|
27
27
|
import type { DesktopAPI, NobleBleIpcErrorResponse } from '@onekeyfe/hd-transport-electron';
|
|
28
28
|
import type {
|
|
29
|
+
AcquireInput,
|
|
29
30
|
OneKeyDeviceInfo,
|
|
30
31
|
ProtocolType,
|
|
31
32
|
ProtocolV2CallContext,
|
|
@@ -117,6 +118,10 @@ export default class ElectronBleTransport {
|
|
|
117
118
|
|
|
118
119
|
private connectedDevices: Set<string> = new Set();
|
|
119
120
|
|
|
121
|
+
private retainedDevices: Set<string> = new Set();
|
|
122
|
+
|
|
123
|
+
private protocolV2CallCounts: Map<string, number> = new Map();
|
|
124
|
+
|
|
120
125
|
/**
|
|
121
126
|
* Devices whose acquire() is still in flight.
|
|
122
127
|
*
|
|
@@ -234,6 +239,7 @@ export default class ElectronBleTransport {
|
|
|
234
239
|
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
235
240
|
.catch(error => this.Log?.debug('[Electron BLE] link cleanup failed:', error));
|
|
236
241
|
this.connectedDevices.delete(deviceId);
|
|
242
|
+
this.retainedDevices.delete(deviceId);
|
|
237
243
|
this.deviceProtocol.delete(deviceId);
|
|
238
244
|
this.deviceMtus.delete(deviceId);
|
|
239
245
|
this.devicePacketCapacities.delete(deviceId);
|
|
@@ -358,13 +364,22 @@ export default class ElectronBleTransport {
|
|
|
358
364
|
}
|
|
359
365
|
|
|
360
366
|
async acquire(input: BleAcquireInput) {
|
|
361
|
-
const { uuid, forceCleanRunPromise, expectedProtocol } =
|
|
367
|
+
const { uuid, forceCleanRunPromise, expectedProtocol, forceProtocolDetection }: AcquireInput =
|
|
368
|
+
input;
|
|
362
369
|
|
|
363
370
|
if (!uuid) {
|
|
364
371
|
throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
|
|
365
372
|
}
|
|
366
373
|
|
|
367
|
-
|
|
374
|
+
const retainedToken =
|
|
375
|
+
this.retainedDevices.has(uuid) &&
|
|
376
|
+
!forceProtocolDetection &&
|
|
377
|
+
(!expectedProtocol || expectedProtocol === 'V2') &&
|
|
378
|
+
this.deviceProtocol.get(uuid) === 'V2'
|
|
379
|
+
? this.notificationTokens.get(uuid)
|
|
380
|
+
: undefined;
|
|
381
|
+
this.retainedDevices.delete(uuid);
|
|
382
|
+
if (this.connectedDevices.has(uuid) && retainedToken === undefined) {
|
|
368
383
|
await this.release(uuid);
|
|
369
384
|
}
|
|
370
385
|
|
|
@@ -385,6 +400,18 @@ export default class ElectronBleTransport {
|
|
|
385
400
|
if (!device) {
|
|
386
401
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
|
|
387
402
|
}
|
|
403
|
+
// A disconnect during the IPC lookup invalidates the retained notification generation.
|
|
404
|
+
if (
|
|
405
|
+
retainedToken !== undefined &&
|
|
406
|
+
this.notificationTokens.get(uuid) === retainedToken &&
|
|
407
|
+
this.connectedDevices.has(uuid) &&
|
|
408
|
+
this.deviceProtocol.get(uuid) === 'V2'
|
|
409
|
+
) {
|
|
410
|
+
return {
|
|
411
|
+
...toBleDescriptor({ id: device.id, name: device.name }, 'V2'),
|
|
412
|
+
uuid,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
388
415
|
const protocolHint = expectedProtocol
|
|
389
416
|
? undefined
|
|
390
417
|
: input.protocolHint ?? this.deviceProtocolHints.get(uuid);
|
|
@@ -452,10 +479,18 @@ export default class ElectronBleTransport {
|
|
|
452
479
|
}
|
|
453
480
|
}
|
|
454
481
|
|
|
455
|
-
async release(id: string,
|
|
482
|
+
async release(id: string, onclose?: boolean, keepSession?: boolean) {
|
|
456
483
|
try {
|
|
457
|
-
|
|
458
|
-
|
|
484
|
+
const retainLink =
|
|
485
|
+
keepSession === true &&
|
|
486
|
+
!onclose &&
|
|
487
|
+
this.connectedDevices.has(id) &&
|
|
488
|
+
this.deviceProtocol.get(id) === 'V2' &&
|
|
489
|
+
!this.protocolV2CallCounts.has(id);
|
|
490
|
+
if (!retainLink) {
|
|
491
|
+
await this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
492
|
+
}
|
|
493
|
+
await this.releaseLogical(id, keepSession, retainLink);
|
|
459
494
|
} catch (error) {
|
|
460
495
|
this.Log?.error('[Electron BLE] release failed:', error);
|
|
461
496
|
this.cleanupDeviceState(id);
|
|
@@ -500,12 +535,15 @@ export default class ElectronBleTransport {
|
|
|
500
535
|
}
|
|
501
536
|
}
|
|
502
537
|
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
private async releaseLogical(id: string, keepSession?: boolean) {
|
|
538
|
+
// Retained V2 links reuse their renderer listeners; legacy releases remove them.
|
|
539
|
+
private async releaseLogical(id: string, keepSession?: boolean, retainLink = false) {
|
|
506
540
|
try {
|
|
507
541
|
if (!this.connectedDevices.has(id)) return;
|
|
508
|
-
|
|
542
|
+
if (retainLink) {
|
|
543
|
+
this.retainedDevices.add(id);
|
|
544
|
+
} else {
|
|
545
|
+
this.cleanupDeviceState(id);
|
|
546
|
+
}
|
|
509
547
|
|
|
510
548
|
const release = window.desktopApi?.nobleBle?.release;
|
|
511
549
|
if (!release) {
|
|
@@ -1016,6 +1054,7 @@ export default class ElectronBleTransport {
|
|
|
1016
1054
|
|
|
1017
1055
|
const callOptions = options;
|
|
1018
1056
|
|
|
1057
|
+
this.protocolV2CallCounts.set(uuid, (this.protocolV2CallCounts.get(uuid) ?? 0) + 1);
|
|
1019
1058
|
try {
|
|
1020
1059
|
return await this.protocolV2Links.call(
|
|
1021
1060
|
uuid,
|
|
@@ -1027,6 +1066,10 @@ export default class ElectronBleTransport {
|
|
|
1027
1066
|
} catch (e) {
|
|
1028
1067
|
this.Log?.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1029
1068
|
throw e;
|
|
1069
|
+
} finally {
|
|
1070
|
+
const remaining = (this.protocolV2CallCounts.get(uuid) ?? 1) - 1;
|
|
1071
|
+
if (remaining > 0) this.protocolV2CallCounts.set(uuid, remaining);
|
|
1072
|
+
else this.protocolV2CallCounts.delete(uuid);
|
|
1030
1073
|
}
|
|
1031
1074
|
}
|
|
1032
1075
|
|