@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.
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +41 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +355 -86
- package/package.json +4 -4
- package/src/constants.ts +3 -0
- package/src/index.ts +499 -131
package/dist/constants.d.ts
CHANGED
package/dist/constants.d.ts.map
CHANGED
|
@@ -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
|
|
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
|
|
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,
|
|
45
|
+
export { PACKET_SIZE, NodeUsbTransport as default };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
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
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
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
|
|
135
|
-
if (
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
271
|
+
catch (_a) {
|
|
272
|
+
try {
|
|
273
|
+
openDev.device.close();
|
|
274
|
+
}
|
|
275
|
+
catch (_b) {
|
|
276
|
+
}
|
|
143
277
|
}
|
|
144
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
},
|
|
208
|
-
receive() {
|
|
479
|
+
throw err;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
receiveData(path, dev) {
|
|
209
483
|
return __awaiter(this, void 0, void 0, function* () {
|
|
210
|
-
|
|
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
|
|
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 >=
|
|
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
|
|
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.
|
|
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.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.1.
|
|
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": "
|
|
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;
|