@onekeyfe/hd-transport-electron 1.2.0-alpha.68 → 1.2.0-alpha.69
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/ble-packet-capacity.d.ts +2 -0
- package/dist/ble-packet-capacity.d.ts.map +1 -0
- package/dist/{index-84fea839.js → index-bd1cfdb6.js} +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/dist/{noble-ble-handler-a0b2f06d.js → noble-ble-handler-7ac9c43d.js} +45 -31
- package/dist/noble-ble-handler.d.ts.map +1 -1
- package/dist/types/desktop-api.d.ts +5 -0
- package/dist/types/desktop-api.d.ts.map +1 -1
- package/dist/types/noble-extended.d.ts +1 -0
- package/dist/types/noble-extended.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/ble-packet-capacity.test.ts +13 -0
- package/src/ble-packet-capacity.ts +13 -0
- package/src/noble-ble-handler.ts +49 -18
- package/src/types/desktop-api.ts +2 -1
- package/src/types/noble-extended.ts +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ble-packet-capacity.d.ts","sourceRoot":"","sources":["../src/ble-packet-capacity.ts"],"names":[],"mappings":"AAEA,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,qBAAqB,EAAE,MAAM,EAC7B,sBAAsB,EAAE,MAAM,GAC7B,MAAM,CAMR"}
|
|
@@ -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-7ac9c43d.js'); });
|
|
36
36
|
setupNobleBleHandlers(webContents);
|
|
37
37
|
});
|
|
38
38
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ interface DeviceInfo extends OneKeyDeviceInfoBase {
|
|
|
6
6
|
id: string;
|
|
7
7
|
name: string;
|
|
8
8
|
state: string;
|
|
9
|
+
mtu?: number;
|
|
9
10
|
}
|
|
10
11
|
interface CharacteristicPair {
|
|
11
12
|
write: Characteristic;
|
|
@@ -38,6 +39,7 @@ interface NobleBleAPI {
|
|
|
38
39
|
getDevice: (uuid: string) => Promise<{
|
|
39
40
|
id: string;
|
|
40
41
|
name: string;
|
|
42
|
+
mtu?: number;
|
|
41
43
|
} | null>;
|
|
42
44
|
connect: (uuid: string) => Promise<void>;
|
|
43
45
|
disconnect: (uuid: string) => Promise<void>;
|
|
@@ -45,6 +47,10 @@ interface NobleBleAPI {
|
|
|
45
47
|
unsubscribe: (uuid: string) => Promise<void>;
|
|
46
48
|
write: (uuid: string, data: string) => Promise<void>;
|
|
47
49
|
onNotification: (callback: (deviceId: string, data: string) => void) => () => void;
|
|
50
|
+
onMtuChanged?: (callback: (device: {
|
|
51
|
+
id: string;
|
|
52
|
+
mtu: number;
|
|
53
|
+
}) => void) => () => void;
|
|
48
54
|
onDeviceDisconnected: (callback: (device: {
|
|
49
55
|
id: string;
|
|
50
56
|
name: string;
|
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-bd1cfdb6.js');
|
|
4
4
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
5
5
|
var pRetry = require('p-retry');
|
|
6
6
|
|
|
@@ -8,6 +8,14 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
8
8
|
|
|
9
9
|
var pRetry__default = /*#__PURE__*/_interopDefaultLegacy(pRetry);
|
|
10
10
|
|
|
11
|
+
const BLE_ATT_HEADER_BYTES = 3;
|
|
12
|
+
function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapacity) {
|
|
13
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= BLE_ATT_HEADER_BYTES) {
|
|
14
|
+
return fallbackPacketCapacity;
|
|
15
|
+
}
|
|
16
|
+
return Math.min(maximumPacketCapacity, Math.floor(mtu) - BLE_ATT_HEADER_BYTES);
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
function safeLog(logger, level, message, ...args) {
|
|
12
20
|
if (logger) {
|
|
13
21
|
logger[level](message, ...args);
|
|
@@ -98,6 +106,7 @@ const notificationCallbacks = new Map();
|
|
|
98
106
|
const subscribedDevices = new Map();
|
|
99
107
|
const subscriptionOperations = new Map();
|
|
100
108
|
const deviceDisconnectListeners = new Map();
|
|
109
|
+
const deviceMtuListeners = new Map();
|
|
101
110
|
const ONEKEY_SERVICE_UUIDS = [hdShared.ONEKEY_SERVICE_UUID];
|
|
102
111
|
const ONEKEY_SERVICE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_SERVICE_UUID);
|
|
103
112
|
const ONEKEY_WRITE_UUID_ALIASES = hdShared.createKnownBleUuidAliases(hdShared.ONEKEY_WRITE_CHARACTERISTIC_UUID);
|
|
@@ -107,8 +116,8 @@ const DEVICE_SCAN_TIMEOUT = 5000;
|
|
|
107
116
|
const DEVICE_CHECK_INTERVAL = 500;
|
|
108
117
|
const SERVICE_DISCOVERY_TIMEOUT = 10000;
|
|
109
118
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
110
|
-
const
|
|
111
|
-
const
|
|
119
|
+
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
120
|
+
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
112
121
|
const RETRY_CONFIG = { MAX_ATTEMPTS: 15, WRITE_TIMEOUT: 2000 };
|
|
113
122
|
const IS_WINDOWS = process.platform === 'win32';
|
|
114
123
|
const ABORTABLE_WRITE_ERROR_PATTERNS = [
|
|
@@ -300,6 +309,11 @@ function cleanupDevice(deviceId, webContents, options = {}) {
|
|
|
300
309
|
disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
|
|
301
310
|
deviceDisconnectListeners.delete(deviceId);
|
|
302
311
|
}
|
|
312
|
+
const mtuEntry = deviceMtuListeners.get(deviceId);
|
|
313
|
+
if (mtuEntry) {
|
|
314
|
+
mtuEntry.peripheral.removeListener('mtu', mtuEntry.listener);
|
|
315
|
+
deviceMtuListeners.delete(deviceId);
|
|
316
|
+
}
|
|
303
317
|
connectedDevices.delete(deviceId);
|
|
304
318
|
deviceCharacteristics.delete(deviceId);
|
|
305
319
|
notificationCallbacks.delete(deviceId);
|
|
@@ -343,8 +357,25 @@ function setupDisconnectListener(peripheral, deviceId, webContents) {
|
|
|
343
357
|
};
|
|
344
358
|
deviceDisconnectListeners.set(deviceId, { peripheral, listener });
|
|
345
359
|
peripheral.on('disconnect', listener);
|
|
360
|
+
setupMtuListener(peripheral, deviceId, webContents);
|
|
361
|
+
}
|
|
362
|
+
function setupMtuListener(peripheral, deviceId, webContents) {
|
|
363
|
+
const existing = deviceMtuListeners.get(deviceId);
|
|
364
|
+
if (existing) {
|
|
365
|
+
existing.peripheral.removeListener('mtu', existing.listener);
|
|
366
|
+
}
|
|
367
|
+
const listener = (mtu) => {
|
|
368
|
+
if (!Number.isFinite(mtu) || mtu <= 0)
|
|
369
|
+
return;
|
|
370
|
+
webContents.send(hdShared.EOneKeyBleMessageKeys.NOBLE_BLE_MTU_CHANGED, {
|
|
371
|
+
id: deviceId,
|
|
372
|
+
mtu,
|
|
373
|
+
});
|
|
374
|
+
};
|
|
375
|
+
deviceMtuListeners.set(deviceId, { peripheral, listener });
|
|
376
|
+
peripheral.on('mtu', listener);
|
|
346
377
|
}
|
|
347
|
-
function
|
|
378
|
+
function writeCharacteristicWithoutResponse(deviceId, writeCharacteristic, buffer) {
|
|
348
379
|
return index.__awaiter(this, void 0, void 0, function* () {
|
|
349
380
|
return new Promise((resolve, reject) => {
|
|
350
381
|
writeCharacteristic.write(buffer, true, (error) => {
|
|
@@ -376,7 +407,7 @@ function attemptWindowsWriteUntilPaired(deviceId, doGetWriteCharacteristic, payl
|
|
|
376
407
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Write characteristic not available for ${deviceId}`);
|
|
377
408
|
}
|
|
378
409
|
try {
|
|
379
|
-
yield
|
|
410
|
+
yield writeCharacteristicWithoutResponse(deviceId, latestWrite, payload);
|
|
380
411
|
}
|
|
381
412
|
catch (e) {
|
|
382
413
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
@@ -444,44 +475,37 @@ function transmitHexDataToDevice(deviceId, hexData) {
|
|
|
444
475
|
}
|
|
445
476
|
const toBuffer = Buffer.from(hexData, 'hex');
|
|
446
477
|
const doGetWriteCharacteristic = () => { var _a; return (_a = deviceCharacteristics.get(deviceId)) === null || _a === void 0 ? void 0 : _a.write; };
|
|
478
|
+
const packetCapacity = resolveBlePacketCapacity(peripheral.mtu, BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
447
479
|
if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
|
|
448
480
|
const writeCharacteristic = doGetWriteCharacteristic();
|
|
449
481
|
if (!writeCharacteristic) {
|
|
450
482
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, `Write characteristic not available for ${deviceId}`);
|
|
451
483
|
}
|
|
452
|
-
if (toBuffer.length <=
|
|
453
|
-
yield
|
|
454
|
-
yield writeCharacteristicWithAck(deviceId, writeCharacteristic, toBuffer);
|
|
484
|
+
if (toBuffer.length <= packetCapacity) {
|
|
485
|
+
yield writeCharacteristicWithoutResponse(deviceId, writeCharacteristic, toBuffer);
|
|
455
486
|
return;
|
|
456
487
|
}
|
|
457
488
|
for (let offset = 0; offset < toBuffer.length;) {
|
|
458
|
-
const chunkSize = Math.min(
|
|
489
|
+
const chunkSize = Math.min(packetCapacity, toBuffer.length - offset);
|
|
459
490
|
const chunk = toBuffer.subarray(offset, offset + chunkSize);
|
|
460
491
|
offset += chunkSize;
|
|
461
492
|
const latest = doGetWriteCharacteristic();
|
|
462
493
|
if (!latest) {
|
|
463
494
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound, `Write characteristic not available for ${deviceId}`);
|
|
464
495
|
}
|
|
465
|
-
yield
|
|
466
|
-
if (offset < toBuffer.length) {
|
|
467
|
-
yield hdShared.wait(UNIFIED_WRITE_DELAY);
|
|
468
|
-
}
|
|
496
|
+
yield writeCharacteristicWithoutResponse(deviceId, latest, chunk);
|
|
469
497
|
}
|
|
470
498
|
return;
|
|
471
499
|
}
|
|
472
|
-
if (toBuffer.length <=
|
|
473
|
-
yield hdShared.wait(UNIFIED_WRITE_DELAY);
|
|
500
|
+
if (toBuffer.length <= packetCapacity) {
|
|
474
501
|
yield attemptWindowsWriteUntilPaired(deviceId, doGetWriteCharacteristic, toBuffer, 'single');
|
|
475
502
|
return;
|
|
476
503
|
}
|
|
477
504
|
for (let offset = 0, idx = 0; offset < toBuffer.length; idx++) {
|
|
478
|
-
const chunkSize = Math.min(
|
|
505
|
+
const chunkSize = Math.min(packetCapacity, toBuffer.length - offset);
|
|
479
506
|
const chunk = toBuffer.subarray(offset, offset + chunkSize);
|
|
480
507
|
offset += chunkSize;
|
|
481
508
|
yield attemptWindowsWriteUntilPaired(deviceId, doGetWriteCharacteristic, chunk, `chunk-${idx + 1}`);
|
|
482
|
-
if (offset < toBuffer.length) {
|
|
483
|
-
yield hdShared.wait(UNIFIED_WRITE_DELAY);
|
|
484
|
-
}
|
|
485
509
|
}
|
|
486
510
|
});
|
|
487
511
|
}
|
|
@@ -658,22 +682,12 @@ function getDevice(deviceId) {
|
|
|
658
682
|
const peripheral = discoveredDevices.get(deviceId);
|
|
659
683
|
if (peripheral) {
|
|
660
684
|
const deviceName = ((_a = peripheral.advertisement) === null || _a === void 0 ? void 0 : _a.localName) || 'Unknown Device';
|
|
661
|
-
return {
|
|
662
|
-
commType: 'electron-ble',
|
|
663
|
-
id: peripheral.id,
|
|
664
|
-
name: deviceName,
|
|
665
|
-
state: peripheral.state || 'disconnected',
|
|
666
|
-
};
|
|
685
|
+
return Object.assign({ commType: 'electron-ble', id: peripheral.id, name: deviceName, state: peripheral.state || 'disconnected' }, (typeof peripheral.mtu === 'number' ? { mtu: peripheral.mtu } : {}));
|
|
667
686
|
}
|
|
668
687
|
const connectedPeripheral = connectedDevices.get(deviceId);
|
|
669
688
|
if (connectedPeripheral) {
|
|
670
689
|
const deviceName = ((_b = connectedPeripheral.advertisement) === null || _b === void 0 ? void 0 : _b.localName) || 'Unknown Device';
|
|
671
|
-
return {
|
|
672
|
-
commType: 'electron-ble',
|
|
673
|
-
id: connectedPeripheral.id,
|
|
674
|
-
name: deviceName,
|
|
675
|
-
state: connectedPeripheral.state || 'connected',
|
|
676
|
-
};
|
|
690
|
+
return Object.assign({ commType: 'electron-ble', id: connectedPeripheral.id, name: deviceName, state: connectedPeripheral.state || 'connected' }, (typeof connectedPeripheral.mtu === 'number' ? { mtu: connectedPeripheral.mtu } : {}));
|
|
677
691
|
}
|
|
678
692
|
return {
|
|
679
693
|
commType: 'electron-ble',
|
|
@@ -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":"AA+BA,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,UAAU,CAAC;AA++ChE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAyJpE"}
|
|
@@ -6,6 +6,7 @@ export interface NobleBleAPI {
|
|
|
6
6
|
getDevice: (uuid: string) => Promise<{
|
|
7
7
|
id: string;
|
|
8
8
|
name: string;
|
|
9
|
+
mtu?: number;
|
|
9
10
|
} | null>;
|
|
10
11
|
connect: (uuid: string) => Promise<void>;
|
|
11
12
|
disconnect: (uuid: string) => Promise<void>;
|
|
@@ -13,6 +14,10 @@ export interface NobleBleAPI {
|
|
|
13
14
|
unsubscribe: (uuid: string) => Promise<void>;
|
|
14
15
|
write: (uuid: string, data: string) => Promise<void>;
|
|
15
16
|
onNotification: (callback: (deviceId: string, data: string) => void) => () => void;
|
|
17
|
+
onMtuChanged?: (callback: (device: {
|
|
18
|
+
id: string;
|
|
19
|
+
mtu: number;
|
|
20
|
+
}) => void) => () => void;
|
|
16
21
|
onDeviceDisconnected: (callback: (device: {
|
|
17
22
|
id: string;
|
|
18
23
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"desktop-api.d.ts","sourceRoot":"","sources":["../../src/types/desktop-api.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC;IACzD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"desktop-api.d.ts","sourceRoot":"","sources":["../../src/types/desktop-api.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC;IACzD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACxF,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,cAAc,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACnF,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACvF,oBAAoB,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC/F,iBAAiB,EAAE,MAAM,OAAO,CAAC;QAC/B,SAAS,EAAE,OAAO,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC,CAAC;CACJ;AAGD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB"}
|
|
@@ -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;
|
|
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.69",
|
|
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.69",
|
|
29
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.69",
|
|
30
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.69",
|
|
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": "c6baed25917e3c3f027f83dfc23cde85400de558"
|
|
40
40
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { resolveBlePacketCapacity } from '../ble-packet-capacity';
|
|
2
|
+
|
|
3
|
+
describe('resolveBlePacketCapacity', () => {
|
|
4
|
+
test('uses ATT MTU payload capacity with an upper bound', () => {
|
|
5
|
+
expect(resolveBlePacketCapacity(247, 244, 192)).toBe(244);
|
|
6
|
+
expect(resolveBlePacketCapacity(185, 244, 192)).toBe(182);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test('preserves the compatibility fallback when MTU is unavailable', () => {
|
|
10
|
+
expect(resolveBlePacketCapacity(null, 244, 192)).toBe(192);
|
|
11
|
+
expect(resolveBlePacketCapacity(undefined, 244, 192)).toBe(192);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const BLE_ATT_HEADER_BYTES = 3;
|
|
2
|
+
|
|
3
|
+
export function resolveBlePacketCapacity(
|
|
4
|
+
mtu: number | null | undefined,
|
|
5
|
+
maximumPacketCapacity: number,
|
|
6
|
+
fallbackPacketCapacity: number
|
|
7
|
+
): number {
|
|
8
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= BLE_ATT_HEADER_BYTES) {
|
|
9
|
+
return fallbackPacketCapacity;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return Math.min(maximumPacketCapacity, Math.floor(mtu) - BLE_ATT_HEADER_BYTES);
|
|
13
|
+
}
|
package/src/noble-ble-handler.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from '@onekeyfe/hd-shared';
|
|
22
22
|
import pRetry from 'p-retry';
|
|
23
23
|
|
|
24
|
+
import { resolveBlePacketCapacity } from './ble-packet-capacity';
|
|
24
25
|
import { safeLog } from './types/noble-extended';
|
|
25
26
|
import { runBleCallbackOperation, softRefreshSubscription } from './ble-ops';
|
|
26
27
|
import {
|
|
@@ -65,6 +66,10 @@ const deviceDisconnectListeners = new Map<
|
|
|
65
66
|
string,
|
|
66
67
|
{ peripheral: Peripheral; listener: () => void }
|
|
67
68
|
>();
|
|
69
|
+
const deviceMtuListeners = new Map<
|
|
70
|
+
string,
|
|
71
|
+
{ peripheral: Peripheral; listener: (mtu: number) => void }
|
|
72
|
+
>();
|
|
68
73
|
|
|
69
74
|
// Windows-only response watchdog state moved to utils/windows-ble-recovery
|
|
70
75
|
|
|
@@ -86,8 +91,8 @@ const SERVICE_DISCOVERY_TIMEOUT = 10000; // 10 seconds for service discovery
|
|
|
86
91
|
const BLE_CLEANUP_TIMEOUT = 250;
|
|
87
92
|
|
|
88
93
|
// Write-related constants
|
|
89
|
-
const
|
|
90
|
-
const
|
|
94
|
+
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
95
|
+
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
91
96
|
const RETRY_CONFIG = { MAX_ATTEMPTS: 15, WRITE_TIMEOUT: 2000 } as const;
|
|
92
97
|
const IS_WINDOWS = process.platform === 'win32';
|
|
93
98
|
const ABORTABLE_WRITE_ERROR_PATTERNS = [
|
|
@@ -364,6 +369,11 @@ function cleanupDevice(
|
|
|
364
369
|
disconnectEntry.peripheral.removeListener('disconnect', disconnectEntry.listener);
|
|
365
370
|
deviceDisconnectListeners.delete(deviceId);
|
|
366
371
|
}
|
|
372
|
+
const mtuEntry = deviceMtuListeners.get(deviceId);
|
|
373
|
+
if (mtuEntry) {
|
|
374
|
+
mtuEntry.peripheral.removeListener('mtu', mtuEntry.listener);
|
|
375
|
+
deviceMtuListeners.delete(deviceId);
|
|
376
|
+
}
|
|
367
377
|
connectedDevices.delete(deviceId);
|
|
368
378
|
deviceCharacteristics.delete(deviceId);
|
|
369
379
|
notificationCallbacks.delete(deviceId);
|
|
@@ -423,11 +433,33 @@ function setupDisconnectListener(
|
|
|
423
433
|
};
|
|
424
434
|
deviceDisconnectListeners.set(deviceId, { peripheral, listener });
|
|
425
435
|
peripheral.on('disconnect', listener);
|
|
436
|
+
setupMtuListener(peripheral, deviceId, webContents);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function setupMtuListener(
|
|
440
|
+
peripheral: Peripheral,
|
|
441
|
+
deviceId: string,
|
|
442
|
+
webContents: WebContents
|
|
443
|
+
): void {
|
|
444
|
+
const existing = deviceMtuListeners.get(deviceId);
|
|
445
|
+
if (existing) {
|
|
446
|
+
existing.peripheral.removeListener('mtu', existing.listener);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const listener = (mtu: number) => {
|
|
450
|
+
if (!Number.isFinite(mtu) || mtu <= 0) return;
|
|
451
|
+
webContents.send(EOneKeyBleMessageKeys.NOBLE_BLE_MTU_CHANGED, {
|
|
452
|
+
id: deviceId,
|
|
453
|
+
mtu,
|
|
454
|
+
});
|
|
455
|
+
};
|
|
456
|
+
deviceMtuListeners.set(deviceId, { peripheral, listener });
|
|
457
|
+
peripheral.on('mtu', listener);
|
|
426
458
|
}
|
|
427
459
|
|
|
428
460
|
// ===== Write helpers (inline) =====
|
|
429
461
|
|
|
430
|
-
async function
|
|
462
|
+
async function writeCharacteristicWithoutResponse(
|
|
431
463
|
deviceId: string,
|
|
432
464
|
writeCharacteristic: Characteristic,
|
|
433
465
|
buffer: Buffer
|
|
@@ -475,7 +507,7 @@ async function attemptWindowsWriteUntilPaired(
|
|
|
475
507
|
}
|
|
476
508
|
|
|
477
509
|
try {
|
|
478
|
-
await
|
|
510
|
+
await writeCharacteristicWithoutResponse(deviceId, latestWrite, payload);
|
|
479
511
|
} catch (e) {
|
|
480
512
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
481
513
|
logger?.error('[BLE-Write] Windows write error', {
|
|
@@ -559,6 +591,11 @@ async function transmitHexDataToDevice(deviceId: string, hexData: string): Promi
|
|
|
559
591
|
|
|
560
592
|
const toBuffer = Buffer.from(hexData, 'hex');
|
|
561
593
|
const doGetWriteCharacteristic = () => deviceCharacteristics.get(deviceId)?.write;
|
|
594
|
+
const packetCapacity = resolveBlePacketCapacity(
|
|
595
|
+
peripheral.mtu,
|
|
596
|
+
BLE_PACKET_SIZE_MAXIMUM,
|
|
597
|
+
BLE_PACKET_SIZE_FALLBACK
|
|
598
|
+
);
|
|
562
599
|
|
|
563
600
|
if (!IS_WINDOWS || pairedDevices.has(deviceId)) {
|
|
564
601
|
// macOS / Linux or already paired on Windows: direct write
|
|
@@ -569,14 +606,13 @@ async function transmitHexDataToDevice(deviceId: string, hexData: string): Promi
|
|
|
569
606
|
`Write characteristic not available for ${deviceId}`
|
|
570
607
|
);
|
|
571
608
|
}
|
|
572
|
-
if (toBuffer.length <=
|
|
573
|
-
await
|
|
574
|
-
await writeCharacteristicWithAck(deviceId, writeCharacteristic, toBuffer);
|
|
609
|
+
if (toBuffer.length <= packetCapacity) {
|
|
610
|
+
await writeCharacteristicWithoutResponse(deviceId, writeCharacteristic, toBuffer);
|
|
575
611
|
return;
|
|
576
612
|
}
|
|
577
613
|
// chunked
|
|
578
614
|
for (let offset = 0; offset < toBuffer.length; ) {
|
|
579
|
-
const chunkSize = Math.min(
|
|
615
|
+
const chunkSize = Math.min(packetCapacity, toBuffer.length - offset);
|
|
580
616
|
const chunk = toBuffer.subarray(offset, offset + chunkSize);
|
|
581
617
|
offset += chunkSize;
|
|
582
618
|
const latest = doGetWriteCharacteristic();
|
|
@@ -586,23 +622,19 @@ async function transmitHexDataToDevice(deviceId: string, hexData: string): Promi
|
|
|
586
622
|
`Write characteristic not available for ${deviceId}`
|
|
587
623
|
);
|
|
588
624
|
}
|
|
589
|
-
await
|
|
590
|
-
if (offset < toBuffer.length) {
|
|
591
|
-
await wait(UNIFIED_WRITE_DELAY);
|
|
592
|
-
}
|
|
625
|
+
await writeCharacteristicWithoutResponse(deviceId, latest, chunk);
|
|
593
626
|
}
|
|
594
627
|
return;
|
|
595
628
|
}
|
|
596
629
|
|
|
597
630
|
// Windows unpaired path: use loop
|
|
598
|
-
if (toBuffer.length <=
|
|
599
|
-
await wait(UNIFIED_WRITE_DELAY);
|
|
631
|
+
if (toBuffer.length <= packetCapacity) {
|
|
600
632
|
await attemptWindowsWriteUntilPaired(deviceId, doGetWriteCharacteristic, toBuffer, 'single');
|
|
601
633
|
return;
|
|
602
634
|
}
|
|
603
635
|
// chunked loop
|
|
604
636
|
for (let offset = 0, idx = 0; offset < toBuffer.length; idx++) {
|
|
605
|
-
const chunkSize = Math.min(
|
|
637
|
+
const chunkSize = Math.min(packetCapacity, toBuffer.length - offset);
|
|
606
638
|
const chunk = toBuffer.subarray(offset, offset + chunkSize);
|
|
607
639
|
offset += chunkSize;
|
|
608
640
|
await attemptWindowsWriteUntilPaired(
|
|
@@ -611,9 +643,6 @@ async function transmitHexDataToDevice(deviceId: string, hexData: string): Promi
|
|
|
611
643
|
chunk,
|
|
612
644
|
`chunk-${idx + 1}`
|
|
613
645
|
);
|
|
614
|
-
if (offset < toBuffer.length) {
|
|
615
|
-
await wait(UNIFIED_WRITE_DELAY);
|
|
616
|
-
}
|
|
617
646
|
}
|
|
618
647
|
}
|
|
619
648
|
|
|
@@ -835,6 +864,7 @@ function getDevice(deviceId: string): DeviceInfo | null {
|
|
|
835
864
|
id: peripheral.id,
|
|
836
865
|
name: deviceName,
|
|
837
866
|
state: peripheral.state || 'disconnected',
|
|
867
|
+
...(typeof peripheral.mtu === 'number' ? { mtu: peripheral.mtu } : {}),
|
|
838
868
|
};
|
|
839
869
|
}
|
|
840
870
|
|
|
@@ -847,6 +877,7 @@ function getDevice(deviceId: string): DeviceInfo | null {
|
|
|
847
877
|
id: connectedPeripheral.id,
|
|
848
878
|
name: deviceName,
|
|
849
879
|
state: connectedPeripheral.state || 'connected',
|
|
880
|
+
...(typeof connectedPeripheral.mtu === 'number' ? { mtu: connectedPeripheral.mtu } : {}),
|
|
850
881
|
};
|
|
851
882
|
}
|
|
852
883
|
|
package/src/types/desktop-api.ts
CHANGED
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
// Noble BLE API interface - core BLE functionality
|
|
7
7
|
export interface NobleBleAPI {
|
|
8
8
|
enumerate: () => Promise<{ id: string; name: string }[]>;
|
|
9
|
-
getDevice: (uuid: string) => Promise<{ id: string; name: string } | null>;
|
|
9
|
+
getDevice: (uuid: string) => Promise<{ id: string; name: string; mtu?: number } | null>;
|
|
10
10
|
connect: (uuid: string) => Promise<void>;
|
|
11
11
|
disconnect: (uuid: string) => Promise<void>;
|
|
12
12
|
subscribe: (uuid: string) => Promise<void>;
|
|
13
13
|
unsubscribe: (uuid: string) => Promise<void>;
|
|
14
14
|
write: (uuid: string, data: string) => Promise<void>;
|
|
15
15
|
onNotification: (callback: (deviceId: string, data: string) => void) => () => void;
|
|
16
|
+
onMtuChanged?: (callback: (device: { id: string; mtu: number }) => void) => () => void;
|
|
16
17
|
onDeviceDisconnected: (callback: (device: { id: string; name: string }) => void) => () => void;
|
|
17
18
|
checkAvailability: () => Promise<{
|
|
18
19
|
available: boolean;
|