@onekeyfe/hd-transport-usb 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__/protocol-v2-link.test.ts +387 -0
- package/dist/index.d.ts +86 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +190 -178
- package/dist/transportLog.d.ts +7 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/index.ts +239 -224
- package/src/transportLog.ts +11 -0
package/dist/index.js
CHANGED
|
@@ -59,6 +59,14 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
59
59
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
const HIGH_VOLUME_CALLS = new Set(['FileWrite', 'FilesystemFileWrite', 'EmmcFileWrite']);
|
|
63
|
+
function shouldSuppressHighVolumeCallLog(name) {
|
|
64
|
+
return HIGH_VOLUME_CALLS.has(name);
|
|
65
|
+
}
|
|
66
|
+
function createTransportCallLog(name, protocol) {
|
|
67
|
+
return { name, protocol };
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
63
71
|
const PACKET_SIZE = transport.PROTOCOL_V1_USB_PACKET_SIZE;
|
|
64
72
|
const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
|
|
@@ -71,7 +79,7 @@ const TRANSFER_TIMEOUT_MS = 30000;
|
|
|
71
79
|
const SERIAL_READ_TIMEOUT_MS = 5000;
|
|
72
80
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
73
81
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
74
|
-
const PROTOCOL_PROBE_TIMEOUT =
|
|
82
|
+
const PROTOCOL_PROBE_TIMEOUT = 5000;
|
|
75
83
|
function getBusId(dev) {
|
|
76
84
|
return `usb:${dev.busNumber}:${dev.deviceAddress}`;
|
|
77
85
|
}
|
|
@@ -132,46 +140,6 @@ function readSerialNumber(dev, openDevices) {
|
|
|
132
140
|
}
|
|
133
141
|
});
|
|
134
142
|
}
|
|
135
|
-
function transferInOnce(ep, length) {
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
ep.transfer(length, (err, data) => {
|
|
138
|
-
if (err)
|
|
139
|
-
return reject(err);
|
|
140
|
-
if (!data || data.length === 0)
|
|
141
|
-
return reject(new Error('Empty USB transfer'));
|
|
142
|
-
resolve(data);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
function transferOutOnce(ep, data) {
|
|
147
|
-
return new Promise((resolve, reject) => {
|
|
148
|
-
ep.transfer(data, (err) => {
|
|
149
|
-
if (err)
|
|
150
|
-
return reject(err);
|
|
151
|
-
resolve();
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
function resetUsbDevice(dev) {
|
|
156
|
-
return new Promise(resolve => {
|
|
157
|
-
const reset = dev.reset;
|
|
158
|
-
if (typeof reset !== 'function') {
|
|
159
|
-
resolve();
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
reset.call(dev, () => resolve());
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
function clearEndpointHalt(ep) {
|
|
166
|
-
return new Promise(resolve => {
|
|
167
|
-
const clearHalt = ep.clearHalt;
|
|
168
|
-
if (typeof clearHalt !== 'function') {
|
|
169
|
-
resolve();
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
clearHalt.call(ep, () => resolve());
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
143
|
function skipReportByte(packet) {
|
|
176
144
|
if (packet[0] === REPORT_ID) {
|
|
177
145
|
return packet.subarray(1);
|
|
@@ -181,8 +149,13 @@ function skipReportByte(packet) {
|
|
|
181
149
|
function toArrayBuffer(buf) {
|
|
182
150
|
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
183
151
|
}
|
|
184
|
-
class NodeUsbTransport {
|
|
152
|
+
class NodeUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
185
153
|
constructor() {
|
|
154
|
+
super({
|
|
155
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
156
|
+
maxFrameBytes: transport.PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
157
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
158
|
+
});
|
|
186
159
|
this.name = 'NodeUsbTransport';
|
|
187
160
|
this.version = '';
|
|
188
161
|
this.configured = false;
|
|
@@ -190,10 +163,8 @@ class NodeUsbTransport {
|
|
|
190
163
|
this.serialToBusId = new Map();
|
|
191
164
|
this.openDevices = new Map();
|
|
192
165
|
this.deviceProtocol = new Map();
|
|
193
|
-
this.protocolV2Assemblers = new Map();
|
|
194
|
-
this.protocolV2Sessions = new Map();
|
|
195
|
-
this.protocolV2ReadTimeouts = new Map();
|
|
196
166
|
this.reconnectLocks = new Map();
|
|
167
|
+
this.activeTransfers = new Map();
|
|
197
168
|
this.cancelled = false;
|
|
198
169
|
}
|
|
199
170
|
init(logger, emitter) {
|
|
@@ -208,15 +179,29 @@ class NodeUsbTransport {
|
|
|
208
179
|
return Promise.resolve();
|
|
209
180
|
}
|
|
210
181
|
configureProtocolV2(signedData) {
|
|
211
|
-
var _a;
|
|
212
182
|
this.messagesV2 = parseConfigure(signedData);
|
|
213
|
-
this.
|
|
214
|
-
this.protocolV2ReadTimeouts.clear();
|
|
215
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V2 schema configured');
|
|
183
|
+
this.invalidateAllProtocolV2UsbLinks('Protocol V2 schema reconfigured').catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] schema link cleanup failed:', error); });
|
|
216
184
|
}
|
|
217
185
|
listen() {
|
|
218
186
|
}
|
|
219
187
|
stop() {
|
|
188
|
+
var _a;
|
|
189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
this.cancelled = true;
|
|
191
|
+
yield this.cancelActiveTransfers();
|
|
192
|
+
try {
|
|
193
|
+
yield this.disposeProtocolV2UsbLinks('Node USB transport stopped');
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] stop link cleanup failed:', error);
|
|
197
|
+
}
|
|
198
|
+
yield Promise.allSettled(this.reconnectLocks.values());
|
|
199
|
+
yield this.cancelActiveTransfers();
|
|
200
|
+
yield Promise.all(Array.from(this.openDevices.keys(), path => this.closeOpenDevice(path)));
|
|
201
|
+
this.reconnectLocks.clear();
|
|
202
|
+
this.deviceProtocol.clear();
|
|
203
|
+
this.serialToBusId.clear();
|
|
204
|
+
});
|
|
220
205
|
}
|
|
221
206
|
post(path, name, data) {
|
|
222
207
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -274,6 +259,7 @@ class NodeUsbTransport {
|
|
|
274
259
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
|
|
275
260
|
}
|
|
276
261
|
try {
|
|
262
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'Node USB transport acquired');
|
|
277
263
|
yield this.closeOpenDevice(path);
|
|
278
264
|
yield this.openDevice(path);
|
|
279
265
|
yield this.detectProtocol(path, input.expectedProtocol);
|
|
@@ -287,9 +273,81 @@ class NodeUsbTransport {
|
|
|
287
273
|
}
|
|
288
274
|
release(path, _onclose) {
|
|
289
275
|
return __awaiter(this, void 0, void 0, function* () {
|
|
276
|
+
yield this.cancelActiveTransfers(path);
|
|
277
|
+
yield this.invalidateProtocolV2UsbLink(path, 'Node USB transport released');
|
|
290
278
|
yield this.closeOpenDevice(path);
|
|
291
279
|
this.deviceProtocol.delete(path);
|
|
292
|
-
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
cancelActiveTransfers(path) {
|
|
283
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
284
|
+
const transfers = Array.from(this.activeTransfers.entries()).filter(([, active]) => path === undefined || active.path === path);
|
|
285
|
+
transfers.forEach(([transfer]) => {
|
|
286
|
+
try {
|
|
287
|
+
transfer.cancel();
|
|
288
|
+
}
|
|
289
|
+
catch (_a) {
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
yield Promise.allSettled(transfers.map(([, active]) => active.settled));
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
createTrackedTransfer(path, endpoint, callback) {
|
|
296
|
+
let resolveSettled = () => undefined;
|
|
297
|
+
const settled = new Promise(resolve => {
|
|
298
|
+
resolveSettled = resolve;
|
|
299
|
+
});
|
|
300
|
+
const transfer = endpoint.makeTransfer(endpoint.timeout, (error, buffer, actualLength) => {
|
|
301
|
+
this.activeTransfers.delete(transfer);
|
|
302
|
+
resolveSettled();
|
|
303
|
+
callback(error, buffer, actualLength);
|
|
304
|
+
});
|
|
305
|
+
this.activeTransfers.set(transfer, { path, settled, resolveSettled });
|
|
306
|
+
return transfer;
|
|
307
|
+
}
|
|
308
|
+
transferInOnce(path, ep, length) {
|
|
309
|
+
return new Promise((resolve, reject) => {
|
|
310
|
+
const buffer = Buffer.alloc(length);
|
|
311
|
+
const transfer = this.createTrackedTransfer(path, ep, (error, _submittedBuffer, actualLength) => {
|
|
312
|
+
if (error) {
|
|
313
|
+
reject(error);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (actualLength <= 0) {
|
|
317
|
+
reject(new Error('Empty USB transfer'));
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
resolve(buffer.subarray(0, actualLength));
|
|
321
|
+
});
|
|
322
|
+
try {
|
|
323
|
+
transfer.submit(buffer);
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
const active = this.activeTransfers.get(transfer);
|
|
327
|
+
this.activeTransfers.delete(transfer);
|
|
328
|
+
active === null || active === void 0 ? void 0 : active.resolveSettled();
|
|
329
|
+
reject(error);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
transferOutOnce(path, ep, data) {
|
|
334
|
+
return new Promise((resolve, reject) => {
|
|
335
|
+
const transfer = this.createTrackedTransfer(path, ep, error => {
|
|
336
|
+
if (error) {
|
|
337
|
+
reject(error);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
resolve();
|
|
341
|
+
});
|
|
342
|
+
try {
|
|
343
|
+
transfer.submit(data);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
const active = this.activeTransfers.get(transfer);
|
|
347
|
+
this.activeTransfers.delete(transfer);
|
|
348
|
+
active === null || active === void 0 ? void 0 : active.resolveSettled();
|
|
349
|
+
reject(error);
|
|
350
|
+
}
|
|
293
351
|
});
|
|
294
352
|
}
|
|
295
353
|
closeOpenDevice(path) {
|
|
@@ -320,7 +378,7 @@ class NodeUsbTransport {
|
|
|
320
378
|
});
|
|
321
379
|
}
|
|
322
380
|
call(path, name, data, options) {
|
|
323
|
-
var _a
|
|
381
|
+
var _a;
|
|
324
382
|
return __awaiter(this, void 0, void 0, function* () {
|
|
325
383
|
this.cancelled = false;
|
|
326
384
|
if (!this.messages) {
|
|
@@ -333,11 +391,8 @@ class NodeUsbTransport {
|
|
|
333
391
|
if (!protocol) {
|
|
334
392
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
335
393
|
}
|
|
336
|
-
if (
|
|
337
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
394
|
+
if (!shouldSuppressHighVolumeCallLog(name)) {
|
|
395
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', createTransportCallLog(name, protocol));
|
|
341
396
|
}
|
|
342
397
|
if (protocol === 'V2') {
|
|
343
398
|
return this.callProtocolV2(path, name, data, options);
|
|
@@ -362,8 +417,6 @@ class NodeUsbTransport {
|
|
|
362
417
|
});
|
|
363
418
|
}
|
|
364
419
|
cancel() {
|
|
365
|
-
var _a;
|
|
366
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport cancel');
|
|
367
420
|
this.cancelled = true;
|
|
368
421
|
}
|
|
369
422
|
getOpenDevice(path) {
|
|
@@ -386,6 +439,9 @@ class NodeUsbTransport {
|
|
|
386
439
|
}
|
|
387
440
|
isRetryableError(error) {
|
|
388
441
|
const message = this.getErrorMessage(error).toLowerCase();
|
|
442
|
+
if (message.includes('cancelled') || message.includes('canceled')) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
389
445
|
return (message.includes('libusb') ||
|
|
390
446
|
message.includes('transfer') ||
|
|
391
447
|
message.includes('disconnected') ||
|
|
@@ -397,6 +453,10 @@ class NodeUsbTransport {
|
|
|
397
453
|
message.includes('timeout') ||
|
|
398
454
|
message.includes('interrupt'));
|
|
399
455
|
}
|
|
456
|
+
isUsbTransferTimeout(error) {
|
|
457
|
+
const message = this.getErrorMessage(error).toLowerCase();
|
|
458
|
+
return message.includes('timeout') || message.includes('timed_out');
|
|
459
|
+
}
|
|
400
460
|
getDeviceInterface(dev) {
|
|
401
461
|
var _a;
|
|
402
462
|
const { interfaces } = dev;
|
|
@@ -416,6 +476,7 @@ class NodeUsbTransport {
|
|
|
416
476
|
var _a, _b;
|
|
417
477
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
|
|
418
478
|
yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
|
|
479
|
+
yield this.rotateProtocolV2UsbGeneration(path, `Node USB Protocol V1 ${direction} reconnect attempt ${attempt}`);
|
|
419
480
|
try {
|
|
420
481
|
yield this.closeOpenDevice(path);
|
|
421
482
|
}
|
|
@@ -449,7 +510,7 @@ class NodeUsbTransport {
|
|
|
449
510
|
const packet = new Uint8Array(PACKET_SIZE);
|
|
450
511
|
packet[0] = REPORT_ID;
|
|
451
512
|
packet.set(new Uint8Array(buffer), 1);
|
|
452
|
-
yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(packet));
|
|
513
|
+
yield this.transferOutOnce(path, this.getOpenDevice(path).epOut, Buffer.from(packet));
|
|
453
514
|
}
|
|
454
515
|
return;
|
|
455
516
|
}
|
|
@@ -472,7 +533,7 @@ class NodeUsbTransport {
|
|
|
472
533
|
throw lastError;
|
|
473
534
|
});
|
|
474
535
|
}
|
|
475
|
-
transferInWithRetry(path, openDev, length) {
|
|
536
|
+
transferInWithRetry(path, openDev, length, options) {
|
|
476
537
|
var _a;
|
|
477
538
|
return __awaiter(this, void 0, void 0, function* () {
|
|
478
539
|
let lastError;
|
|
@@ -482,21 +543,26 @@ class NodeUsbTransport {
|
|
|
482
543
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
483
544
|
}
|
|
484
545
|
try {
|
|
485
|
-
return yield transferInOnce(currentDev.epIn, length);
|
|
546
|
+
return yield this.transferInOnce(path, currentDev.epIn, length);
|
|
486
547
|
}
|
|
487
548
|
catch (error) {
|
|
488
549
|
lastError = error;
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
throw error;
|
|
492
|
-
}
|
|
493
|
-
try {
|
|
494
|
-
currentDev = yield this.reconnectForRetry(path, 'in', attempt, error);
|
|
550
|
+
if ((options === null || options === void 0 ? void 0 : options.waitIndefinitelyOnTimeout) && this.isUsbTransferTimeout(error)) {
|
|
551
|
+
attempt -= 1;
|
|
495
552
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
(
|
|
499
|
-
|
|
553
|
+
else {
|
|
554
|
+
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
555
|
+
if (!shouldRetry) {
|
|
556
|
+
throw error;
|
|
557
|
+
}
|
|
558
|
+
try {
|
|
559
|
+
currentDev = yield this.reconnectForRetry(path, 'in', attempt, error);
|
|
560
|
+
}
|
|
561
|
+
catch (reconnectError) {
|
|
562
|
+
lastError = reconnectError;
|
|
563
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
500
566
|
}
|
|
501
567
|
}
|
|
502
568
|
}
|
|
@@ -518,13 +584,6 @@ class NodeUsbTransport {
|
|
|
518
584
|
try {
|
|
519
585
|
dev.open();
|
|
520
586
|
dev.timeout = TRANSFER_TIMEOUT_MS;
|
|
521
|
-
yield resetUsbDevice(dev);
|
|
522
|
-
try {
|
|
523
|
-
dev.open();
|
|
524
|
-
}
|
|
525
|
-
catch (_d) {
|
|
526
|
-
}
|
|
527
|
-
dev.timeout = TRANSFER_TIMEOUT_MS;
|
|
528
587
|
const iface = this.getDeviceInterface(dev);
|
|
529
588
|
if (process.platform === 'linux') {
|
|
530
589
|
try {
|
|
@@ -532,7 +591,7 @@ class NodeUsbTransport {
|
|
|
532
591
|
iface.detachKernelDriver();
|
|
533
592
|
}
|
|
534
593
|
}
|
|
535
|
-
catch (
|
|
594
|
+
catch (_d) {
|
|
536
595
|
}
|
|
537
596
|
}
|
|
538
597
|
iface.claim();
|
|
@@ -543,29 +602,27 @@ class NodeUsbTransport {
|
|
|
543
602
|
}
|
|
544
603
|
epIn.timeout = TRANSFER_TIMEOUT_MS;
|
|
545
604
|
epOut.timeout = TRANSFER_TIMEOUT_MS;
|
|
546
|
-
yield
|
|
547
|
-
yield clearEndpointHalt(epOut);
|
|
548
|
-
yield this.drainStaleInput(epIn);
|
|
605
|
+
yield this.drainStaleInput(path, epIn);
|
|
549
606
|
this.openDevices.set(path, { device: dev, iface, epIn, epOut });
|
|
550
607
|
}
|
|
551
608
|
catch (err) {
|
|
552
609
|
try {
|
|
553
610
|
dev.close();
|
|
554
611
|
}
|
|
555
|
-
catch (
|
|
612
|
+
catch (_e) {
|
|
556
613
|
}
|
|
557
614
|
throw err;
|
|
558
615
|
}
|
|
559
616
|
});
|
|
560
617
|
}
|
|
561
|
-
drainStaleInput(epIn) {
|
|
618
|
+
drainStaleInput(path, epIn) {
|
|
562
619
|
return __awaiter(this, void 0, void 0, function* () {
|
|
563
620
|
const originalTimeout = epIn.timeout;
|
|
564
621
|
epIn.timeout = 50;
|
|
565
622
|
try {
|
|
566
623
|
for (let index = 0; index < 16; index += 1) {
|
|
567
624
|
try {
|
|
568
|
-
yield transferInOnce(epIn, PACKET_SIZE);
|
|
625
|
+
yield this.transferInOnce(path, epIn, PACKET_SIZE);
|
|
569
626
|
}
|
|
570
627
|
catch (_a) {
|
|
571
628
|
break;
|
|
@@ -584,37 +641,30 @@ class NodeUsbTransport {
|
|
|
584
641
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
|
|
585
642
|
}
|
|
586
643
|
detectProtocol(path, expectedProtocol) {
|
|
587
|
-
var _a
|
|
644
|
+
var _a;
|
|
588
645
|
return __awaiter(this, void 0, void 0, function* () {
|
|
646
|
+
if (expectedProtocol === 'V2') {
|
|
647
|
+
this.deviceProtocol.set(path, 'V2');
|
|
648
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
649
|
+
return 'V2';
|
|
650
|
+
}
|
|
589
651
|
if (expectedProtocol === 'V1') {
|
|
590
652
|
if (yield this.probeProtocolV1(path)) {
|
|
591
653
|
this.deviceProtocol.set(path, 'V1');
|
|
592
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
593
654
|
return 'V1';
|
|
594
655
|
}
|
|
595
656
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
596
657
|
}
|
|
597
|
-
if (expectedProtocol === 'V2') {
|
|
598
|
-
if (yield this.probeProtocolV2(path)) {
|
|
599
|
-
this.deviceProtocol.set(path, 'V2');
|
|
600
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
601
|
-
return 'V2';
|
|
602
|
-
}
|
|
603
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
604
|
-
}
|
|
605
658
|
if (this.deviceProtocol.get(path) === 'V2' && (yield this.probeProtocolV2(path))) {
|
|
606
659
|
this.deviceProtocol.set(path, 'V2');
|
|
607
|
-
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
|
|
608
660
|
return 'V2';
|
|
609
661
|
}
|
|
610
662
|
if (yield this.probeProtocolV1(path)) {
|
|
611
663
|
this.deviceProtocol.set(path, 'V1');
|
|
612
|
-
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1`);
|
|
613
664
|
return 'V1';
|
|
614
665
|
}
|
|
615
666
|
if (yield this.probeProtocolV2(path)) {
|
|
616
667
|
this.deviceProtocol.set(path, 'V2');
|
|
617
|
-
(_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2`);
|
|
618
668
|
return 'V2';
|
|
619
669
|
}
|
|
620
670
|
this.deviceProtocol.delete(path);
|
|
@@ -622,16 +672,15 @@ class NodeUsbTransport {
|
|
|
622
672
|
});
|
|
623
673
|
}
|
|
624
674
|
resetConnectionAfterProbe(path) {
|
|
625
|
-
var _a
|
|
675
|
+
var _a;
|
|
626
676
|
return __awaiter(this, void 0, void 0, function* () {
|
|
627
|
-
|
|
628
|
-
this.protocolV2Sessions.delete(path);
|
|
629
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
677
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'Node USB protocol probe reset');
|
|
630
678
|
try {
|
|
679
|
+
yield this.cancelActiveTransfers(path);
|
|
631
680
|
yield this.closeOpenDevice(path);
|
|
632
681
|
}
|
|
633
682
|
catch (error) {
|
|
634
|
-
(
|
|
683
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] close after protocol probe error:', error);
|
|
635
684
|
}
|
|
636
685
|
yield this.enumerate();
|
|
637
686
|
yield this.openDevice(path);
|
|
@@ -675,7 +724,6 @@ class NodeUsbTransport {
|
|
|
675
724
|
});
|
|
676
725
|
}
|
|
677
726
|
probeProtocolV1(path) {
|
|
678
|
-
var _a;
|
|
679
727
|
return __awaiter(this, void 0, void 0, function* () {
|
|
680
728
|
if (!this.messages) {
|
|
681
729
|
return false;
|
|
@@ -684,8 +732,7 @@ class NodeUsbTransport {
|
|
|
684
732
|
yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
|
|
685
733
|
return true;
|
|
686
734
|
}
|
|
687
|
-
catch (
|
|
688
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
735
|
+
catch (_error) {
|
|
689
736
|
return false;
|
|
690
737
|
}
|
|
691
738
|
});
|
|
@@ -704,96 +751,61 @@ class NodeUsbTransport {
|
|
|
704
751
|
});
|
|
705
752
|
});
|
|
706
753
|
}
|
|
707
|
-
|
|
708
|
-
|
|
754
|
+
getProtocolV2UsbSchemas() {
|
|
755
|
+
if (!this.messages || !this.messagesV2) {
|
|
756
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
protocolV1: this.messages,
|
|
760
|
+
protocolV2: this.messagesV2,
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
getProtocolV2UsbLogger() {
|
|
764
|
+
return this.Log;
|
|
765
|
+
}
|
|
766
|
+
writeProtocolV2UsbPacket(path, frame, _context) {
|
|
709
767
|
return __awaiter(this, void 0, void 0, function* () {
|
|
710
|
-
|
|
711
|
-
|
|
768
|
+
if (this.cancelled) {
|
|
769
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
770
|
+
}
|
|
771
|
+
yield this.transferOutOnce(path, this.getOpenDevice(path).epOut, Buffer.from(frame));
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
readProtocolV2UsbPacket(path, _context) {
|
|
775
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
776
|
+
for (;;) {
|
|
712
777
|
if (this.cancelled) {
|
|
713
778
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
714
779
|
}
|
|
715
780
|
try {
|
|
716
|
-
yield
|
|
717
|
-
return;
|
|
781
|
+
const packet = yield this.transferInOnce(path, this.getOpenDevice(path).epIn, transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
782
|
+
return new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
718
783
|
}
|
|
719
784
|
catch (error) {
|
|
720
|
-
|
|
721
|
-
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
722
|
-
if (!shouldRetry) {
|
|
785
|
+
if (!this.isUsbTransferTimeout(error)) {
|
|
723
786
|
throw error;
|
|
724
787
|
}
|
|
725
|
-
try {
|
|
726
|
-
yield this.reconnectForRetry(path, 'out', attempt, error);
|
|
727
|
-
}
|
|
728
|
-
catch (reconnectError) {
|
|
729
|
-
lastError = reconnectError;
|
|
730
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] Protocol V2 write reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
|
|
731
|
-
break;
|
|
732
|
-
}
|
|
733
788
|
}
|
|
734
789
|
}
|
|
735
|
-
throw lastError;
|
|
736
790
|
});
|
|
737
791
|
}
|
|
738
|
-
|
|
792
|
+
resetProtocolV2UsbNativeLink(path, _reason) {
|
|
739
793
|
return __awaiter(this, void 0, void 0, function* () {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
743
|
-
this.protocolV2Assemblers.set(path, assembler);
|
|
744
|
-
}
|
|
745
|
-
let frame = assembler.push(new Uint8Array(0));
|
|
746
|
-
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
747
|
-
while (!frame) {
|
|
748
|
-
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
749
|
-
const packet = deadline
|
|
750
|
-
? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2')
|
|
751
|
-
: yield transferIn;
|
|
752
|
-
const bytes = new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
753
|
-
try {
|
|
754
|
-
frame = assembler.push(bytes);
|
|
755
|
-
}
|
|
756
|
-
catch (error) {
|
|
757
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
return frame;
|
|
794
|
+
yield this.cancelActiveTransfers(path);
|
|
795
|
+
yield this.closeOpenDevice(path);
|
|
761
796
|
});
|
|
762
797
|
}
|
|
763
|
-
|
|
798
|
+
onProtocolV2UsbLinkInvalidated(path, reason) {
|
|
764
799
|
var _a;
|
|
800
|
+
this.deviceProtocol.delete(path);
|
|
801
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
|
|
802
|
+
}
|
|
803
|
+
createProtocolV2UsbTimeoutError(name, timeoutMs) {
|
|
804
|
+
return new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
|
|
805
|
+
}
|
|
806
|
+
callProtocolV2(path, name, data, options) {
|
|
765
807
|
return __awaiter(this, void 0, void 0, function* () {
|
|
766
|
-
|
|
767
|
-
if (!this.messagesV2) {
|
|
768
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
769
|
-
}
|
|
770
|
-
if (!protocolV1Messages) {
|
|
771
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
772
|
-
}
|
|
773
|
-
let session = this.protocolV2Sessions.get(path);
|
|
774
|
-
if (!session) {
|
|
775
|
-
session = new transport.ProtocolV2Session({
|
|
776
|
-
schemas: {
|
|
777
|
-
protocolV1: protocolV1Messages,
|
|
778
|
-
protocolV2: this.messagesV2,
|
|
779
|
-
},
|
|
780
|
-
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
781
|
-
writeFrame: (frame) => this.writeProtocolV2Frame(path, frame),
|
|
782
|
-
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
783
|
-
logger: this.Log,
|
|
784
|
-
logPrefix: 'ProtocolV2 NodeUSB',
|
|
785
|
-
createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
|
|
786
|
-
});
|
|
787
|
-
this.protocolV2Sessions.set(path, session);
|
|
788
|
-
}
|
|
789
|
-
this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
790
|
-
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
791
|
-
try {
|
|
792
|
-
return yield session.call(name, data, options);
|
|
793
|
-
}
|
|
794
|
-
finally {
|
|
795
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
796
|
-
}
|
|
808
|
+
return this.callProtocolV2Usb(path, name, data, options);
|
|
797
809
|
});
|
|
798
810
|
}
|
|
799
811
|
receiveData(path, dev, timeoutMs) {
|
|
@@ -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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-usb",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.21",
|
|
4
4
|
"description": "OneKey hardware wallet direct USB transport plugin (libusb)",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.21",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.21",
|
|
25
25
|
"bytebuffer": "^5.0.1",
|
|
26
26
|
"usb": "^2.14.0"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "efe594367fb3b196a5126baee7e2aba3e94986cd"
|
|
29
29
|
}
|