@onekeyfe/hd-transport-usb 1.2.0-alpha.7 → 1.2.0-alpha.9

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.
@@ -0,0 +1,260 @@
1
+ import transportPackage, { PROTOCOL_V2_CHANNEL_USB, ProtocolV2 } from '@onekeyfe/hd-transport';
2
+
3
+ import NodeUsbTransport from '../src';
4
+
5
+ let mockUsbDevices: any[] = [];
6
+
7
+ jest.mock('usb', () => ({
8
+ getDeviceList: jest.fn(() => mockUsbDevices),
9
+ }));
10
+
11
+ const { parseConfigure } = transportPackage;
12
+
13
+ const protocolV1Schema = {
14
+ nested: {
15
+ Initialize: { fields: {} },
16
+ Success: {
17
+ fields: {
18
+ message: { type: 'string', id: 1 },
19
+ },
20
+ },
21
+ MessageType: {
22
+ values: {
23
+ MessageType_Initialize: 1,
24
+ MessageType_Success: 2,
25
+ },
26
+ },
27
+ },
28
+ };
29
+
30
+ const protocolV2Schema = {
31
+ nested: {
32
+ Ping: {
33
+ fields: {
34
+ message: { type: 'string', id: 1 },
35
+ },
36
+ },
37
+ Success: {
38
+ fields: {
39
+ message: { type: 'string', id: 1 },
40
+ },
41
+ },
42
+ MessageType: {
43
+ values: {
44
+ MessageType_Ping: 60206,
45
+ MessageType_Success: 60207,
46
+ },
47
+ },
48
+ },
49
+ };
50
+
51
+ const schemas = {
52
+ protocolV1: parseConfigure(protocolV1Schema),
53
+ protocolV2: parseConfigure(protocolV2Schema),
54
+ };
55
+
56
+ type PendingRead = {
57
+ started: Promise<void>;
58
+ fail: (error?: Error) => void;
59
+ };
60
+
61
+ const createHarness = () => {
62
+ const path = '6136';
63
+ const responseQueue: Buffer[] = [];
64
+ const sentSeqs: number[] = [];
65
+ let writeError: Error | undefined;
66
+ let holdNextRead:
67
+ | {
68
+ markStarted: () => void;
69
+ started: Promise<void>;
70
+ callback?: (error?: Error, data?: Buffer) => void;
71
+ }
72
+ | undefined;
73
+
74
+ const epIn = {
75
+ direction: 'in',
76
+ address: 0x81,
77
+ timeout: 30_000,
78
+ transfer: jest.fn((_length: number, callback: (error?: Error, data?: Buffer) => void) => {
79
+ if (epIn.timeout === 50) {
80
+ callback(new Error('LIBUSB_TRANSFER_TIMED_OUT'));
81
+ return;
82
+ }
83
+ if (holdNextRead) {
84
+ const pending = holdNextRead;
85
+ holdNextRead = undefined;
86
+ pending.callback = callback;
87
+ pending.markStarted();
88
+ return;
89
+ }
90
+ const response = responseQueue.shift();
91
+ if (!response) {
92
+ callback(new Error('LIBUSB_TRANSFER_TIMED_OUT'));
93
+ return;
94
+ }
95
+ callback(undefined, response);
96
+ }),
97
+ };
98
+
99
+ const epOut = {
100
+ direction: 'out',
101
+ address: 0x01,
102
+ timeout: 30_000,
103
+ transfer: jest.fn((data: Buffer, callback: (error?: Error) => void) => {
104
+ const seq = data[6];
105
+ sentSeqs.push(seq);
106
+ if (writeError) {
107
+ const error = writeError;
108
+ writeError = undefined;
109
+ callback(error);
110
+ return;
111
+ }
112
+ responseQueue.push(
113
+ Buffer.from(
114
+ ProtocolV2.encodeFrame(
115
+ schemas,
116
+ 'Success',
117
+ { message: 'ok' },
118
+ { router: PROTOCOL_V2_CHANNEL_USB, seq }
119
+ )
120
+ )
121
+ );
122
+ callback();
123
+ }),
124
+ };
125
+
126
+ const iface = {
127
+ descriptor: { bInterfaceClass: 0xff, bInterfaceNumber: 0 },
128
+ endpoints: [epIn, epOut],
129
+ claim: jest.fn(),
130
+ release: jest.fn((callback: () => void) => callback()),
131
+ isKernelDriverActive: jest.fn(() => false),
132
+ detachKernelDriver: jest.fn(),
133
+ };
134
+
135
+ const device = {
136
+ busNumber: 1,
137
+ deviceAddress: 2,
138
+ timeout: 30_000,
139
+ deviceDescriptor: {
140
+ idVendor: 0x1209,
141
+ idProduct: 0x4f4a,
142
+ iSerialNumber: 1,
143
+ },
144
+ interfaces: [iface],
145
+ open: jest.fn(),
146
+ close: jest.fn(),
147
+ getStringDescriptor: jest.fn(
148
+ (_index: number, callback: (error?: Error, value?: string) => void) =>
149
+ callback(undefined, path)
150
+ ),
151
+ };
152
+
153
+ mockUsbDevices = [device];
154
+ const transport = new NodeUsbTransport();
155
+ transport.init({ debug: jest.fn(), error: jest.fn() });
156
+ transport.configure(protocolV1Schema);
157
+ transport.configureProtocolV2(protocolV2Schema);
158
+
159
+ return {
160
+ transport,
161
+ path,
162
+ device,
163
+ iface,
164
+ epIn,
165
+ epOut,
166
+ sentSeqs,
167
+ async acquire() {
168
+ await transport.enumerate();
169
+ await transport.acquire({ path, expectedProtocol: 'V2' });
170
+ },
171
+ failNextWrite(error: Error) {
172
+ writeError = error;
173
+ },
174
+ holdRead(): PendingRead {
175
+ let markStarted: () => void = () => undefined;
176
+ const started = new Promise<void>(resolve => {
177
+ markStarted = resolve;
178
+ });
179
+ const pending = { markStarted, started, callback: undefined };
180
+ holdNextRead = pending;
181
+ return {
182
+ started,
183
+ fail(error = new Error('read released after test')) {
184
+ pending.callback?.(error);
185
+ },
186
+ };
187
+ },
188
+ };
189
+ };
190
+
191
+ describe('NodeUsbTransport Protocol V2 link lifecycle', () => {
192
+ test('keeps seq across probe, call and reacquire', async () => {
193
+ const harness = createHarness();
194
+ const { transport, path, sentSeqs } = harness;
195
+
196
+ await harness.acquire();
197
+ await transport.call(path, 'Ping', { message: 'first' });
198
+ await transport.release(path);
199
+ await harness.acquire();
200
+ await transport.call(path, 'Ping', { message: 'second' });
201
+
202
+ expect(sentSeqs).toEqual([1, 2, 3, 4]);
203
+ await transport.release(path);
204
+ });
205
+
206
+ test('does not resend a Protocol V2 frame after transferOut fails', async () => {
207
+ const harness = createHarness();
208
+ const { transport, path, epOut } = harness;
209
+ await harness.acquire();
210
+ epOut.transfer.mockClear();
211
+ harness.failNextWrite(new Error('LIBUSB_ERROR_IO'));
212
+
213
+ await expect(transport.call(path, 'Ping', { message: 'write-failure' })).rejects.toThrow(
214
+ 'LIBUSB_ERROR_IO'
215
+ );
216
+
217
+ expect(epOut.transfer).toHaveBeenCalledTimes(1);
218
+ });
219
+
220
+ test('rejects a pending read when release invalidates the link', async () => {
221
+ const harness = createHarness();
222
+ const { transport, path } = harness;
223
+ await harness.acquire();
224
+ const pendingRead = harness.holdRead();
225
+
226
+ const call = transport.call(path, 'Ping', { message: 'pending' }, { timeoutMs: 5000 });
227
+ const outcome = call.then(
228
+ () => 'resolved',
229
+ error => error.message
230
+ );
231
+ await pendingRead.started;
232
+ await transport.release(path);
233
+ const settled = await Promise.race([
234
+ outcome,
235
+ new Promise<string>(resolve => {
236
+ setTimeout(() => resolve('still pending'), 50);
237
+ }),
238
+ ]);
239
+ pendingRead.fail();
240
+
241
+ expect(settled).not.toBe('still pending');
242
+ });
243
+
244
+ test('keeps the cursor after a response timeout rebuilds the USB connection', async () => {
245
+ const harness = createHarness();
246
+ const { transport, path, sentSeqs } = harness;
247
+ await harness.acquire();
248
+ const pendingRead = harness.holdRead();
249
+
250
+ await expect(
251
+ transport.call(path, 'Ping', { message: 'timeout' }, { timeoutMs: 20 })
252
+ ).rejects.toThrow('20ms');
253
+ pendingRead.fail();
254
+ await harness.acquire();
255
+ await transport.call(path, 'Ping', { message: 'after-timeout' });
256
+
257
+ expect(sentSeqs).toEqual([1, 2, 3, 4]);
258
+ await transport.release(path);
259
+ });
260
+ });
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as transport from '@onekeyfe/hd-transport';
2
- import transport__default, { OneKeyDeviceInfo, AcquireInput, TransportCallOptions, ProtocolType } from '@onekeyfe/hd-transport';
2
+ import transport__default, { ProtocolV2UsbTransportBase, OneKeyDeviceInfo, AcquireInput, TransportCallOptions, ProtocolV2Schemas, ProtocolV2CallContext, ProtocolType } from '@onekeyfe/hd-transport';
3
3
  import EventEmitter from 'events';
4
4
 
5
- declare class NodeUsbTransport {
5
+ declare class NodeUsbTransport extends ProtocolV2UsbTransportBase<string> {
6
6
  messages: ReturnType<typeof transport__default.parseConfigure> | undefined;
7
7
  messagesV2: ReturnType<typeof transport__default.parseConfigure> | undefined;
8
8
  name: string;
@@ -14,11 +14,9 @@ declare class NodeUsbTransport {
14
14
  private serialToBusId;
15
15
  private openDevices;
16
16
  private deviceProtocol;
17
- private protocolV2Assemblers;
18
- private protocolV2Sessions;
19
- private protocolV2ReadTimeouts;
20
17
  private reconnectLocks;
21
18
  private cancelled;
19
+ constructor();
22
20
  init(logger: any, emitter?: EventEmitter): Promise<string>;
23
21
  configure(signedData: any): Promise<void>;
24
22
  configureProtocolV2(signedData: any): void;
@@ -55,8 +53,13 @@ declare class NodeUsbTransport {
55
53
  private withProtocolReadTimeout;
56
54
  private probeProtocolV1;
57
55
  private probeProtocolV2;
58
- private writeProtocolV2Frame;
59
- private receiveProtocolV2Frame;
56
+ protected getProtocolV2UsbSchemas(): ProtocolV2Schemas;
57
+ protected getProtocolV2UsbLogger(): any;
58
+ protected writeProtocolV2UsbPacket(path: string, frame: Uint8Array, _context: ProtocolV2CallContext): Promise<void>;
59
+ protected readProtocolV2UsbPacket(path: string, _context: ProtocolV2CallContext): Promise<Uint8Array>;
60
+ protected resetProtocolV2UsbNativeLink(path: string, _reason: string): Promise<void>;
61
+ protected onProtocolV2UsbLinkInvalidated(path: string, reason: string): void;
62
+ protected createProtocolV2UsbTimeoutError(name: string, timeoutMs: number): Error;
60
63
  private callProtocolV2;
61
64
  private receiveData;
62
65
  getProtocolType(path: string): ProtocolType | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,SAWN,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAgKhC,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGlE,UAAU,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEpE,IAAI,SAAsB;IAE1B,OAAO,SAAM;IAEb,UAAU,UAAS;IAEnB,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAGvB,OAAO,CAAC,aAAa,CAA6B;IAGlD,OAAO,CAAC,WAAW,CAAiC;IAGpD,OAAO,CAAC,cAAc,CAAwC;IAG9D,OAAO,CAAC,oBAAoB,CAAoD;IAGhF,OAAO,CAAC,kBAAkB,CAA6C;IAGvE,OAAO,CAAC,sBAAsB,CAA8C;IAG5E,OAAO,CAAC,cAAc,CAA0C;IAGhE,OAAO,CAAC,SAAS,CAAS;IAM1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAMxC,SAAS,CAAC,UAAU,EAAE,GAAG;IAOzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAOnC,MAAM;IAIN,IAAI;IAQE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAY9E,IAAI,CAAC,IAAI,EAAE,MAAM;;;;;;IAiBjB,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IA8BxC,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB7C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAMhD,eAAe;IA6BvB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YAwClB,cAAc;IA0B5B,MAAM;IAWN,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,iBAAiB;YAmDX,sBAAsB;YAyCtB,mBAAmB;YA2CnB,UAAU;YA+DV,eAAe;IAiB7B,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;YAOtB,cAAc;YA4Cd,yBAAyB;YAezB,uBAAuB;YA0CvB,eAAe;YAcf,eAAe;YAcf,oBAAoB;YA+BpB,sBAAsB;YAwCtB,cAAc;YAgDd,WAAW;IA6CzB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -161,8 +161,13 @@ function skipReportByte(packet) {
161
161
  function toArrayBuffer(buf) {
162
162
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
163
163
  }
164
- class NodeUsbTransport {
164
+ class NodeUsbTransport extends transport.ProtocolV2UsbTransportBase {
165
165
  constructor() {
166
+ super({
167
+ router: transport.PROTOCOL_V2_CHANNEL_USB,
168
+ maxFrameBytes: transport.PROTOCOL_V2_FRAME_MAX_BYTES,
169
+ logPrefix: 'ProtocolV2 NodeUSB',
170
+ });
166
171
  this.name = 'NodeUsbTransport';
167
172
  this.version = '';
168
173
  this.configured = false;
@@ -170,9 +175,6 @@ class NodeUsbTransport {
170
175
  this.serialToBusId = new Map();
171
176
  this.openDevices = new Map();
172
177
  this.deviceProtocol = new Map();
173
- this.protocolV2Assemblers = new Map();
174
- this.protocolV2Sessions = new Map();
175
- this.protocolV2ReadTimeouts = new Map();
176
178
  this.reconnectLocks = new Map();
177
179
  this.cancelled = false;
178
180
  }
@@ -190,13 +192,13 @@ class NodeUsbTransport {
190
192
  configureProtocolV2(signedData) {
191
193
  var _a;
192
194
  this.messagesV2 = parseConfigure(signedData);
193
- this.protocolV2Sessions.clear();
194
- this.protocolV2ReadTimeouts.clear();
195
+ 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); });
195
196
  (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V2 schema configured');
196
197
  }
197
198
  listen() {
198
199
  }
199
200
  stop() {
201
+ this.disposeProtocolV2UsbLinks('Node USB transport stopped').catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] stop link cleanup failed:', error); });
200
202
  }
201
203
  post(path, name, data) {
202
204
  return __awaiter(this, void 0, void 0, function* () {
@@ -254,6 +256,7 @@ class NodeUsbTransport {
254
256
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
255
257
  }
256
258
  try {
259
+ yield this.rotateProtocolV2UsbGeneration(path, 'Node USB transport acquired');
257
260
  yield this.closeOpenDevice(path);
258
261
  yield this.openDevice(path);
259
262
  yield this.detectProtocol(path, input.expectedProtocol);
@@ -267,9 +270,9 @@ class NodeUsbTransport {
267
270
  }
268
271
  release(path, _onclose) {
269
272
  return __awaiter(this, void 0, void 0, function* () {
273
+ yield this.invalidateProtocolV2UsbLink(path, 'Node USB transport released');
270
274
  yield this.closeOpenDevice(path);
271
275
  this.deviceProtocol.delete(path);
272
- this.protocolV2Assemblers.delete(path);
273
276
  });
274
277
  }
275
278
  closeOpenDevice(path) {
@@ -400,6 +403,7 @@ class NodeUsbTransport {
400
403
  var _a, _b;
401
404
  (_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
405
  yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
406
+ yield this.rotateProtocolV2UsbGeneration(path, `Node USB Protocol V1 ${direction} reconnect attempt ${attempt}`);
403
407
  try {
404
408
  yield this.closeOpenDevice(path);
405
409
  }
@@ -472,19 +476,20 @@ class NodeUsbTransport {
472
476
  lastError = error;
473
477
  if ((options === null || options === void 0 ? void 0 : options.waitIndefinitelyOnTimeout) && this.isUsbTransferTimeout(error)) {
474
478
  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
479
  }
484
- catch (reconnectError) {
485
- lastError = reconnectError;
486
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
487
- break;
480
+ else {
481
+ const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
482
+ if (!shouldRetry) {
483
+ throw error;
484
+ }
485
+ try {
486
+ currentDev = yield this.reconnectForRetry(path, 'in', attempt, error);
487
+ }
488
+ catch (reconnectError) {
489
+ lastError = reconnectError;
490
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
491
+ break;
492
+ }
488
493
  }
489
494
  }
490
495
  }
@@ -601,16 +606,14 @@ class NodeUsbTransport {
601
606
  });
602
607
  }
603
608
  resetConnectionAfterProbe(path) {
604
- var _a, _b;
609
+ var _a;
605
610
  return __awaiter(this, void 0, void 0, function* () {
606
- (_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
607
- this.protocolV2Sessions.delete(path);
608
- this.protocolV2ReadTimeouts.delete(path);
611
+ yield this.rotateProtocolV2UsbGeneration(path, 'Node USB protocol probe reset');
609
612
  try {
610
613
  yield this.closeOpenDevice(path);
611
614
  }
612
615
  catch (error) {
613
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[NodeUsbTransport] close after protocol probe error:', error);
616
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] close after protocol probe error:', error);
614
617
  }
615
618
  yield this.enumerate();
616
619
  yield this.openDevice(path);
@@ -683,96 +686,60 @@ class NodeUsbTransport {
683
686
  });
684
687
  });
685
688
  }
686
- writeProtocolV2Frame(path, frame) {
687
- var _a;
689
+ getProtocolV2UsbSchemas() {
690
+ if (!this.messages || !this.messagesV2) {
691
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
692
+ }
693
+ return {
694
+ protocolV1: this.messages,
695
+ protocolV2: this.messagesV2,
696
+ };
697
+ }
698
+ getProtocolV2UsbLogger() {
699
+ return this.Log;
700
+ }
701
+ writeProtocolV2UsbPacket(path, frame, _context) {
688
702
  return __awaiter(this, void 0, void 0, function* () {
689
- let lastError;
690
- for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
703
+ if (this.cancelled) {
704
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
705
+ }
706
+ yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
707
+ });
708
+ }
709
+ readProtocolV2UsbPacket(path, _context) {
710
+ return __awaiter(this, void 0, void 0, function* () {
711
+ for (;;) {
691
712
  if (this.cancelled) {
692
713
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
693
714
  }
694
715
  try {
695
- yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
696
- return;
716
+ const packet = yield transferInOnce(this.getOpenDevice(path).epIn, transport.PROTOCOL_V2_FRAME_MAX_BYTES);
717
+ return new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
697
718
  }
698
719
  catch (error) {
699
- lastError = error;
700
- const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
701
- if (!shouldRetry) {
720
+ if (!this.isUsbTransferTimeout(error)) {
702
721
  throw error;
703
722
  }
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
723
  }
713
724
  }
714
- throw lastError;
715
725
  });
716
726
  }
717
- receiveProtocolV2Frame(path, timeoutMs) {
727
+ resetProtocolV2UsbNativeLink(path, _reason) {
718
728
  return __awaiter(this, void 0, void 0, function* () {
719
- let assembler = this.protocolV2Assemblers.get(path);
720
- if (!assembler) {
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;
729
+ yield this.closeOpenDevice(path);
740
730
  });
741
731
  }
742
- callProtocolV2(path, name, data, options) {
732
+ onProtocolV2UsbLinkInvalidated(path, reason) {
743
733
  var _a;
734
+ this.deviceProtocol.delete(path);
735
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
736
+ }
737
+ createProtocolV2UsbTimeoutError(name, timeoutMs) {
738
+ return new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
739
+ }
740
+ callProtocolV2(path, name, data, options) {
744
741
  return __awaiter(this, void 0, void 0, function* () {
745
- const protocolV1Messages = this.messages;
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
- }
742
+ return this.callProtocolV2Usb(path, name, data, options);
776
743
  });
777
744
  }
778
745
  receiveData(path, dev, timeoutMs) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-usb",
3
- "version": "1.2.0-alpha.7",
3
+ "version": "1.2.0-alpha.9",
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.7",
24
- "@onekeyfe/hd-transport": "1.2.0-alpha.7",
23
+ "@onekeyfe/hd-shared": "1.2.0-alpha.9",
24
+ "@onekeyfe/hd-transport": "1.2.0-alpha.9",
25
25
  "bytebuffer": "^5.0.1",
26
26
  "usb": "^2.14.0"
27
27
  },
28
- "gitHead": "001372047f518aaeed5fcbe87b990b8b619a9a65"
28
+ "gitHead": "f90ef9921b742f68cce9f4e7a0425e45e8ae7ec9"
29
29
  }
package/src/index.ts CHANGED
@@ -8,8 +8,7 @@ import transport, {
8
8
  PROTOCOL_V1_USB_PACKET_SIZE,
9
9
  PROTOCOL_V2_CHANNEL_USB,
10
10
  PROTOCOL_V2_FRAME_MAX_BYTES,
11
- ProtocolV2FrameAssembler,
12
- ProtocolV2Session,
11
+ ProtocolV2UsbTransportBase,
13
12
  probeProtocolV2 as probeProtocolV2Helper,
14
13
  } from '@onekeyfe/hd-transport';
15
14
  import { ERRORS, HardwareErrorCode, ONEKEY_WEBUSB_FILTER, wait } from '@onekeyfe/hd-shared';
@@ -19,6 +18,8 @@ import type {
19
18
  AcquireInput,
20
19
  OneKeyDeviceInfo,
21
20
  ProtocolType,
21
+ ProtocolV2CallContext,
22
+ ProtocolV2Schemas,
22
23
  TransportCallOptions,
23
24
  } from '@onekeyfe/hd-transport';
24
25
 
@@ -180,7 +181,7 @@ function toArrayBuffer(buf: Buffer): ArrayBuffer {
180
181
  *
181
182
  * Modeled after WebUsbTransport.
182
183
  */
183
- export default class NodeUsbTransport {
184
+ export default class NodeUsbTransport extends ProtocolV2UsbTransportBase<string> {
184
185
  messages: ReturnType<typeof transport.parseConfigure> | undefined;
185
186
 
186
187
  /** Protobuf schema for Protocol V2 transports. */
@@ -207,21 +208,20 @@ export default class NodeUsbTransport {
207
208
  /** Per-path protocol type detected by active wire-level probe. */
208
209
  private deviceProtocol: Map<string, ProtocolType> = new Map();
209
210
 
210
- /** Per-path Protocol V2 frame assembler, preserving buffered frames during reads. */
211
- private protocolV2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
212
-
213
- /** Per-path Protocol V2 session, preserving seq across API calls on the same device path. */
214
- private protocolV2Sessions: Map<string, ProtocolV2Session> = new Map();
215
-
216
- /** Current Protocol V2 read timeout, consumed by cached session readFrame closures. */
217
- private protocolV2ReadTimeouts: Map<string, number | undefined> = new Map();
218
-
219
211
  /** per-path reconnect lock to prevent concurrent reconnects */
220
212
  private reconnectLocks = new Map<string, Promise<OpenDevice>>();
221
213
 
222
214
  /** set to true when cancel() is called; checked by retry loops */
223
215
  private cancelled = false;
224
216
 
217
+ constructor() {
218
+ super({
219
+ router: PROTOCOL_V2_CHANNEL_USB,
220
+ maxFrameBytes: PROTOCOL_V2_FRAME_MAX_BYTES,
221
+ logPrefix: 'ProtocolV2 NodeUSB',
222
+ });
223
+ }
224
+
225
225
  /**
226
226
  * Initialize transport.
227
227
  * Signature matches the Transport.init interface (logger, emitter).
@@ -241,8 +241,9 @@ export default class NodeUsbTransport {
241
241
 
242
242
  configureProtocolV2(signedData: any) {
243
243
  this.messagesV2 = parseConfigure(signedData);
244
- this.protocolV2Sessions.clear();
245
- this.protocolV2ReadTimeouts.clear();
244
+ this.invalidateAllProtocolV2UsbLinks('Protocol V2 schema reconfigured').catch(error =>
245
+ this.Log?.debug('[NodeUsbTransport] schema link cleanup failed:', error)
246
+ );
246
247
  this.Log?.debug('[NodeUsbTransport] Protocol V2 schema configured');
247
248
  }
248
249
 
@@ -251,7 +252,9 @@ export default class NodeUsbTransport {
251
252
  }
252
253
 
253
254
  stop() {
254
- // Placeholder no background listeners to tear down
255
+ this.disposeProtocolV2UsbLinks('Node USB transport stopped').catch(error =>
256
+ this.Log?.debug('[NodeUsbTransport] stop link cleanup failed:', error)
257
+ );
255
258
  }
256
259
 
257
260
  /**
@@ -326,6 +329,7 @@ export default class NodeUsbTransport {
326
329
  }
327
330
 
328
331
  try {
332
+ await this.rotateProtocolV2UsbGeneration(path, 'Node USB transport acquired');
329
333
  await this.closeOpenDevice(path);
330
334
  await this.openDevice(path);
331
335
  await this.detectProtocol(path, input.expectedProtocol);
@@ -340,9 +344,9 @@ export default class NodeUsbTransport {
340
344
  * Release device — release interface and close.
341
345
  */
342
346
  async release(path: string, _onclose?: boolean): Promise<void> {
347
+ await this.invalidateProtocolV2UsbLink(path, 'Node USB transport released');
343
348
  await this.closeOpenDevice(path);
344
349
  this.deviceProtocol.delete(path);
345
- this.protocolV2Assemblers.delete(path);
346
350
  }
347
351
 
348
352
  private async closeOpenDevice(path: string): Promise<void> {
@@ -531,6 +535,10 @@ export default class NodeUsbTransport {
531
535
  );
532
536
  await wait(attempt * PACKET_IO_RETRY_DELAY);
533
537
 
538
+ await this.rotateProtocolV2UsbGeneration(
539
+ path,
540
+ `Node USB Protocol V1 ${direction} reconnect attempt ${attempt}`
541
+ );
534
542
  // Close the existing device without clearing the detected protocol cache.
535
543
  try {
536
544
  await this.closeOpenDevice(path);
@@ -623,22 +631,22 @@ export default class NodeUsbTransport {
623
631
  lastError = error;
624
632
  if (options?.waitIndefinitelyOnTimeout && this.isUsbTransferTimeout(error)) {
625
633
  attempt -= 1;
626
- continue;
627
- }
628
- const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
629
- if (!shouldRetry) {
630
- throw error;
631
- }
632
- try {
633
- currentDev = await this.reconnectForRetry(path, 'in', attempt, error);
634
- } catch (reconnectError) {
635
- lastError = reconnectError;
636
- this.Log?.debug(
637
- `[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(
638
- reconnectError
639
- )}`
640
- );
641
- break;
634
+ } else {
635
+ const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
636
+ if (!shouldRetry) {
637
+ throw error;
638
+ }
639
+ try {
640
+ currentDev = await this.reconnectForRetry(path, 'in', attempt, error);
641
+ } catch (reconnectError) {
642
+ lastError = reconnectError;
643
+ this.Log?.debug(
644
+ `[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(
645
+ reconnectError
646
+ )}`
647
+ );
648
+ break;
649
+ }
642
650
  }
643
651
  }
644
652
  }
@@ -787,9 +795,7 @@ export default class NodeUsbTransport {
787
795
  }
788
796
 
789
797
  private async resetConnectionAfterProbe(path: string) {
790
- this.protocolV2Assemblers.get(path)?.reset();
791
- this.protocolV2Sessions.delete(path);
792
- this.protocolV2ReadTimeouts.delete(path);
798
+ await this.rotateProtocolV2UsbGeneration(path, 'Node USB protocol probe reset');
793
799
 
794
800
  try {
795
801
  await this.closeOpenDevice(path);
@@ -871,75 +877,66 @@ export default class NodeUsbTransport {
871
877
  });
872
878
  }
873
879
 
874
- private async writeProtocolV2Frame(path: string, frame: Uint8Array) {
875
- let lastError: unknown;
876
- for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
880
+ protected getProtocolV2UsbSchemas(): ProtocolV2Schemas {
881
+ if (!this.messages || !this.messagesV2) {
882
+ throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
883
+ }
884
+ return {
885
+ protocolV1: this.messages,
886
+ protocolV2: this.messagesV2,
887
+ };
888
+ }
889
+
890
+ protected getProtocolV2UsbLogger() {
891
+ return this.Log;
892
+ }
893
+
894
+ protected async writeProtocolV2UsbPacket(
895
+ path: string,
896
+ frame: Uint8Array,
897
+ _context: ProtocolV2CallContext
898
+ ): Promise<void> {
899
+ if (this.cancelled) {
900
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
901
+ }
902
+ await transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
903
+ }
904
+
905
+ protected async readProtocolV2UsbPacket(
906
+ path: string,
907
+ _context: ProtocolV2CallContext
908
+ ): Promise<Uint8Array> {
909
+ for (;;) {
877
910
  if (this.cancelled) {
878
911
  throw ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
879
912
  }
880
913
  try {
881
- await transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
882
- return;
914
+ const packet = await transferInOnce(
915
+ this.getOpenDevice(path).epIn,
916
+ PROTOCOL_V2_FRAME_MAX_BYTES
917
+ );
918
+ return new Uint8Array(
919
+ packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength)
920
+ );
883
921
  } catch (error) {
884
- lastError = error;
885
- const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
886
- if (!shouldRetry) {
922
+ if (!this.isUsbTransferTimeout(error)) {
887
923
  throw error;
888
924
  }
889
- try {
890
- await this.reconnectForRetry(path, 'out', attempt, error);
891
- } catch (reconnectError) {
892
- lastError = reconnectError;
893
- this.Log?.debug(
894
- `[NodeUsbTransport] Protocol V2 write reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(
895
- reconnectError
896
- )}`
897
- );
898
- break;
899
- }
900
925
  }
901
926
  }
902
- throw lastError;
903
927
  }
904
928
 
905
- private async receiveProtocolV2Frame(path: string, timeoutMs?: number): Promise<Uint8Array> {
906
- let assembler = this.protocolV2Assemblers.get(path);
907
- if (!assembler) {
908
- assembler = new ProtocolV2FrameAssembler(PROTOCOL_V2_FRAME_MAX_BYTES);
909
- this.protocolV2Assemblers.set(path, assembler);
910
- }
929
+ protected async resetProtocolV2UsbNativeLink(path: string, _reason: string): Promise<void> {
930
+ await this.closeOpenDevice(path);
931
+ }
911
932
 
912
- let frame: Uint8Array | undefined = assembler.push(new Uint8Array(0));
913
- const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
933
+ protected onProtocolV2UsbLinkInvalidated(path: string, reason: string) {
934
+ this.deviceProtocol.delete(path);
935
+ this.Log?.debug(`[NodeUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
936
+ }
914
937
 
915
- while (!frame) {
916
- const transferIn = this.transferInWithRetry(
917
- path,
918
- this.getOpenDevice(path),
919
- PROTOCOL_V2_FRAME_MAX_BYTES,
920
- { waitIndefinitelyOnTimeout: !deadline }
921
- );
922
- const packet = deadline
923
- ? await this.withProtocolReadTimeout(
924
- path,
925
- transferIn,
926
- Math.max(deadline - Date.now(), 1),
927
- 'V2'
928
- )
929
- : await transferIn;
930
- const bytes = new Uint8Array(
931
- packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength)
932
- );
933
- try {
934
- frame = assembler.push(bytes);
935
- } catch (error) {
936
- throw ERRORS.TypedError(
937
- HardwareErrorCode.NetworkError,
938
- error instanceof Error ? error.message : String(error)
939
- );
940
- }
941
- }
942
- return frame;
938
+ protected createProtocolV2UsbTimeoutError(name: string, timeoutMs: number): Error {
939
+ return new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
943
940
  }
944
941
 
945
942
  private async callProtocolV2(
@@ -948,42 +945,7 @@ export default class NodeUsbTransport {
948
945
  data: Record<string, unknown>,
949
946
  options?: TransportCallOptions
950
947
  ) {
951
- const protocolV1Messages = this.messages;
952
- if (!this.messagesV2) {
953
- throw ERRORS.TypedError(
954
- HardwareErrorCode.TransportNotConfigured,
955
- 'Protocol V2 schema not configured'
956
- );
957
- }
958
- if (!protocolV1Messages) {
959
- throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
960
- }
961
-
962
- let session = this.protocolV2Sessions.get(path);
963
- if (!session) {
964
- session = new ProtocolV2Session({
965
- schemas: {
966
- protocolV1: protocolV1Messages,
967
- protocolV2: this.messagesV2,
968
- },
969
- router: PROTOCOL_V2_CHANNEL_USB,
970
- writeFrame: (frame: Uint8Array) => this.writeProtocolV2Frame(path, frame),
971
- readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
972
- logger: this.Log,
973
- logPrefix: 'ProtocolV2 NodeUSB',
974
- createTimeoutError: (messageName: string, timeoutMs: number) =>
975
- new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
976
- });
977
- this.protocolV2Sessions.set(path, session);
978
- }
979
-
980
- this.protocolV2ReadTimeouts.set(path, options?.timeoutMs);
981
- this.protocolV2Assemblers.get(path)?.reset();
982
- try {
983
- return await session.call(name, data, options);
984
- } finally {
985
- this.protocolV2ReadTimeouts.delete(path);
986
- }
948
+ return this.callProtocolV2Usb(path, name, data, options);
987
949
  }
988
950
 
989
951
  /**