@onekeyfe/hd-transport-usb 1.1.25 → 1.1.26-alpha.10

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.
@@ -1,4 +1,5 @@
1
1
  export declare const PACKET_SIZE = 64;
2
2
  export declare const REPORT_ID = 63;
3
+ export declare const PAYLOAD_SIZE: number;
3
4
  export declare const HEADER_LENGTH = 6;
4
5
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW,KAAK,CAAC;AAG9B,eAAO,MAAM,SAAS,KAAO,CAAC;AAG9B,eAAO,MAAM,aAAa,IAAI,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW,KAAK,CAAC;AAG9B,eAAO,MAAM,SAAS,KAAO,CAAC;AAG9B,eAAO,MAAM,YAAY,QAAkB,CAAC;AAG5C,eAAO,MAAM,aAAa,IAAI,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,45 @@
1
- import { LowlevelTransportSharedPlugin } from '@onekeyfe/hd-transport';
1
+ import * as transport from '@onekeyfe/hd-transport';
2
+ import transport__default, { OneKeyDeviceInfo, AcquireInput } from '@onekeyfe/hd-transport';
3
+ import EventEmitter from 'events';
2
4
 
3
5
  declare const PACKET_SIZE = 64;
4
6
 
5
- declare const UsbPlugin: LowlevelTransportSharedPlugin;
7
+ declare class NodeUsbTransport {
8
+ messages: ReturnType<typeof transport__default.parseConfigure> | undefined;
9
+ name: string;
10
+ version: string;
11
+ configured: boolean;
12
+ isOutdated: boolean;
13
+ Log?: any;
14
+ emitter?: EventEmitter;
15
+ private serialToBusId;
16
+ private openDevices;
17
+ private reconnectLocks;
18
+ private cancelled;
19
+ init(logger: any, emitter?: EventEmitter): Promise<string>;
20
+ configure(signedData: any): Promise<void>;
21
+ listen(): void;
22
+ stop(): void;
23
+ post(path: string, name: string, data: Record<string, unknown>): Promise<void>;
24
+ read(path: string): Promise<{
25
+ message: {
26
+ [key: string]: any;
27
+ };
28
+ type: string;
29
+ }>;
30
+ enumerate(): Promise<OneKeyDeviceInfo[]>;
31
+ acquire(input: AcquireInput): Promise<string>;
32
+ release(path: string, _onclose?: boolean): Promise<void>;
33
+ call(path: string, name: string, data: Record<string, unknown>): Promise<transport.MessageFromOneKey>;
34
+ cancel(): void;
35
+ private getOpenDevice;
36
+ private getErrorMessage;
37
+ private isRetryableError;
38
+ private reconnectForRetry;
39
+ private sendAllChunksWithRetry;
40
+ private transferInWithRetry;
41
+ private openDevice;
42
+ private receiveData;
43
+ }
6
44
 
7
- export { PACKET_SIZE, UsbPlugin, UsbPlugin as default };
45
+ export { PACKET_SIZE, NodeUsbTransport as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAkB,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAoG5F,eAAO,MAAM,SAAS,EAAE,6BA+JvB,CAAC;AAEF,eAAe,SAAS,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,SAA8B,MAAM,wBAAwB,CAAC;AAKpE,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AA0J7E,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAElE,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,CAA0C;IAGhE,OAAO,CAAC,SAAS,CAAS;IAM1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAMxC,SAAS,CAAC,UAAU,EAAE,GAAG;IAOzB,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;IA8B9C,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBvC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BxD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAkCpE,MAAM;IAWN,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,iBAAiB;YAmDX,sBAAsB;YAyCtB,mBAAmB;IAsCjC,OAAO,CAAC,UAAU;YAgEJ,WAAW;CAkC1B;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -63,19 +63,78 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
63
63
 
64
64
  const PACKET_SIZE = 64;
65
65
  const REPORT_ID = 0x3f;
66
+ const PAYLOAD_SIZE = PACKET_SIZE - 1;
66
67
  const HEADER_LENGTH = 6;
67
68
 
68
- const { decodeProtocol } = transport__default["default"];
69
+ const { parseConfigure, buildEncodeBuffers, decodeProtocol, receiveOne, check } = transport__default["default"];
69
70
  const INTERFACE_NUMBER = 0;
70
71
  const ENDPOINT_IN = 0x81;
71
72
  const ENDPOINT_OUT = 0x01;
72
73
  const TRANSFER_TIMEOUT_MS = 30000;
73
- let activeDevice = null;
74
- const openDevices = new Map();
75
- function getDeviceId(dev) {
74
+ const SERIAL_READ_TIMEOUT_MS = 5000;
75
+ const PACKET_IO_MAX_RETRIES = 3;
76
+ const PACKET_IO_RETRY_DELAY = 300;
77
+ function getBusId(dev) {
76
78
  return `usb:${dev.busNumber}:${dev.deviceAddress}`;
77
79
  }
78
- function transferIn(ep, length) {
80
+ function readSerialNumber(dev, openDevices) {
81
+ const { iSerialNumber } = dev.deviceDescriptor;
82
+ if (!iSerialNumber)
83
+ return Promise.resolve(getBusId(dev));
84
+ const busId = getBusId(dev);
85
+ if (openDevices) {
86
+ for (const [serial, od] of openDevices) {
87
+ if (od.device === dev || getBusId(od.device) === busId) {
88
+ return Promise.resolve(serial);
89
+ }
90
+ }
91
+ }
92
+ return new Promise(resolve => {
93
+ let settled = false;
94
+ const settle = (value) => {
95
+ if (settled)
96
+ return;
97
+ settled = true;
98
+ resolve(value);
99
+ };
100
+ const timer = setTimeout(() => {
101
+ try {
102
+ dev.close();
103
+ }
104
+ catch (_a) {
105
+ }
106
+ settle(busId);
107
+ }, SERIAL_READ_TIMEOUT_MS);
108
+ try {
109
+ dev.open();
110
+ try {
111
+ dev.getStringDescriptor(iSerialNumber, (_err, data) => {
112
+ clearTimeout(timer);
113
+ try {
114
+ dev.close();
115
+ }
116
+ catch (_a) {
117
+ }
118
+ settle(data || busId);
119
+ });
120
+ }
121
+ catch (_a) {
122
+ clearTimeout(timer);
123
+ try {
124
+ dev.close();
125
+ }
126
+ catch (_b) {
127
+ }
128
+ settle(busId);
129
+ }
130
+ }
131
+ catch (_c) {
132
+ clearTimeout(timer);
133
+ settle(busId);
134
+ }
135
+ });
136
+ }
137
+ function transferInOnce(ep, length) {
79
138
  return new Promise((resolve, reject) => {
80
139
  ep.transfer(length, (err, data) => {
81
140
  if (err)
@@ -86,7 +145,7 @@ function transferIn(ep, length) {
86
145
  });
87
146
  });
88
147
  }
89
- function transferOut(ep, data) {
148
+ function transferOutOnce(ep, data) {
90
149
  return new Promise((resolve, reject) => {
91
150
  ep.transfer(data, (err) => {
92
151
  if (err)
@@ -95,11 +154,6 @@ function transferOut(ep, data) {
95
154
  });
96
155
  });
97
156
  }
98
- function readPacket(dev) {
99
- return __awaiter(this, void 0, void 0, function* () {
100
- return transferIn(dev.epIn, PACKET_SIZE);
101
- });
102
- }
103
157
  function skipReportByte(packet) {
104
158
  if (packet[0] === REPORT_ID) {
105
159
  return packet.subarray(1);
@@ -109,12 +163,54 @@ function skipReportByte(packet) {
109
163
  function toArrayBuffer(buf) {
110
164
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
111
165
  }
112
- const UsbPlugin = {
113
- version: '1.0.0',
114
- init() {
166
+ class NodeUsbTransport {
167
+ constructor() {
168
+ this.name = 'NodeUsbTransport';
169
+ this.version = '';
170
+ this.configured = false;
171
+ this.isOutdated = false;
172
+ this.serialToBusId = new Map();
173
+ this.openDevices = new Map();
174
+ this.reconnectLocks = new Map();
175
+ this.cancelled = false;
176
+ }
177
+ init(logger, emitter) {
178
+ this.Log = logger;
179
+ this.emitter = emitter;
180
+ return Promise.resolve('');
181
+ }
182
+ configure(signedData) {
183
+ const messages = parseConfigure(signedData);
184
+ this.configured = true;
185
+ this.messages = messages;
186
+ return Promise.resolve();
187
+ }
188
+ listen() {
189
+ }
190
+ stop() {
191
+ }
192
+ post(path, name, data) {
115
193
  return __awaiter(this, void 0, void 0, function* () {
194
+ if (!this.messages) {
195
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
196
+ }
197
+ const encodeBuffers = buildEncodeBuffers(this.messages, name, data);
198
+ yield this.sendAllChunksWithRetry(path, encodeBuffers);
199
+ });
200
+ }
201
+ read(path) {
202
+ return __awaiter(this, void 0, void 0, function* () {
203
+ const dev = this.getOpenDevice(path);
204
+ const resData = yield this.receiveData(path, dev);
205
+ if (typeof resData !== 'string') {
206
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Returning data is not string.');
207
+ }
208
+ if (!this.messages) {
209
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
210
+ }
211
+ return receiveOne(this.messages, resData);
116
212
  });
117
- },
213
+ }
118
214
  enumerate() {
119
215
  return __awaiter(this, void 0, void 0, function* () {
120
216
  const allDevices = usb__namespace.getDeviceList();
@@ -122,26 +218,237 @@ const UsbPlugin = {
122
218
  const { idVendor, idProduct } = d.deviceDescriptor;
123
219
  return hdShared.ONEKEY_WEBUSB_FILTER.some(f => idVendor === f.vendorId && idProduct === f.productId);
124
220
  });
125
- return onekeyDevices.map(d => ({
126
- id: getDeviceId(d),
127
- name: 'OneKey',
128
- commType: 'usb',
129
- }));
221
+ const newSerialToBusId = new Map();
222
+ const results = [];
223
+ for (const d of onekeyDevices) {
224
+ const busId = getBusId(d);
225
+ const serial = yield readSerialNumber(d, this.openDevices);
226
+ newSerialToBusId.set(serial, busId);
227
+ results.push({
228
+ path: serial,
229
+ id: serial,
230
+ name: 'OneKey',
231
+ commType: 'usb',
232
+ debug: false,
233
+ });
234
+ }
235
+ this.serialToBusId = newSerialToBusId;
236
+ return results;
130
237
  });
131
- },
132
- connect(uuid) {
238
+ }
239
+ acquire(input) {
240
+ var _a, _b, _c;
241
+ const path = (_a = input.path) !== null && _a !== void 0 ? _a : '';
242
+ if (!path) {
243
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
244
+ }
245
+ try {
246
+ this.openDevice(path);
247
+ return Promise.resolve(path);
248
+ }
249
+ catch (error) {
250
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport acquire error: ', error);
251
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, (_c = error.message) !== null && _c !== void 0 ? _c : String(error));
252
+ }
253
+ }
254
+ release(path, _onclose) {
133
255
  return __awaiter(this, void 0, void 0, function* () {
134
- const existing = openDevices.get(uuid);
135
- if (existing) {
136
- activeDevice = existing;
256
+ const openDev = this.openDevices.get(path);
257
+ if (!openDev)
137
258
  return;
259
+ try {
260
+ yield new Promise(resolve => {
261
+ openDev.iface.release(() => {
262
+ try {
263
+ openDev.device.close();
264
+ }
265
+ catch (_a) {
266
+ }
267
+ resolve();
268
+ });
269
+ });
138
270
  }
139
- const allDevices = usb__namespace.getDeviceList();
140
- const dev = allDevices.find(d => getDeviceId(d) === uuid);
141
- if (!dev) {
142
- throw new Error(`USB device not found: ${uuid}`);
271
+ catch (_a) {
272
+ try {
273
+ openDev.device.close();
274
+ }
275
+ catch (_b) {
276
+ }
143
277
  }
144
- dev.open();
278
+ this.openDevices.delete(path);
279
+ });
280
+ }
281
+ call(path, name, data) {
282
+ var _a, _b;
283
+ return __awaiter(this, void 0, void 0, function* () {
284
+ this.cancelled = false;
285
+ if (!this.messages) {
286
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
287
+ }
288
+ if (!this.openDevices.get(path)) {
289
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device not acquired: ${path}`);
290
+ }
291
+ const { messages } = this;
292
+ if (transport.LogBlockCommand.has(name)) {
293
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport call-', ' name: ', name);
294
+ }
295
+ else {
296
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data);
297
+ }
298
+ const encodeBuffers = buildEncodeBuffers(messages, name, data);
299
+ yield this.sendAllChunksWithRetry(path, encodeBuffers);
300
+ const resData = yield this.receiveData(path, this.getOpenDevice(path));
301
+ if (typeof resData !== 'string') {
302
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Returning data is not string.');
303
+ }
304
+ const jsonData = receiveOne(messages, resData);
305
+ return check.call(jsonData);
306
+ });
307
+ }
308
+ cancel() {
309
+ var _a;
310
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport cancel');
311
+ this.cancelled = true;
312
+ }
313
+ getOpenDevice(path) {
314
+ const dev = this.openDevices.get(path);
315
+ if (!dev) {
316
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device not acquired: ${path}`);
317
+ }
318
+ return dev;
319
+ }
320
+ getErrorMessage(error) {
321
+ if (!error)
322
+ return '';
323
+ if (typeof error === 'string')
324
+ return error;
325
+ if (typeof error === 'object' && 'message' in error) {
326
+ const { message } = error;
327
+ return typeof message === 'string' ? message : String(message !== null && message !== void 0 ? message : '');
328
+ }
329
+ return String(error);
330
+ }
331
+ isRetryableError(error) {
332
+ const message = this.getErrorMessage(error).toLowerCase();
333
+ return (message.includes('libusb') ||
334
+ message.includes('transfer') ||
335
+ message.includes('disconnected') ||
336
+ message.includes('device not found') ||
337
+ message.includes('busy') ||
338
+ message.includes('pipe') ||
339
+ message.includes('empty usb transfer') ||
340
+ message.includes('network') ||
341
+ message.includes('timeout') ||
342
+ message.includes('interrupt'));
343
+ }
344
+ reconnectForRetry(path, direction, attempt, error) {
345
+ const existing = this.reconnectLocks.get(path);
346
+ if (existing)
347
+ return existing;
348
+ const doReconnect = () => __awaiter(this, void 0, void 0, function* () {
349
+ var _a, _b;
350
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
351
+ yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
352
+ try {
353
+ yield this.release(path);
354
+ }
355
+ catch (releaseError) {
356
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[NodeUsbTransport] release before retry error:', releaseError);
357
+ }
358
+ yield this.enumerate();
359
+ this.openDevice(path);
360
+ const openDev = this.openDevices.get(path);
361
+ if (!openDev) {
362
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device not found after reconnect: ${path}`);
363
+ }
364
+ return openDev;
365
+ });
366
+ const promise = doReconnect().finally(() => {
367
+ this.reconnectLocks.delete(path);
368
+ });
369
+ this.reconnectLocks.set(path, promise);
370
+ return promise;
371
+ }
372
+ sendAllChunksWithRetry(path, encodeBuffers) {
373
+ var _a;
374
+ return __awaiter(this, void 0, void 0, function* () {
375
+ let lastError;
376
+ for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
377
+ if (this.cancelled) {
378
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
379
+ }
380
+ try {
381
+ for (const buffer of encodeBuffers) {
382
+ const packet = new Uint8Array(PACKET_SIZE);
383
+ packet[0] = REPORT_ID;
384
+ packet.set(new Uint8Array(buffer), 1);
385
+ yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(packet));
386
+ }
387
+ return;
388
+ }
389
+ catch (error) {
390
+ lastError = error;
391
+ const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
392
+ if (!shouldRetry) {
393
+ throw error;
394
+ }
395
+ try {
396
+ yield this.reconnectForRetry(path, 'out', attempt, error);
397
+ }
398
+ catch (reconnectError) {
399
+ lastError = reconnectError;
400
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reconnect failed on send retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
401
+ break;
402
+ }
403
+ }
404
+ }
405
+ throw lastError;
406
+ });
407
+ }
408
+ transferInWithRetry(path, openDev, length) {
409
+ var _a;
410
+ return __awaiter(this, void 0, void 0, function* () {
411
+ let lastError;
412
+ let currentDev = openDev;
413
+ for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
414
+ if (this.cancelled) {
415
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
416
+ }
417
+ try {
418
+ return yield transferInOnce(currentDev.epIn, length);
419
+ }
420
+ catch (error) {
421
+ lastError = error;
422
+ const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
423
+ if (!shouldRetry) {
424
+ throw error;
425
+ }
426
+ try {
427
+ currentDev = yield this.reconnectForRetry(path, 'in', attempt, error);
428
+ }
429
+ catch (reconnectError) {
430
+ lastError = reconnectError;
431
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
432
+ break;
433
+ }
434
+ }
435
+ }
436
+ throw lastError;
437
+ });
438
+ }
439
+ openDevice(path) {
440
+ var _a;
441
+ const existing = this.openDevices.get(path);
442
+ if (existing)
443
+ return;
444
+ const busId = (_a = this.serialToBusId.get(path)) !== null && _a !== void 0 ? _a : path;
445
+ const allDevices = usb__namespace.getDeviceList();
446
+ const dev = allDevices.find(d => getBusId(d) === busId);
447
+ if (!dev) {
448
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `USB device not found: ${path}`);
449
+ }
450
+ dev.open();
451
+ try {
145
452
  dev.timeout = TRANSFER_TIMEOUT_MS;
146
453
  const iface = dev.interface(INTERFACE_NUMBER);
147
454
  if (process.platform === 'linux') {
@@ -150,68 +457,31 @@ const UsbPlugin = {
150
457
  iface.detachKernelDriver();
151
458
  }
152
459
  }
153
- catch (_a) {
460
+ catch (_b) {
154
461
  }
155
462
  }
156
463
  iface.claim();
157
464
  const epIn = iface.endpoints.find((e) => e.direction === 'in' && e.address === ENDPOINT_IN);
158
465
  const epOut = iface.endpoints.find((e) => e.direction === 'out' && e.address === ENDPOINT_OUT);
159
466
  if (!epIn || !epOut) {
160
- dev.close();
161
- throw new Error('USB endpoints not found (expected IN 0x81, OUT 0x01)');
467
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'USB endpoints not found (expected IN 0x81, OUT 0x01)');
162
468
  }
163
469
  epIn.timeout = TRANSFER_TIMEOUT_MS;
164
470
  epOut.timeout = TRANSFER_TIMEOUT_MS;
165
- const openDev = { device: dev, iface, epIn, epOut };
166
- openDevices.set(uuid, openDev);
167
- activeDevice = openDev;
168
- });
169
- },
170
- disconnect(uuid) {
171
- return __awaiter(this, void 0, void 0, function* () {
172
- const openDev = openDevices.get(uuid);
173
- if (openDev) {
174
- try {
175
- openDev.iface.release(() => {
176
- try {
177
- openDev.device.close();
178
- }
179
- catch (_a) {
180
- }
181
- });
182
- }
183
- catch (_a) {
184
- try {
185
- openDev.device.close();
186
- }
187
- catch (_b) {
188
- }
189
- }
190
- openDevices.delete(uuid);
191
- if (activeDevice === openDev) {
192
- activeDevice = null;
193
- }
471
+ this.openDevices.set(path, { device: dev, iface, epIn, epOut });
472
+ }
473
+ catch (err) {
474
+ try {
475
+ dev.close();
194
476
  }
195
- });
196
- },
197
- send(uuid, data) {
198
- return __awaiter(this, void 0, void 0, function* () {
199
- const openDev = openDevices.get(uuid);
200
- if (!openDev) {
201
- throw new Error(`Device not connected: ${uuid}`);
477
+ catch (_c) {
202
478
  }
203
- activeDevice = openDev;
204
- const dataBuffer = Buffer.from(data, 'hex');
205
- yield transferOut(openDev.epOut, dataBuffer);
206
- });
207
- },
208
- receive() {
479
+ throw err;
480
+ }
481
+ }
482
+ receiveData(path, dev) {
209
483
  return __awaiter(this, void 0, void 0, function* () {
210
- if (!activeDevice) {
211
- throw new Error('No active device for receive');
212
- }
213
- const dev = activeDevice;
214
- const firstPacket = yield readPacket(dev);
484
+ const firstPacket = yield this.transferInWithRetry(path, dev, PACKET_SIZE);
215
485
  const firstData = skipReportByte(firstPacket);
216
486
  const { length, typeId, restBuffer } = decodeProtocol.decodeChunked(toArrayBuffer(firstData));
217
487
  const lengthWithHeader = Number(length) + HEADER_LENGTH;
@@ -222,10 +492,10 @@ const UsbPlugin = {
222
492
  decoded.append(restBuffer);
223
493
  }
224
494
  while (decoded.offset < lengthWithHeader) {
225
- const packet = yield readPacket(dev);
495
+ const packet = yield this.transferInWithRetry(path, this.getOpenDevice(path), PACKET_SIZE);
226
496
  const pktData = skipReportByte(packet);
227
497
  const buf = toArrayBuffer(pktData);
228
- if (lengthWithHeader - decoded.offset >= PACKET_SIZE) {
498
+ if (lengthWithHeader - decoded.offset >= PAYLOAD_SIZE) {
229
499
  decoded.append(buf);
230
500
  }
231
501
  else {
@@ -236,9 +506,8 @@ const UsbPlugin = {
236
506
  const result = decoded.toBuffer();
237
507
  return Buffer.from(result).toString('hex');
238
508
  });
239
- },
240
- };
509
+ }
510
+ }
241
511
 
242
512
  exports.PACKET_SIZE = PACKET_SIZE;
243
- exports.UsbPlugin = UsbPlugin;
244
- exports["default"] = UsbPlugin;
513
+ exports["default"] = NodeUsbTransport;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-usb",
3
- "version": "1.1.25",
3
+ "version": "1.1.26-alpha.10",
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.1.25",
24
- "@onekeyfe/hd-transport": "1.1.25",
23
+ "@onekeyfe/hd-shared": "1.1.26-alpha.10",
24
+ "@onekeyfe/hd-transport": "1.1.26-alpha.10",
25
25
  "bytebuffer": "^5.0.1",
26
26
  "usb": "^2.14.0"
27
27
  },
28
- "gitHead": "6110417c47363db38190076610ea4de0e8508924"
28
+ "gitHead": "4cab4ba97dee894aa87145ced1e629c06f0ab8b7"
29
29
  }
package/src/constants.ts CHANGED
@@ -4,5 +4,8 @@ export const PACKET_SIZE = 64;
4
4
  /** Protocol marker byte (0x3F = '?') — first byte of every packet */
5
5
  export const REPORT_ID = 0x3f;
6
6
 
7
+ /** Usable payload per packet after stripping the 0x3F report byte */
8
+ export const PAYLOAD_SIZE = PACKET_SIZE - 1;
9
+
7
10
  /** Protocol header length: typeId (2 bytes) + length (4 bytes) */
8
11
  export const HEADER_LENGTH = 6;