@onekeyfe/hd-transport-usb 1.2.0-alpha.4 → 1.2.0-alpha.40
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 +439 -0
- package/dist/index.d.ts +86 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +203 -160
- package/dist/transportLog.d.ts +2 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/jest.config.js +5 -0
- package/package.json +5 -4
- package/src/index.ts +262 -199
- package/src/transportLog.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -132,26 +132,6 @@ function readSerialNumber(dev, openDevices) {
|
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
}
|
|
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
135
|
function skipReportByte(packet) {
|
|
156
136
|
if (packet[0] === REPORT_ID) {
|
|
157
137
|
return packet.subarray(1);
|
|
@@ -161,8 +141,13 @@ function skipReportByte(packet) {
|
|
|
161
141
|
function toArrayBuffer(buf) {
|
|
162
142
|
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
163
143
|
}
|
|
164
|
-
class NodeUsbTransport {
|
|
144
|
+
class NodeUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
165
145
|
constructor() {
|
|
146
|
+
super({
|
|
147
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
148
|
+
maxFrameBytes: transport.PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
149
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
150
|
+
});
|
|
166
151
|
this.name = 'NodeUsbTransport';
|
|
167
152
|
this.version = '';
|
|
168
153
|
this.configured = false;
|
|
@@ -170,10 +155,8 @@ class NodeUsbTransport {
|
|
|
170
155
|
this.serialToBusId = new Map();
|
|
171
156
|
this.openDevices = new Map();
|
|
172
157
|
this.deviceProtocol = new Map();
|
|
173
|
-
this.protocolV2Assemblers = new Map();
|
|
174
|
-
this.protocolV2Sessions = new Map();
|
|
175
|
-
this.protocolV2ReadTimeouts = new Map();
|
|
176
158
|
this.reconnectLocks = new Map();
|
|
159
|
+
this.activeTransfers = new Map();
|
|
177
160
|
this.cancelled = false;
|
|
178
161
|
}
|
|
179
162
|
init(logger, emitter) {
|
|
@@ -189,14 +172,38 @@ class NodeUsbTransport {
|
|
|
189
172
|
}
|
|
190
173
|
configureProtocolV2(signedData) {
|
|
191
174
|
var _a;
|
|
175
|
+
const schemaSource = typeof signedData === 'string'
|
|
176
|
+
? signedData
|
|
177
|
+
: (_a = JSON.stringify(signedData)) !== null && _a !== void 0 ? _a : String(signedData);
|
|
178
|
+
if (schemaSource === this.protocolV2SchemaSource)
|
|
179
|
+
return;
|
|
180
|
+
const hadProtocolV2Schema = this.protocolV2SchemaSource !== undefined;
|
|
192
181
|
this.messagesV2 = parseConfigure(signedData);
|
|
193
|
-
this.
|
|
194
|
-
|
|
195
|
-
|
|
182
|
+
this.protocolV2SchemaSource = schemaSource;
|
|
183
|
+
if (!hadProtocolV2Schema)
|
|
184
|
+
return;
|
|
185
|
+
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); });
|
|
196
186
|
}
|
|
197
187
|
listen() {
|
|
198
188
|
}
|
|
199
189
|
stop() {
|
|
190
|
+
var _a;
|
|
191
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
this.cancelled = true;
|
|
193
|
+
yield this.cancelActiveTransfers();
|
|
194
|
+
try {
|
|
195
|
+
yield this.disposeProtocolV2UsbLinks('Node USB transport stopped');
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] stop link cleanup failed:', error);
|
|
199
|
+
}
|
|
200
|
+
yield Promise.allSettled(this.reconnectLocks.values());
|
|
201
|
+
yield this.cancelActiveTransfers();
|
|
202
|
+
yield Promise.all(Array.from(this.openDevices.keys(), path => this.closeOpenDevice(path)));
|
|
203
|
+
this.reconnectLocks.clear();
|
|
204
|
+
this.deviceProtocol.clear();
|
|
205
|
+
this.serialToBusId.clear();
|
|
206
|
+
});
|
|
200
207
|
}
|
|
201
208
|
post(path, name, data) {
|
|
202
209
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -246,7 +253,7 @@ class NodeUsbTransport {
|
|
|
246
253
|
});
|
|
247
254
|
}
|
|
248
255
|
acquire(input) {
|
|
249
|
-
var _a, _b, _c;
|
|
256
|
+
var _a, _b, _c, _d;
|
|
250
257
|
return __awaiter(this, void 0, void 0, function* () {
|
|
251
258
|
this.cancelled = false;
|
|
252
259
|
const path = (_a = input.path) !== null && _a !== void 0 ? _a : '';
|
|
@@ -254,22 +261,101 @@ class NodeUsbTransport {
|
|
|
254
261
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
|
|
255
262
|
}
|
|
256
263
|
try {
|
|
264
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'Node USB transport acquired');
|
|
257
265
|
yield this.closeOpenDevice(path);
|
|
258
266
|
yield this.openDevice(path);
|
|
259
|
-
yield this.detectProtocol(path, input.expectedProtocol);
|
|
267
|
+
yield this.detectProtocol(path, input.expectedProtocol, input.protocolHint);
|
|
260
268
|
return path;
|
|
261
269
|
}
|
|
262
270
|
catch (error) {
|
|
263
271
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport acquire error: ', error);
|
|
264
|
-
|
|
272
|
+
try {
|
|
273
|
+
yield this.release(path);
|
|
274
|
+
}
|
|
275
|
+
catch (cleanupError) {
|
|
276
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('NodeUsbTransport acquire cleanup error: ', cleanupError);
|
|
277
|
+
}
|
|
278
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, (_d = error.message) !== null && _d !== void 0 ? _d : String(error));
|
|
265
279
|
}
|
|
266
280
|
});
|
|
267
281
|
}
|
|
268
282
|
release(path, _onclose) {
|
|
269
283
|
return __awaiter(this, void 0, void 0, function* () {
|
|
284
|
+
yield this.cancelActiveTransfers(path);
|
|
285
|
+
yield this.invalidateProtocolV2UsbLink(path, 'Node USB transport released');
|
|
270
286
|
yield this.closeOpenDevice(path);
|
|
271
287
|
this.deviceProtocol.delete(path);
|
|
272
|
-
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
cancelActiveTransfers(path) {
|
|
291
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
292
|
+
const transfers = Array.from(this.activeTransfers.entries()).filter(([, active]) => path === undefined || active.path === path);
|
|
293
|
+
transfers.forEach(([transfer]) => {
|
|
294
|
+
try {
|
|
295
|
+
transfer.cancel();
|
|
296
|
+
}
|
|
297
|
+
catch (_a) {
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
yield Promise.allSettled(transfers.map(([, active]) => active.settled));
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
createTrackedTransfer(path, endpoint, callback) {
|
|
304
|
+
let resolveSettled = () => undefined;
|
|
305
|
+
const settled = new Promise(resolve => {
|
|
306
|
+
resolveSettled = resolve;
|
|
307
|
+
});
|
|
308
|
+
const transfer = endpoint.makeTransfer(endpoint.timeout, (error, buffer, actualLength) => {
|
|
309
|
+
this.activeTransfers.delete(transfer);
|
|
310
|
+
resolveSettled();
|
|
311
|
+
callback(error, buffer, actualLength);
|
|
312
|
+
});
|
|
313
|
+
this.activeTransfers.set(transfer, { path, settled, resolveSettled });
|
|
314
|
+
return transfer;
|
|
315
|
+
}
|
|
316
|
+
transferInOnce(path, ep, length) {
|
|
317
|
+
return new Promise((resolve, reject) => {
|
|
318
|
+
const buffer = Buffer.alloc(length);
|
|
319
|
+
const transfer = this.createTrackedTransfer(path, ep, (error, _submittedBuffer, actualLength) => {
|
|
320
|
+
if (error) {
|
|
321
|
+
reject(error);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (actualLength <= 0) {
|
|
325
|
+
reject(new Error('Empty USB transfer'));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
resolve(buffer.subarray(0, actualLength));
|
|
329
|
+
});
|
|
330
|
+
try {
|
|
331
|
+
transfer.submit(buffer);
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
const active = this.activeTransfers.get(transfer);
|
|
335
|
+
this.activeTransfers.delete(transfer);
|
|
336
|
+
active === null || active === void 0 ? void 0 : active.resolveSettled();
|
|
337
|
+
reject(error);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
transferOutOnce(path, ep, data) {
|
|
342
|
+
return new Promise((resolve, reject) => {
|
|
343
|
+
const transfer = this.createTrackedTransfer(path, ep, error => {
|
|
344
|
+
if (error) {
|
|
345
|
+
reject(error);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
resolve();
|
|
349
|
+
});
|
|
350
|
+
try {
|
|
351
|
+
transfer.submit(data);
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
const active = this.activeTransfers.get(transfer);
|
|
355
|
+
this.activeTransfers.delete(transfer);
|
|
356
|
+
active === null || active === void 0 ? void 0 : active.resolveSettled();
|
|
357
|
+
reject(error);
|
|
358
|
+
}
|
|
273
359
|
});
|
|
274
360
|
}
|
|
275
361
|
closeOpenDevice(path) {
|
|
@@ -300,7 +386,7 @@ class NodeUsbTransport {
|
|
|
300
386
|
});
|
|
301
387
|
}
|
|
302
388
|
call(path, name, data, options) {
|
|
303
|
-
var _a
|
|
389
|
+
var _a;
|
|
304
390
|
return __awaiter(this, void 0, void 0, function* () {
|
|
305
391
|
this.cancelled = false;
|
|
306
392
|
if (!this.messages) {
|
|
@@ -313,11 +399,8 @@ class NodeUsbTransport {
|
|
|
313
399
|
if (!protocol) {
|
|
314
400
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
315
401
|
}
|
|
316
|
-
if (transport.
|
|
317
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
402
|
+
if (!transport.shouldSuppressHighVolumeCallLog(name)) {
|
|
403
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
321
404
|
}
|
|
322
405
|
if (protocol === 'V2') {
|
|
323
406
|
return this.callProtocolV2(path, name, data, options);
|
|
@@ -342,8 +425,6 @@ class NodeUsbTransport {
|
|
|
342
425
|
});
|
|
343
426
|
}
|
|
344
427
|
cancel() {
|
|
345
|
-
var _a;
|
|
346
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport cancel');
|
|
347
428
|
this.cancelled = true;
|
|
348
429
|
}
|
|
349
430
|
getOpenDevice(path) {
|
|
@@ -366,6 +447,9 @@ class NodeUsbTransport {
|
|
|
366
447
|
}
|
|
367
448
|
isRetryableError(error) {
|
|
368
449
|
const message = this.getErrorMessage(error).toLowerCase();
|
|
450
|
+
if (message.includes('cancelled') || message.includes('canceled')) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
369
453
|
return (message.includes('libusb') ||
|
|
370
454
|
message.includes('transfer') ||
|
|
371
455
|
message.includes('disconnected') ||
|
|
@@ -400,6 +484,7 @@ class NodeUsbTransport {
|
|
|
400
484
|
var _a, _b;
|
|
401
485
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
|
|
402
486
|
yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
|
|
487
|
+
yield this.rotateProtocolV2UsbGeneration(path, `Node USB Protocol V1 ${direction} reconnect attempt ${attempt}`);
|
|
403
488
|
try {
|
|
404
489
|
yield this.closeOpenDevice(path);
|
|
405
490
|
}
|
|
@@ -433,7 +518,7 @@ class NodeUsbTransport {
|
|
|
433
518
|
const packet = new Uint8Array(PACKET_SIZE);
|
|
434
519
|
packet[0] = REPORT_ID;
|
|
435
520
|
packet.set(new Uint8Array(buffer), 1);
|
|
436
|
-
yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(packet));
|
|
521
|
+
yield this.transferOutOnce(path, this.getOpenDevice(path).epOut, Buffer.from(packet));
|
|
437
522
|
}
|
|
438
523
|
return;
|
|
439
524
|
}
|
|
@@ -466,25 +551,26 @@ class NodeUsbTransport {
|
|
|
466
551
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
467
552
|
}
|
|
468
553
|
try {
|
|
469
|
-
return yield transferInOnce(currentDev.epIn, length);
|
|
554
|
+
return yield this.transferInOnce(path, currentDev.epIn, length);
|
|
470
555
|
}
|
|
471
556
|
catch (error) {
|
|
472
557
|
lastError = error;
|
|
473
558
|
if ((options === null || options === void 0 ? void 0 : options.waitIndefinitelyOnTimeout) && this.isUsbTransferTimeout(error)) {
|
|
474
559
|
attempt -= 1;
|
|
475
|
-
continue;
|
|
476
|
-
}
|
|
477
|
-
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
478
|
-
if (!shouldRetry) {
|
|
479
|
-
throw error;
|
|
480
|
-
}
|
|
481
|
-
try {
|
|
482
|
-
currentDev = yield this.reconnectForRetry(path, 'in', attempt, error);
|
|
483
560
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
(
|
|
487
|
-
|
|
561
|
+
else {
|
|
562
|
+
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
563
|
+
if (!shouldRetry) {
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
currentDev = yield this.reconnectForRetry(path, 'in', attempt, error);
|
|
568
|
+
}
|
|
569
|
+
catch (reconnectError) {
|
|
570
|
+
lastError = reconnectError;
|
|
571
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
488
574
|
}
|
|
489
575
|
}
|
|
490
576
|
}
|
|
@@ -524,7 +610,7 @@ class NodeUsbTransport {
|
|
|
524
610
|
}
|
|
525
611
|
epIn.timeout = TRANSFER_TIMEOUT_MS;
|
|
526
612
|
epOut.timeout = TRANSFER_TIMEOUT_MS;
|
|
527
|
-
yield this.drainStaleInput(epIn);
|
|
613
|
+
yield this.drainStaleInput(path, epIn);
|
|
528
614
|
this.openDevices.set(path, { device: dev, iface, epIn, epOut });
|
|
529
615
|
}
|
|
530
616
|
catch (err) {
|
|
@@ -537,14 +623,14 @@ class NodeUsbTransport {
|
|
|
537
623
|
}
|
|
538
624
|
});
|
|
539
625
|
}
|
|
540
|
-
drainStaleInput(epIn) {
|
|
626
|
+
drainStaleInput(path, epIn) {
|
|
541
627
|
return __awaiter(this, void 0, void 0, function* () {
|
|
542
628
|
const originalTimeout = epIn.timeout;
|
|
543
629
|
epIn.timeout = 50;
|
|
544
630
|
try {
|
|
545
631
|
for (let index = 0; index < 16; index += 1) {
|
|
546
632
|
try {
|
|
547
|
-
yield transferInOnce(epIn, PACKET_SIZE);
|
|
633
|
+
yield this.transferInOnce(path, epIn, PACKET_SIZE);
|
|
548
634
|
}
|
|
549
635
|
catch (_a) {
|
|
550
636
|
break;
|
|
@@ -562,55 +648,49 @@ class NodeUsbTransport {
|
|
|
562
648
|
createProtocolDetectionError() {
|
|
563
649
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
|
|
564
650
|
}
|
|
565
|
-
detectProtocol(path, expectedProtocol) {
|
|
566
|
-
var _a
|
|
651
|
+
detectProtocol(path, expectedProtocol, protocolHint) {
|
|
652
|
+
var _a;
|
|
567
653
|
return __awaiter(this, void 0, void 0, function* () {
|
|
568
|
-
if (expectedProtocol === 'V1') {
|
|
569
|
-
if (yield this.probeProtocolV1(path)) {
|
|
570
|
-
this.deviceProtocol.set(path, 'V1');
|
|
571
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
572
|
-
return 'V1';
|
|
573
|
-
}
|
|
574
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
575
|
-
}
|
|
576
654
|
if (expectedProtocol === 'V2') {
|
|
577
655
|
if (yield this.probeProtocolV2(path)) {
|
|
578
656
|
this.deviceProtocol.set(path, 'V2');
|
|
579
|
-
(
|
|
657
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
580
658
|
return 'V2';
|
|
581
659
|
}
|
|
582
660
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
583
661
|
}
|
|
584
|
-
if (
|
|
585
|
-
this.
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
this.deviceProtocol.set(path, 'V1');
|
|
591
|
-
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1`);
|
|
592
|
-
return 'V1';
|
|
662
|
+
if (expectedProtocol === 'V1') {
|
|
663
|
+
if (yield this.probeProtocolV1(path)) {
|
|
664
|
+
this.deviceProtocol.set(path, 'V1');
|
|
665
|
+
return 'V1';
|
|
666
|
+
}
|
|
667
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
593
668
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
(
|
|
597
|
-
|
|
669
|
+
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
670
|
+
for (const [index, protocol] of probeOrder.entries()) {
|
|
671
|
+
if (index > 0) {
|
|
672
|
+
yield this.resetConnectionAfterProbe(path);
|
|
673
|
+
}
|
|
674
|
+
const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
|
|
675
|
+
if (detected) {
|
|
676
|
+
this.deviceProtocol.set(path, protocol);
|
|
677
|
+
return protocol;
|
|
678
|
+
}
|
|
598
679
|
}
|
|
599
680
|
this.deviceProtocol.delete(path);
|
|
600
681
|
throw this.createProtocolDetectionError();
|
|
601
682
|
});
|
|
602
683
|
}
|
|
603
684
|
resetConnectionAfterProbe(path) {
|
|
604
|
-
var _a
|
|
685
|
+
var _a;
|
|
605
686
|
return __awaiter(this, void 0, void 0, function* () {
|
|
606
|
-
|
|
607
|
-
this.protocolV2Sessions.delete(path);
|
|
608
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
687
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'Node USB protocol probe reset');
|
|
609
688
|
try {
|
|
689
|
+
yield this.cancelActiveTransfers(path);
|
|
610
690
|
yield this.closeOpenDevice(path);
|
|
611
691
|
}
|
|
612
692
|
catch (error) {
|
|
613
|
-
(
|
|
693
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] close after protocol probe error:', error);
|
|
614
694
|
}
|
|
615
695
|
yield this.enumerate();
|
|
616
696
|
yield this.openDevice(path);
|
|
@@ -654,7 +734,6 @@ class NodeUsbTransport {
|
|
|
654
734
|
});
|
|
655
735
|
}
|
|
656
736
|
probeProtocolV1(path) {
|
|
657
|
-
var _a;
|
|
658
737
|
return __awaiter(this, void 0, void 0, function* () {
|
|
659
738
|
if (!this.messages) {
|
|
660
739
|
return false;
|
|
@@ -663,8 +742,7 @@ class NodeUsbTransport {
|
|
|
663
742
|
yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
|
|
664
743
|
return true;
|
|
665
744
|
}
|
|
666
|
-
catch (
|
|
667
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
745
|
+
catch (_error) {
|
|
668
746
|
return false;
|
|
669
747
|
}
|
|
670
748
|
});
|
|
@@ -683,96 +761,61 @@ class NodeUsbTransport {
|
|
|
683
761
|
});
|
|
684
762
|
});
|
|
685
763
|
}
|
|
686
|
-
|
|
687
|
-
|
|
764
|
+
getProtocolV2UsbSchemas() {
|
|
765
|
+
if (!this.messages || !this.messagesV2) {
|
|
766
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
767
|
+
}
|
|
768
|
+
return {
|
|
769
|
+
protocolV1: this.messages,
|
|
770
|
+
protocolV2: this.messagesV2,
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
getProtocolV2UsbLogger() {
|
|
774
|
+
return this.Log;
|
|
775
|
+
}
|
|
776
|
+
writeProtocolV2UsbPacket(path, frame, _context) {
|
|
688
777
|
return __awaiter(this, void 0, void 0, function* () {
|
|
689
|
-
|
|
690
|
-
|
|
778
|
+
if (this.cancelled) {
|
|
779
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
780
|
+
}
|
|
781
|
+
yield this.transferOutOnce(path, this.getOpenDevice(path).epOut, Buffer.from(frame));
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
readProtocolV2UsbPacket(path, _context) {
|
|
785
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
786
|
+
for (;;) {
|
|
691
787
|
if (this.cancelled) {
|
|
692
788
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
693
789
|
}
|
|
694
790
|
try {
|
|
695
|
-
yield
|
|
696
|
-
return;
|
|
791
|
+
const packet = yield this.transferInOnce(path, this.getOpenDevice(path).epIn, transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
792
|
+
return new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
697
793
|
}
|
|
698
794
|
catch (error) {
|
|
699
|
-
|
|
700
|
-
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
701
|
-
if (!shouldRetry) {
|
|
795
|
+
if (!this.isUsbTransferTimeout(error)) {
|
|
702
796
|
throw error;
|
|
703
797
|
}
|
|
704
|
-
try {
|
|
705
|
-
yield this.reconnectForRetry(path, 'out', attempt, error);
|
|
706
|
-
}
|
|
707
|
-
catch (reconnectError) {
|
|
708
|
-
lastError = reconnectError;
|
|
709
|
-
(_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)}`);
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
798
|
}
|
|
713
799
|
}
|
|
714
|
-
throw lastError;
|
|
715
800
|
});
|
|
716
801
|
}
|
|
717
|
-
|
|
802
|
+
resetProtocolV2UsbNativeLink(path, _reason) {
|
|
718
803
|
return __awaiter(this, void 0, void 0, function* () {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
722
|
-
this.protocolV2Assemblers.set(path, assembler);
|
|
723
|
-
}
|
|
724
|
-
let frame = assembler.push(new Uint8Array(0));
|
|
725
|
-
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
726
|
-
while (!frame) {
|
|
727
|
-
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), transport.PROTOCOL_V2_FRAME_MAX_BYTES, { waitIndefinitelyOnTimeout: !deadline });
|
|
728
|
-
const packet = deadline
|
|
729
|
-
? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2')
|
|
730
|
-
: yield transferIn;
|
|
731
|
-
const bytes = new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
732
|
-
try {
|
|
733
|
-
frame = assembler.push(bytes);
|
|
734
|
-
}
|
|
735
|
-
catch (error) {
|
|
736
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return frame;
|
|
804
|
+
yield this.cancelActiveTransfers(path);
|
|
805
|
+
yield this.closeOpenDevice(path);
|
|
740
806
|
});
|
|
741
807
|
}
|
|
742
|
-
|
|
808
|
+
onProtocolV2UsbLinkInvalidated(path, reason) {
|
|
743
809
|
var _a;
|
|
810
|
+
this.deviceProtocol.delete(path);
|
|
811
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
|
|
812
|
+
}
|
|
813
|
+
createProtocolV2UsbTimeoutError(name, timeoutMs) {
|
|
814
|
+
return new transport.ProtocolV2LinkError('response-timeout', `Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
|
|
815
|
+
}
|
|
816
|
+
callProtocolV2(path, name, data, options) {
|
|
744
817
|
return __awaiter(this, void 0, void 0, function* () {
|
|
745
|
-
|
|
746
|
-
if (!this.messagesV2) {
|
|
747
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
748
|
-
}
|
|
749
|
-
if (!protocolV1Messages) {
|
|
750
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
751
|
-
}
|
|
752
|
-
let session = this.protocolV2Sessions.get(path);
|
|
753
|
-
if (!session) {
|
|
754
|
-
session = new transport.ProtocolV2Session({
|
|
755
|
-
schemas: {
|
|
756
|
-
protocolV1: protocolV1Messages,
|
|
757
|
-
protocolV2: this.messagesV2,
|
|
758
|
-
},
|
|
759
|
-
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
760
|
-
writeFrame: (frame) => this.writeProtocolV2Frame(path, frame),
|
|
761
|
-
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
762
|
-
logger: this.Log,
|
|
763
|
-
logPrefix: 'ProtocolV2 NodeUSB',
|
|
764
|
-
createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
|
|
765
|
-
});
|
|
766
|
-
this.protocolV2Sessions.set(path, session);
|
|
767
|
-
}
|
|
768
|
-
this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
769
|
-
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
770
|
-
try {
|
|
771
|
-
return yield session.call(name, data, options);
|
|
772
|
-
}
|
|
773
|
-
finally {
|
|
774
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
775
|
-
}
|
|
818
|
+
return this.callProtocolV2Usb(path, name, data, options);
|
|
776
819
|
});
|
|
777
820
|
}
|
|
778
821
|
receiveData(path, dev, timeoutMs) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportLog.d.ts","sourceRoot":"","sources":["../src/transportLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,wBAAwB,CAAC"}
|
package/jest.config.js
ADDED
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.40",
|
|
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",
|
|
@@ -16,14 +16,15 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"dev": "rimraf dist && rollup -c ../../build/rollup.config.js -w",
|
|
18
18
|
"build": "rimraf dist && rollup -c ../../build/rollup.config.js",
|
|
19
|
+
"test": "jest",
|
|
19
20
|
"lint": "eslint .",
|
|
20
21
|
"lint:fix": "eslint . --fix"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.40",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.40",
|
|
25
26
|
"bytebuffer": "^5.0.1",
|
|
26
27
|
"usb": "^2.14.0"
|
|
27
28
|
},
|
|
28
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "caf94ecc5e90731ae788ac81b500a245a8497d69"
|
|
29
30
|
}
|