@onekeyfe/hd-transport-web-device 1.2.0-alpha.2 → 1.2.0-alpha.21
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/__tests__/electron-ble-transport.test.ts +102 -8
- package/__tests__/webusb-protocol-v2-timeout.test.ts +63 -0
- package/dist/electron-ble-transport.d.ts +4 -4
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +96 -4
- package/dist/index.js +162 -177
- package/dist/transportLog.d.ts +7 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/dist/webusb.d.ts +2 -0
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/electron-ble-transport.ts +111 -138
- package/src/transportLog.ts +11 -0
- package/src/webusb.ts +76 -78
package/dist/index.js
CHANGED
|
@@ -41,6 +41,14 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
41
41
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
const HIGH_VOLUME_CALLS = new Set(['FileWrite', 'FilesystemFileWrite', 'EmmcFileWrite']);
|
|
45
|
+
function shouldSuppressHighVolumeCallLog(name) {
|
|
46
|
+
return HIGH_VOLUME_CALLS.has(name);
|
|
47
|
+
}
|
|
48
|
+
function createTransportCallLog(name, protocol) {
|
|
49
|
+
return { name, protocol };
|
|
50
|
+
}
|
|
51
|
+
|
|
44
52
|
const { parseConfigure: parseConfigure$1, check: check$1, ProtocolV1: ProtocolV1$1 } = transport__default["default"];
|
|
45
53
|
const CONFIGURATION_ID = 1;
|
|
46
54
|
const INTERFACE_ID = 0;
|
|
@@ -52,19 +60,6 @@ const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
|
52
60
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
53
61
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
54
62
|
const PROTOCOL_PROBE_TIMEOUT = 1000;
|
|
55
|
-
const WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
|
|
56
|
-
function shouldSuppressWebUsbCallLog(name) {
|
|
57
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
58
|
-
return WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
59
|
-
}
|
|
60
|
-
function isLogBlockCommand$1(name) {
|
|
61
|
-
var _a, _b;
|
|
62
|
-
return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
|
|
63
|
-
}
|
|
64
|
-
function shouldBlockWebUsbCallDataLog(name) {
|
|
65
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
66
|
-
return isLogBlockCommand$1(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
67
|
-
}
|
|
68
63
|
function inferProtocolHintFromDeviceName$1(name) {
|
|
69
64
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
70
65
|
}
|
|
@@ -74,6 +69,7 @@ class WebUsbTransport {
|
|
|
74
69
|
this.deviceProtocolHints = new Map();
|
|
75
70
|
this.protocolV2Assemblers = new Map();
|
|
76
71
|
this.protocolV2Sessions = new Map();
|
|
72
|
+
this.protocolV2Sequences = new Map();
|
|
77
73
|
this.protocolV2ReadTimeouts = new Map();
|
|
78
74
|
this.deviceEndpoints = new Map();
|
|
79
75
|
this.mockSerialPaths = new WeakMap();
|
|
@@ -100,11 +96,9 @@ class WebUsbTransport {
|
|
|
100
96
|
this.messages = messages;
|
|
101
97
|
}
|
|
102
98
|
configureProtocolV2(signedData) {
|
|
103
|
-
var _a;
|
|
104
99
|
this.messagesV2 = parseConfigure$1(signedData);
|
|
105
100
|
this.protocolV2Sessions.clear();
|
|
106
101
|
this.protocolV2ReadTimeouts.clear();
|
|
107
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] Protocol V2 schema configured');
|
|
108
102
|
}
|
|
109
103
|
promptDeviceAccess() {
|
|
110
104
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -145,7 +139,10 @@ class WebUsbTransport {
|
|
|
145
139
|
if (!this.usb)
|
|
146
140
|
return [];
|
|
147
141
|
const devices = yield this.usb.getDevices();
|
|
148
|
-
const onekeyDevices = devices.filter(dev =>
|
|
142
|
+
const onekeyDevices = devices.filter(dev => {
|
|
143
|
+
const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
|
|
144
|
+
return isOneKey && !hdShared.isKnownTrezorWebUsbDevice(dev);
|
|
145
|
+
});
|
|
149
146
|
this.deviceList = onekeyDevices.map(device => {
|
|
150
147
|
const path = this.getDevicePath(device);
|
|
151
148
|
const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
|
|
@@ -158,10 +155,6 @@ class WebUsbTransport {
|
|
|
158
155
|
commType: 'webusb',
|
|
159
156
|
};
|
|
160
157
|
});
|
|
161
|
-
for (const dev of onekeyDevices) {
|
|
162
|
-
this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
|
|
163
|
-
`VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
|
|
164
|
-
}
|
|
165
158
|
return this.deviceList;
|
|
166
159
|
});
|
|
167
160
|
}
|
|
@@ -200,14 +193,13 @@ class WebUsbTransport {
|
|
|
200
193
|
if (expectedProtocol === 'V1') {
|
|
201
194
|
if (yield this.probeProtocolV1(path)) {
|
|
202
195
|
this.deviceProtocol.set(path, 'V1');
|
|
203
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
204
196
|
return 'V1';
|
|
205
197
|
}
|
|
198
|
+
yield this.resetConnectionAfterProbe(path);
|
|
206
199
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
207
200
|
}
|
|
208
201
|
if (expectedProtocol === 'V2') {
|
|
209
202
|
this.deviceProtocol.set(path, 'V2');
|
|
210
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
211
203
|
return 'V2';
|
|
212
204
|
}
|
|
213
205
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
@@ -215,9 +207,11 @@ class WebUsbTransport {
|
|
|
215
207
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
|
|
216
208
|
if (detected) {
|
|
217
209
|
this.deviceProtocol.set(path, protocol);
|
|
218
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> ${protocol}`);
|
|
219
210
|
return protocol;
|
|
220
211
|
}
|
|
212
|
+
if (protocol === 'V1') {
|
|
213
|
+
yield this.resetConnectionAfterProbe(path);
|
|
214
|
+
}
|
|
221
215
|
}
|
|
222
216
|
this.deviceProtocol.delete(path);
|
|
223
217
|
throw this.createProtocolDetectionError();
|
|
@@ -287,7 +281,6 @@ class WebUsbTransport {
|
|
|
287
281
|
var _a, _b;
|
|
288
282
|
return __awaiter(this, void 0, void 0, function* () {
|
|
289
283
|
let device = yield this.findDevice(path);
|
|
290
|
-
this.Log.debug('[WebUsbTransport] connecting to device:', device.productName, 'PID:', device.productId);
|
|
291
284
|
if (!device.opened) {
|
|
292
285
|
yield device.open();
|
|
293
286
|
}
|
|
@@ -420,19 +413,11 @@ class WebUsbTransport {
|
|
|
420
413
|
return copied.buffer;
|
|
421
414
|
}
|
|
422
415
|
transferOutWithRetry(path, packet) {
|
|
423
|
-
var _a;
|
|
424
416
|
return __awaiter(this, void 0, void 0, function* () {
|
|
425
417
|
let lastError;
|
|
426
418
|
for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt += 1) {
|
|
427
419
|
try {
|
|
428
|
-
|
|
429
|
-
if (!device.opened) {
|
|
430
|
-
yield this.connect(path, false);
|
|
431
|
-
}
|
|
432
|
-
const endpoints = this.deviceEndpoints.get(path);
|
|
433
|
-
const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
434
|
-
const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
435
|
-
yield device.transferOut(endpointOut, transferBuffer);
|
|
420
|
+
yield this.transferOutOnce(path, packet);
|
|
436
421
|
return;
|
|
437
422
|
}
|
|
438
423
|
catch (error) {
|
|
@@ -453,6 +438,19 @@ class WebUsbTransport {
|
|
|
453
438
|
throw lastError;
|
|
454
439
|
});
|
|
455
440
|
}
|
|
441
|
+
transferOutOnce(path, packet) {
|
|
442
|
+
var _a;
|
|
443
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
444
|
+
const device = yield this.findDevice(path);
|
|
445
|
+
if (!device.opened) {
|
|
446
|
+
yield this.connect(path, false);
|
|
447
|
+
}
|
|
448
|
+
const endpoints = this.deviceEndpoints.get(path);
|
|
449
|
+
const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
450
|
+
const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
451
|
+
yield device.transferOut(endpointOut, transferBuffer);
|
|
452
|
+
});
|
|
453
|
+
}
|
|
456
454
|
transferInWithRetry(path, length, cancelToken) {
|
|
457
455
|
var _a;
|
|
458
456
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -519,7 +517,7 @@ class WebUsbTransport {
|
|
|
519
517
|
yield this.connect(path, false);
|
|
520
518
|
});
|
|
521
519
|
}
|
|
522
|
-
withProtocolReadTimeout(
|
|
520
|
+
withProtocolReadTimeout(_path, promise, timeoutMs, protocol, onTimeout) {
|
|
523
521
|
return __awaiter(this, void 0, void 0, function* () {
|
|
524
522
|
let timer;
|
|
525
523
|
let timedOut = false;
|
|
@@ -534,11 +532,11 @@ class WebUsbTransport {
|
|
|
534
532
|
return yield Promise.race([
|
|
535
533
|
guardedPromise,
|
|
536
534
|
new Promise((_, reject) => {
|
|
537
|
-
timer = setTimeout(() =>
|
|
535
|
+
timer = setTimeout(() => {
|
|
538
536
|
timedOut = true;
|
|
539
537
|
onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
|
|
540
538
|
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
541
|
-
}
|
|
539
|
+
}, timeoutMs);
|
|
542
540
|
}),
|
|
543
541
|
]);
|
|
544
542
|
}
|
|
@@ -557,8 +555,7 @@ class WebUsbTransport {
|
|
|
557
555
|
yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
|
|
558
556
|
return true;
|
|
559
557
|
}
|
|
560
|
-
catch (
|
|
561
|
-
this.Log.debug('[WebUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
558
|
+
catch (_error) {
|
|
562
559
|
return false;
|
|
563
560
|
}
|
|
564
561
|
});
|
|
@@ -573,7 +570,6 @@ class WebUsbTransport {
|
|
|
573
570
|
timeoutMs: PROTOCOL_PROBE_TIMEOUT,
|
|
574
571
|
logger: this.Log,
|
|
575
572
|
logPrefix: 'ProtocolV2 WebUSB',
|
|
576
|
-
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
577
573
|
});
|
|
578
574
|
});
|
|
579
575
|
}
|
|
@@ -590,12 +586,8 @@ class WebUsbTransport {
|
|
|
590
586
|
if (!protocol) {
|
|
591
587
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
592
588
|
}
|
|
593
|
-
if (
|
|
594
|
-
|
|
595
|
-
this.Log.debug('call-', ' name: ', name, ' protocol: ', protocol);
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
this.Log.debug('call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
589
|
+
if (!shouldSuppressHighVolumeCallLog(name)) {
|
|
590
|
+
this.Log.debug('transport call', createTransportCallLog(name, protocol));
|
|
599
591
|
}
|
|
600
592
|
if (protocol === 'V2') {
|
|
601
593
|
return this.callProtocolV2(path, name, data, options);
|
|
@@ -636,13 +628,19 @@ class WebUsbTransport {
|
|
|
636
628
|
}
|
|
637
629
|
let session = this.protocolV2Sessions.get(path);
|
|
638
630
|
if (!session) {
|
|
631
|
+
let sequenceCursor = this.protocolV2Sequences.get(path);
|
|
632
|
+
if (!sequenceCursor) {
|
|
633
|
+
sequenceCursor = new transport.ProtocolV2SequenceCursor();
|
|
634
|
+
this.protocolV2Sequences.set(path, sequenceCursor);
|
|
635
|
+
}
|
|
639
636
|
session = new transport.ProtocolV2Session({
|
|
640
637
|
schemas: {
|
|
641
638
|
protocolV1: protocolV1Messages,
|
|
642
639
|
protocolV2: this.messagesV2,
|
|
643
640
|
},
|
|
644
641
|
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
645
|
-
|
|
642
|
+
sequenceCursor,
|
|
643
|
+
writeFrame: (frame) => this.transferOutOnce(path, frame),
|
|
646
644
|
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
647
645
|
logger: this.Log,
|
|
648
646
|
logPrefix: 'ProtocolV2 WebUSB',
|
|
@@ -655,6 +653,18 @@ class WebUsbTransport {
|
|
|
655
653
|
try {
|
|
656
654
|
return yield session.call(name, data, options);
|
|
657
655
|
}
|
|
656
|
+
catch (error) {
|
|
657
|
+
const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
658
|
+
if (message.includes('protocol v2 read timeout') || message.includes('response timeout')) {
|
|
659
|
+
try {
|
|
660
|
+
yield this.resetConnectionAfterProbe(path);
|
|
661
|
+
}
|
|
662
|
+
catch (resetError) {
|
|
663
|
+
this.Log.debug('[WebUsbTransport] Protocol V2 timeout reset failed:', resetError);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
throw error;
|
|
667
|
+
}
|
|
658
668
|
finally {
|
|
659
669
|
this.protocolV2ReadTimeouts.delete(path);
|
|
660
670
|
}
|
|
@@ -737,6 +747,8 @@ class WebUsbTransport {
|
|
|
737
747
|
this.deviceProtocolHints.delete(path);
|
|
738
748
|
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
739
749
|
this.protocolV2Assemblers.delete(path);
|
|
750
|
+
this.protocolV2Sessions.delete(path);
|
|
751
|
+
this.protocolV2ReadTimeouts.delete(path);
|
|
740
752
|
this.deviceEndpoints.delete(path);
|
|
741
753
|
});
|
|
742
754
|
}
|
|
@@ -745,15 +757,6 @@ class WebUsbTransport {
|
|
|
745
757
|
}
|
|
746
758
|
}
|
|
747
759
|
|
|
748
|
-
const FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
|
|
749
|
-
function shouldSuppressHighVolumeCallLog(name) {
|
|
750
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
751
|
-
return FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
752
|
-
}
|
|
753
|
-
function isLogBlockCommand(name) {
|
|
754
|
-
var _a, _b;
|
|
755
|
-
return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
|
|
756
|
-
}
|
|
757
760
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
758
761
|
function inferProtocolHintFromDeviceName(name) {
|
|
759
762
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
@@ -761,8 +764,6 @@ function inferProtocolHintFromDeviceName(name) {
|
|
|
761
764
|
const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
|
|
762
765
|
const BLE_PACKET_SIZE = 192;
|
|
763
766
|
const BLE_WRITE_DELAY_MS = 5;
|
|
764
|
-
const BLE_WRITE_MAX_RETRIES = 3;
|
|
765
|
-
const BLE_WRITE_RETRY_DELAY_MS = 300;
|
|
766
767
|
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
767
768
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
768
769
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
|
|
@@ -778,8 +779,27 @@ class ElectronBleTransport {
|
|
|
778
779
|
this.v2Assemblers = new Map();
|
|
779
780
|
this.v2FrameQueues = new Map();
|
|
780
781
|
this.v2FramePromises = new Map();
|
|
781
|
-
this.
|
|
782
|
-
|
|
782
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
783
|
+
getSchemas: () => {
|
|
784
|
+
if (!this._messages || !this._messagesV2) {
|
|
785
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
786
|
+
}
|
|
787
|
+
return {
|
|
788
|
+
protocolV1: this._messages,
|
|
789
|
+
protocolV2: this._messagesV2,
|
|
790
|
+
};
|
|
791
|
+
},
|
|
792
|
+
classifyError: () => 'link-fatal',
|
|
793
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
794
|
+
var _a, _b;
|
|
795
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
796
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
797
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
798
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
799
|
+
yield this.release(uuid);
|
|
800
|
+
}
|
|
801
|
+
}),
|
|
802
|
+
});
|
|
783
803
|
this.notificationCleanups = new Map();
|
|
784
804
|
this.disconnectCleanups = new Map();
|
|
785
805
|
this.notificationTokens = new Map();
|
|
@@ -815,15 +835,14 @@ class ElectronBleTransport {
|
|
|
815
835
|
throw error;
|
|
816
836
|
}
|
|
817
837
|
cleanupDeviceState(deviceId) {
|
|
818
|
-
|
|
838
|
+
this.protocolV2Links
|
|
839
|
+
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
840
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
819
841
|
this.connectedDevices.delete(deviceId);
|
|
820
842
|
this.deviceProtocol.delete(deviceId);
|
|
821
843
|
this.v1Buffers.delete(deviceId);
|
|
822
844
|
this.v2Assemblers.delete(deviceId);
|
|
823
845
|
this.resetProtocolV2Frames(deviceId);
|
|
824
|
-
if (((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === deviceId) {
|
|
825
|
-
this.activeProtocolV2Call = null;
|
|
826
|
-
}
|
|
827
846
|
this.notificationTokens.delete(deviceId);
|
|
828
847
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
829
848
|
if (notifyCleanup) {
|
|
@@ -850,9 +869,10 @@ class ElectronBleTransport {
|
|
|
850
869
|
this.configured = true;
|
|
851
870
|
}
|
|
852
871
|
configureProtocolV2(signedData) {
|
|
853
|
-
var _a;
|
|
854
872
|
this._messagesV2 = parseConfigure(signedData);
|
|
855
|
-
|
|
873
|
+
this.protocolV2Links
|
|
874
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
875
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
|
|
856
876
|
}
|
|
857
877
|
listen() {
|
|
858
878
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -890,12 +910,14 @@ class ElectronBleTransport {
|
|
|
890
910
|
if (!uuid) {
|
|
891
911
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
892
912
|
}
|
|
913
|
+
if (this.connectedDevices.has(uuid)) {
|
|
914
|
+
yield this.release(uuid);
|
|
915
|
+
}
|
|
893
916
|
if (forceCleanRunPromise && this.runPromise) {
|
|
894
917
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
895
918
|
this.runPromise.reject(error);
|
|
896
919
|
this.rejectAllProtocolV2Frames(error);
|
|
897
920
|
this.runPromise = null;
|
|
898
|
-
this.activeProtocolV2Call = null;
|
|
899
921
|
}
|
|
900
922
|
try {
|
|
901
923
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -963,6 +985,7 @@ class ElectronBleTransport {
|
|
|
963
985
|
var _a, _b;
|
|
964
986
|
return __awaiter(this, void 0, void 0, function* () {
|
|
965
987
|
try {
|
|
988
|
+
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
966
989
|
if (this.connectedDevices.has(id)) {
|
|
967
990
|
if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
|
|
968
991
|
yield window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -1036,14 +1059,12 @@ class ElectronBleTransport {
|
|
|
1036
1059
|
});
|
|
1037
1060
|
}
|
|
1038
1061
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1039
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
1062
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1040
1063
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1064
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1041
1065
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1042
1066
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1043
1067
|
this.resetProtocolV2Frames(uuid);
|
|
1044
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1045
|
-
this.activeProtocolV2Call = null;
|
|
1046
|
-
}
|
|
1047
1068
|
if (this.runPromise) {
|
|
1048
1069
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1049
1070
|
this.runPromise.reject(error);
|
|
@@ -1056,16 +1077,16 @@ class ElectronBleTransport {
|
|
|
1056
1077
|
}
|
|
1057
1078
|
this.notificationTokens.delete(uuid);
|
|
1058
1079
|
try {
|
|
1059
|
-
yield ((
|
|
1080
|
+
yield ((_c = (_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) === null || _c === void 0 ? void 0 : _c.unsubscribe(uuid));
|
|
1060
1081
|
}
|
|
1061
1082
|
catch (error) {
|
|
1062
|
-
(
|
|
1083
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1063
1084
|
}
|
|
1064
1085
|
try {
|
|
1065
|
-
yield ((
|
|
1086
|
+
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.subscribe(uuid));
|
|
1066
1087
|
}
|
|
1067
1088
|
catch (error) {
|
|
1068
|
-
(
|
|
1089
|
+
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1069
1090
|
throw error;
|
|
1070
1091
|
}
|
|
1071
1092
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
@@ -1120,52 +1141,40 @@ class ElectronBleTransport {
|
|
|
1120
1141
|
const totalBytes = hexData.length / 2;
|
|
1121
1142
|
if (totalBytes <= BLE_PACKET_SIZE) {
|
|
1122
1143
|
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1123
|
-
yield this.
|
|
1144
|
+
yield this.writeOnce(uuid, hexData);
|
|
1124
1145
|
return;
|
|
1125
1146
|
}
|
|
1126
1147
|
for (let offset = 0; offset < hexData.length;) {
|
|
1127
1148
|
const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
|
|
1128
1149
|
const chunkHex = hexData.substring(offset, offset + chunkHexLen);
|
|
1129
1150
|
offset += chunkHexLen;
|
|
1130
|
-
yield this.
|
|
1151
|
+
yield this.writeOnce(uuid, chunkHex);
|
|
1131
1152
|
if (offset < hexData.length) {
|
|
1132
1153
|
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1133
1154
|
}
|
|
1134
1155
|
}
|
|
1135
1156
|
});
|
|
1136
1157
|
}
|
|
1137
|
-
|
|
1138
|
-
var _a
|
|
1158
|
+
writeOnce(uuid, hexData) {
|
|
1159
|
+
var _a;
|
|
1139
1160
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1140
|
-
let lastError;
|
|
1141
1161
|
const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
|
|
1142
1162
|
if (!nobleBle) {
|
|
1143
1163
|
throw new Error('Noble BLE API not available');
|
|
1144
1164
|
}
|
|
1145
|
-
|
|
1146
|
-
try {
|
|
1147
|
-
yield nobleBle.write(uuid, hexData);
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
catch (error) {
|
|
1151
|
-
lastError = error;
|
|
1152
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error(`[Electron BLE] write failed (attempt ${attempt}/${BLE_WRITE_MAX_RETRIES}):`, error);
|
|
1153
|
-
if (attempt < BLE_WRITE_MAX_RETRIES) {
|
|
1154
|
-
yield hdShared.wait(BLE_WRITE_RETRY_DELAY_MS);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write failed after ${BLE_WRITE_MAX_RETRIES} attempts: ${(_c = lastError === null || lastError === void 0 ? void 0 : lastError.message) !== null && _c !== void 0 ? _c : lastError}`);
|
|
1165
|
+
yield nobleBle.write(uuid, hexData);
|
|
1159
1166
|
});
|
|
1160
1167
|
}
|
|
1161
1168
|
handleNotification(deviceId, hexData) {
|
|
1162
1169
|
var _a, _b;
|
|
1163
1170
|
if (hexData === 'PAIRING_REJECTED') {
|
|
1164
1171
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
|
|
1165
|
-
|
|
1166
|
-
|
|
1172
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
|
|
1173
|
+
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
1174
|
+
this.rejectProtocolV2Frames(deviceId, error);
|
|
1175
|
+
}
|
|
1176
|
+
else if (this.runPromise) {
|
|
1167
1177
|
this.runPromise.reject(error);
|
|
1168
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1169
1178
|
}
|
|
1170
1179
|
return;
|
|
1171
1180
|
}
|
|
@@ -1181,13 +1190,8 @@ class ElectronBleTransport {
|
|
|
1181
1190
|
this.handleProtocolV1Notification(deviceId, hexData);
|
|
1182
1191
|
}
|
|
1183
1192
|
handleProtocolV2Notification(deviceId, hexData) {
|
|
1184
|
-
var _a
|
|
1193
|
+
var _a;
|
|
1185
1194
|
try {
|
|
1186
|
-
if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== deviceId) {
|
|
1187
|
-
(_b = this.v2Assemblers.get(deviceId)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1188
|
-
this.resetProtocolV2Frames(deviceId);
|
|
1189
|
-
return;
|
|
1190
|
-
}
|
|
1191
1195
|
const bytes = transport.hexToBytes(hexData);
|
|
1192
1196
|
if (bytes.length === 0)
|
|
1193
1197
|
return;
|
|
@@ -1199,12 +1203,9 @@ class ElectronBleTransport {
|
|
|
1199
1203
|
}
|
|
1200
1204
|
}
|
|
1201
1205
|
catch (error) {
|
|
1202
|
-
(
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
this.runPromise.reject(notifyError);
|
|
1206
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
1207
|
-
}
|
|
1206
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 notification error:', error);
|
|
1207
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1208
|
+
this.rejectProtocolV2Frames(deviceId, notifyError);
|
|
1208
1209
|
}
|
|
1209
1210
|
}
|
|
1210
1211
|
getProtocolV2FrameQueue(uuid) {
|
|
@@ -1235,9 +1236,13 @@ class ElectronBleTransport {
|
|
|
1235
1236
|
this.v2FrameQueues.delete(uuid);
|
|
1236
1237
|
this.v2FramePromises.delete(uuid);
|
|
1237
1238
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1239
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1240
|
+
this.v2FrameQueues.delete(uuid);
|
|
1241
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
1242
|
+
if (framePromise) {
|
|
1243
|
+
this.v2FramePromises.delete(uuid);
|
|
1244
|
+
framePromise.reject(error);
|
|
1245
|
+
}
|
|
1241
1246
|
}
|
|
1242
1247
|
readProtocolV2Frame(uuid) {
|
|
1243
1248
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1272,7 +1277,7 @@ class ElectronBleTransport {
|
|
|
1272
1277
|
}
|
|
1273
1278
|
}
|
|
1274
1279
|
call(uuid, name, data, options) {
|
|
1275
|
-
var _a
|
|
1280
|
+
var _a;
|
|
1276
1281
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1277
1282
|
if (!this._messages) {
|
|
1278
1283
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
@@ -1284,12 +1289,8 @@ class ElectronBleTransport {
|
|
|
1284
1289
|
if (!protocol) {
|
|
1285
1290
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1286
1291
|
}
|
|
1287
|
-
if (shouldSuppressHighVolumeCallLog(name))
|
|
1288
|
-
|
|
1289
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
|
|
1290
|
-
}
|
|
1291
|
-
else {
|
|
1292
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
|
|
1292
|
+
if (!shouldSuppressHighVolumeCallLog(name)) {
|
|
1293
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', createTransportCallLog(name, protocol));
|
|
1293
1294
|
}
|
|
1294
1295
|
if (protocol === 'V2') {
|
|
1295
1296
|
return this.callProtocolV2(uuid, name, data, options);
|
|
@@ -1360,76 +1361,60 @@ class ElectronBleTransport {
|
|
|
1360
1361
|
});
|
|
1361
1362
|
}
|
|
1362
1363
|
callProtocolV2(uuid, name, data, options) {
|
|
1363
|
-
var _a, _b
|
|
1364
|
+
var _a, _b;
|
|
1364
1365
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1365
1366
|
if (!this._messages || !this._messagesV2) {
|
|
1366
1367
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1367
1368
|
}
|
|
1368
|
-
const
|
|
1369
|
-
if (this.runPromise) {
|
|
1370
|
-
if (!forceRun) {
|
|
1371
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1372
|
-
}
|
|
1373
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1374
|
-
this.runPromise.reject(error);
|
|
1375
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1376
|
-
this.runPromise = null;
|
|
1377
|
-
this.activeProtocolV2Call = null;
|
|
1378
|
-
}
|
|
1379
|
-
const runPromise = hdShared.createDeferred();
|
|
1380
|
-
runPromise.promise.catch(() => undefined);
|
|
1381
|
-
this.runPromise = runPromise;
|
|
1382
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1383
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1384
|
-
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1385
|
-
this.resetProtocolV2Frames(uuid);
|
|
1386
|
-
let completed = false;
|
|
1387
|
-
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
|
|
1369
|
+
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : BLE_RESPONSE_TIMEOUT_MS });
|
|
1388
1370
|
try {
|
|
1389
|
-
|
|
1390
|
-
schemas: {
|
|
1391
|
-
protocolV1: this._messages,
|
|
1392
|
-
protocolV2: this._messagesV2,
|
|
1393
|
-
},
|
|
1394
|
-
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1395
|
-
writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
|
|
1396
|
-
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1397
|
-
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1398
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1399
|
-
throw new Error('Response is not Uint8Array');
|
|
1400
|
-
}
|
|
1401
|
-
return rxFrame;
|
|
1402
|
-
}),
|
|
1403
|
-
logger: this.Log,
|
|
1404
|
-
logPrefix: 'ProtocolV2 BLE',
|
|
1405
|
-
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1406
|
-
});
|
|
1407
|
-
const result = yield session.call(name, data, callOptions);
|
|
1408
|
-
completed = true;
|
|
1409
|
-
return result;
|
|
1371
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1410
1372
|
}
|
|
1411
1373
|
catch (e) {
|
|
1412
|
-
|
|
1413
|
-
(_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1414
|
-
this.resetProtocolV2Frames(uuid);
|
|
1415
|
-
}
|
|
1416
|
-
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1374
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1417
1375
|
throw e;
|
|
1418
1376
|
}
|
|
1419
|
-
finally {
|
|
1420
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1421
|
-
if (!completed) {
|
|
1422
|
-
(_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
|
|
1423
|
-
}
|
|
1424
|
-
this.resetProtocolV2Frames(uuid);
|
|
1425
|
-
this.activeProtocolV2Call = null;
|
|
1426
|
-
}
|
|
1427
|
-
if (this.runPromise === runPromise) {
|
|
1428
|
-
this.runPromise = null;
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
1377
|
});
|
|
1432
1378
|
}
|
|
1379
|
+
createProtocolV2Adapter(uuid) {
|
|
1380
|
+
var _a;
|
|
1381
|
+
const generation = (_a = this.notificationTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1382
|
+
const assertCurrentGeneration = () => {
|
|
1383
|
+
if (this.notificationTokens.get(uuid) !== generation) {
|
|
1384
|
+
throw new Error(`Protocol V2 notification generation changed for ${uuid}`);
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
return {
|
|
1388
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1389
|
+
generation,
|
|
1390
|
+
prepareCall: () => {
|
|
1391
|
+
var _a;
|
|
1392
|
+
assertCurrentGeneration();
|
|
1393
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1394
|
+
this.resetProtocolV2Frames(uuid);
|
|
1395
|
+
},
|
|
1396
|
+
writeFrame: (frame) => {
|
|
1397
|
+
assertCurrentGeneration();
|
|
1398
|
+
return this.writeWithChunking(uuid, transport.bytesToHex(frame));
|
|
1399
|
+
},
|
|
1400
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1401
|
+
assertCurrentGeneration();
|
|
1402
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1403
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1404
|
+
throw new Error('Response is not Uint8Array');
|
|
1405
|
+
}
|
|
1406
|
+
return rxFrame;
|
|
1407
|
+
}),
|
|
1408
|
+
reset: (reason) => {
|
|
1409
|
+
var _a;
|
|
1410
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1411
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1412
|
+
},
|
|
1413
|
+
logger: this.Log,
|
|
1414
|
+
logPrefix: 'ProtocolV2 BLE',
|
|
1415
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1433
1418
|
processProtocolV1Notification(deviceId, hexData) {
|
|
1434
1419
|
try {
|
|
1435
1420
|
if (typeof hexData !== 'string') {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProtocolType } from '@onekeyfe/hd-transport';
|
|
2
|
+
export declare function shouldSuppressHighVolumeCallLog(name: string): boolean;
|
|
3
|
+
export declare function createTransportCallLog(name: string, protocol: ProtocolType): {
|
|
4
|
+
name: string;
|
|
5
|
+
protocol: ProtocolType;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=transportLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportLog.d.ts","sourceRoot":"","sources":["../src/transportLog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,WAE3D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY;;;EAE1E"}
|