@onekeyfe/hd-transport-web-device 1.2.8-alpha.103 → 1.2.8-alpha.104
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__/webusb-identity-probe.test.ts +0 -47
- package/__tests__/webusb-protocol-cache.test.ts +1 -219
- package/dist/index.d.ts +2 -20
- package/dist/index.js +65 -373
- package/dist/webusb.d.ts +2 -21
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/webusb.ts +57 -494
package/dist/index.js
CHANGED
|
@@ -52,14 +52,11 @@ const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
|
52
52
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
53
53
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
54
54
|
const USB_DEVICE_IN_USE = 'USB device is already in use';
|
|
55
|
-
const WEBUSB_LIFECYCLE_LOG_PREFIX = '[WebUsbTransport][lifecycle]';
|
|
56
|
-
const WEBUSB_ERROR_MESSAGE_LIMIT = 240;
|
|
57
55
|
const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
|
|
58
56
|
const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
|
|
59
57
|
const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
|
|
60
58
|
let activeWebUsbTransport;
|
|
61
59
|
let usbDisconnectListenerAttached = false;
|
|
62
|
-
let nextWebUsbTransportInstanceId = 0;
|
|
63
60
|
const identityProbeHandles = new WeakSet();
|
|
64
61
|
const openingHandles = new WeakSet();
|
|
65
62
|
const normalHandleOwners = new WeakMap();
|
|
@@ -86,10 +83,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
86
83
|
logPrefix: 'ProtocolV2 WebUSB',
|
|
87
84
|
});
|
|
88
85
|
this.identityProbe = identityProbe;
|
|
89
|
-
this.transportInstanceId = ++nextWebUsbTransportInstanceId;
|
|
90
|
-
this.handleOperationSequence = 0;
|
|
91
|
-
this.deviceLogSequence = 0;
|
|
92
|
-
this.deviceLogIds = new WeakMap();
|
|
93
86
|
this.deviceProtocol = new Map();
|
|
94
87
|
this.confirmedDeviceProtocols = new Map();
|
|
95
88
|
this.deviceProtocolHints = new Map();
|
|
@@ -121,20 +114,12 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
121
114
|
registerActiveWebUsbTransport(this, usb);
|
|
122
115
|
}
|
|
123
116
|
stop() {
|
|
124
|
-
const startedAt = Date.now();
|
|
125
117
|
this.stopped = true;
|
|
126
118
|
this.acquiredPaths.clear();
|
|
127
119
|
if (activeWebUsbTransport === this)
|
|
128
120
|
activeWebUsbTransport = undefined;
|
|
129
121
|
if (!this.stopPromise) {
|
|
130
|
-
this.
|
|
131
|
-
this.stopPromise = this.stopResources().then(() => {
|
|
132
|
-
this.logLifecycle('stop', {
|
|
133
|
-
phase: 'success',
|
|
134
|
-
durationMs: Date.now() - startedAt,
|
|
135
|
-
});
|
|
136
|
-
}, error => {
|
|
137
|
-
this.logLifecycle('stop', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(error)));
|
|
122
|
+
this.stopPromise = this.stopResources().catch(error => {
|
|
138
123
|
this.stopPromise = undefined;
|
|
139
124
|
throw error;
|
|
140
125
|
});
|
|
@@ -163,31 +148,13 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
163
148
|
try {
|
|
164
149
|
if (device.opened) {
|
|
165
150
|
const iface = (_b = (_a = this.deviceEndpoints.get(path)) === null || _a === void 0 ? void 0 : _a.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
166
|
-
|
|
167
|
-
|
|
151
|
+
try {
|
|
152
|
+
yield device.releaseInterface(iface);
|
|
168
153
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
yield this.runLoggedHandleOperation({
|
|
172
|
-
operation: 'releaseInterface',
|
|
173
|
-
device,
|
|
174
|
-
path,
|
|
175
|
-
interfaceNumber: iface,
|
|
176
|
-
allowStopped: true,
|
|
177
|
-
task: () => device.releaseInterface(iface),
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
catch (error) {
|
|
181
|
-
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] stop releaseInterface failed:', error);
|
|
182
|
-
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] stop releaseInterface failed:', error);
|
|
183
156
|
}
|
|
184
|
-
yield
|
|
185
|
-
operation: 'close',
|
|
186
|
-
device,
|
|
187
|
-
path,
|
|
188
|
-
allowStopped: true,
|
|
189
|
-
task: () => device.close(),
|
|
190
|
-
});
|
|
157
|
+
yield device.close();
|
|
191
158
|
if (device.opened)
|
|
192
159
|
throw new Error('WebUSB handle remains open after stop');
|
|
193
160
|
}
|
|
@@ -242,71 +209,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
242
209
|
}
|
|
243
210
|
});
|
|
244
211
|
}
|
|
245
|
-
getInterfaceClaimed(device, interfaceNumber) {
|
|
246
|
-
var _a, _b, _c;
|
|
247
|
-
return (_c = (_b = (_a = device.configuration) === null || _a === void 0 ? void 0 : _a.interfaces) === null || _b === void 0 ? void 0 : _b.find(usbInterface => usbInterface.interfaceNumber === interfaceNumber)) === null || _c === void 0 ? void 0 : _c.claimed;
|
|
248
|
-
}
|
|
249
|
-
getDeviceLogId(device) {
|
|
250
|
-
const existing = this.deviceLogIds.get(device);
|
|
251
|
-
if (existing)
|
|
252
|
-
return existing;
|
|
253
|
-
const next = ++this.deviceLogSequence;
|
|
254
|
-
this.deviceLogIds.set(device, next);
|
|
255
|
-
return next;
|
|
256
|
-
}
|
|
257
|
-
getHandleLogState(device, interfaceNumber) {
|
|
258
|
-
var _a, _b;
|
|
259
|
-
const interfaceClaimed = interfaceNumber === undefined ? undefined : this.getInterfaceClaimed(device, interfaceNumber);
|
|
260
|
-
return {
|
|
261
|
-
deviceRefId: this.getDeviceLogId(device),
|
|
262
|
-
opened: device.opened,
|
|
263
|
-
configurationValue: (_b = (_a = device.configuration) === null || _a === void 0 ? void 0 : _a.configurationValue) !== null && _b !== void 0 ? _b : null,
|
|
264
|
-
interfaceNumber: interfaceNumber !== null && interfaceNumber !== void 0 ? interfaceNumber : null,
|
|
265
|
-
interfaceClaimed: interfaceClaimed !== null && interfaceClaimed !== void 0 ? interfaceClaimed : null,
|
|
266
|
-
identityProbe: this.identityProbe,
|
|
267
|
-
stopped: this.stopped,
|
|
268
|
-
acquiredPathCount: this.acquiredPaths.size,
|
|
269
|
-
normalHandleCount: this.normalDevices.size,
|
|
270
|
-
identityProbeHandleCount: this.identityProbeDevices.size,
|
|
271
|
-
pendingHandleOperationCount: this.pendingHandleOperations.size,
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
getDiagnosticError(error, path) {
|
|
275
|
-
const errorMessage = this.getErrorMessage(error);
|
|
276
|
-
const redactedMessage = path ? errorMessage.split(path).join('<device>') : errorMessage;
|
|
277
|
-
return {
|
|
278
|
-
errorName: this.getErrorName(error) || 'Error',
|
|
279
|
-
errorMessage: redactedMessage.slice(0, WEBUSB_ERROR_MESSAGE_LIMIT),
|
|
280
|
-
errorCode: error instanceof hdShared.HardwareError ? error.errorCode : undefined,
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
logLifecycle(event, payload = {}) {
|
|
284
|
-
var _a;
|
|
285
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(WEBUSB_LIFECYCLE_LOG_PREFIX, Object.assign({ event, transportInstanceId: this.transportInstanceId }, payload));
|
|
286
|
-
}
|
|
287
|
-
logSkippedHandleOperation(operation, device, reason, interfaceNumber) {
|
|
288
|
-
const operationId = ++this.handleOperationSequence;
|
|
289
|
-
this.logLifecycle('handle-operation', Object.assign({ operationId,
|
|
290
|
-
operation, phase: 'skipped', reason }, this.getHandleLogState(device, interfaceNumber)));
|
|
291
|
-
}
|
|
292
|
-
runLoggedHandleOperation({ operation, device, task, path, interfaceNumber, endpointNumber, allowStopped = false, }) {
|
|
293
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
-
const operationId = ++this.handleOperationSequence;
|
|
295
|
-
const startedAt = Date.now();
|
|
296
|
-
const details = Object.assign({ operationId,
|
|
297
|
-
operation }, (endpointNumber === undefined ? {} : { endpointNumber }));
|
|
298
|
-
this.logLifecycle('handle-operation', Object.assign(Object.assign(Object.assign({}, details), { phase: 'start' }), this.getHandleLogState(device, interfaceNumber)));
|
|
299
|
-
try {
|
|
300
|
-
const result = allowStopped ? yield task() : yield this.runHandleOperation(task);
|
|
301
|
-
this.logLifecycle('handle-operation', Object.assign(Object.assign(Object.assign({}, details), { phase: 'success', durationMs: Date.now() - startedAt }), this.getHandleLogState(device, interfaceNumber)));
|
|
302
|
-
return result;
|
|
303
|
-
}
|
|
304
|
-
catch (error) {
|
|
305
|
-
this.logLifecycle('handle-operation', Object.assign(Object.assign(Object.assign(Object.assign({}, details), { phase: 'error', durationMs: Date.now() - startedAt }), this.getHandleLogState(device, interfaceNumber)), this.getDiagnosticError(error, path)));
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
212
|
emitDeviceDisconnect(path, device) {
|
|
311
213
|
var _a, _b;
|
|
312
214
|
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
@@ -342,19 +244,11 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
342
244
|
return __awaiter(this, void 0, void 0, function* () {
|
|
343
245
|
if (!this.usb)
|
|
344
246
|
return null;
|
|
345
|
-
const startedAt = Date.now();
|
|
346
|
-
this.logLifecycle('prompt-device-access', { phase: 'start' });
|
|
347
247
|
try {
|
|
348
248
|
const device = yield this.usb.requestDevice({ filters: hdShared.ONEKEY_WEBUSB_FILTER });
|
|
349
|
-
this.logLifecycle('prompt-device-access', {
|
|
350
|
-
phase: 'success',
|
|
351
|
-
durationMs: Date.now() - startedAt,
|
|
352
|
-
selected: Boolean(device),
|
|
353
|
-
});
|
|
354
249
|
return device;
|
|
355
250
|
}
|
|
356
251
|
catch (e) {
|
|
357
|
-
this.logLifecycle('prompt-device-access', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(e)));
|
|
358
252
|
this.Log.debug('requestDevice error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
|
|
359
253
|
return null;
|
|
360
254
|
}
|
|
@@ -362,31 +256,15 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
362
256
|
}
|
|
363
257
|
enumerate() {
|
|
364
258
|
return __awaiter(this, void 0, void 0, function* () {
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
try {
|
|
371
|
-
for (const path of this.identityProbeCleanupPaths) {
|
|
372
|
-
try {
|
|
373
|
-
yield this.release(path);
|
|
374
|
-
}
|
|
375
|
-
catch (_a) {
|
|
376
|
-
}
|
|
259
|
+
for (const path of this.identityProbeCleanupPaths) {
|
|
260
|
+
try {
|
|
261
|
+
yield this.release(path);
|
|
262
|
+
}
|
|
263
|
+
catch (_a) {
|
|
377
264
|
}
|
|
378
|
-
yield this.getConnectedDevices();
|
|
379
|
-
this.logLifecycle('enumerate', {
|
|
380
|
-
phase: 'success',
|
|
381
|
-
durationMs: Date.now() - startedAt,
|
|
382
|
-
deviceCount: this.deviceList.length,
|
|
383
|
-
});
|
|
384
|
-
return this.deviceList;
|
|
385
|
-
}
|
|
386
|
-
catch (error) {
|
|
387
|
-
this.logLifecycle('enumerate', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(error)));
|
|
388
|
-
throw error;
|
|
389
265
|
}
|
|
266
|
+
yield this.getConnectedDevices();
|
|
267
|
+
return this.deviceList;
|
|
390
268
|
});
|
|
391
269
|
}
|
|
392
270
|
getConnectedDevices() {
|
|
@@ -395,21 +273,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
395
273
|
this.assertRunning();
|
|
396
274
|
if (!this.usb)
|
|
397
275
|
return [];
|
|
398
|
-
const
|
|
399
|
-
this.logLifecycle('get-devices', { phase: 'start' });
|
|
400
|
-
let devices;
|
|
401
|
-
try {
|
|
402
|
-
devices = yield this.usb.getDevices();
|
|
403
|
-
this.logLifecycle('get-devices', {
|
|
404
|
-
phase: 'success',
|
|
405
|
-
durationMs: Date.now() - startedAt,
|
|
406
|
-
authorizedDeviceCount: devices.length,
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
catch (error) {
|
|
410
|
-
this.logLifecycle('get-devices', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(error)));
|
|
411
|
-
throw error;
|
|
412
|
-
}
|
|
276
|
+
const devices = yield this.usb.getDevices();
|
|
413
277
|
this.assertRunning();
|
|
414
278
|
for (const owner of new Set(devices.map(device => normalHandleOwners.get(device)))) {
|
|
415
279
|
if (owner === null || owner === void 0 ? void 0 : owner.stopped) {
|
|
@@ -446,34 +310,22 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
446
310
|
});
|
|
447
311
|
}
|
|
448
312
|
acquire(input) {
|
|
449
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
313
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
450
314
|
return __awaiter(this, void 0, void 0, function* () {
|
|
451
315
|
this.assertRunning();
|
|
452
316
|
if (!input.path)
|
|
453
317
|
return;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
hasCachedProtocol: this.deviceProtocol.has(input.path),
|
|
462
|
-
});
|
|
318
|
+
if (this.identityProbe) {
|
|
319
|
+
yield this.getConnectedDevices();
|
|
320
|
+
this.claimIdentityProbeHandle(input.path, yield this.findDevice(input.path));
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
this.claimNormalHandle(input.path, yield this.findDevice(input.path));
|
|
324
|
+
}
|
|
463
325
|
try {
|
|
464
|
-
if (this.identityProbe) {
|
|
465
|
-
yield this.getConnectedDevices();
|
|
466
|
-
this.claimIdentityProbeHandle(input.path, yield this.findDevice(input.path));
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
this.claimNormalHandle(input.path, yield this.findDevice(input.path));
|
|
470
|
-
}
|
|
471
326
|
yield this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
|
|
472
327
|
yield this.closeOpenDevice(input.path);
|
|
473
|
-
yield this.connect((
|
|
474
|
-
expectedProtocol: input.expectedProtocol,
|
|
475
|
-
forceProtocolDetection: input.forceProtocolDetection,
|
|
476
|
-
});
|
|
328
|
+
yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
|
|
477
329
|
if (input.skipProtocolProbe) {
|
|
478
330
|
if (!input.expectedProtocol) {
|
|
479
331
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires an expected protocol');
|
|
@@ -483,7 +335,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
483
335
|
}
|
|
484
336
|
this.staleProtocolPaths.delete(input.path);
|
|
485
337
|
this.deviceProtocol.set(input.path, input.expectedProtocol);
|
|
486
|
-
const currentDevice = (
|
|
338
|
+
const currentDevice = (_b = this.deviceList.find(d => d.path === input.path)) === null || _b === void 0 ? void 0 : _b.device;
|
|
487
339
|
if (currentDevice) {
|
|
488
340
|
this.probedDeviceObjects.set(input.path, currentDevice);
|
|
489
341
|
}
|
|
@@ -498,7 +350,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
498
350
|
this.deviceProtocol.delete(input.path);
|
|
499
351
|
}
|
|
500
352
|
if (!input.skipProtocolProbe && this.deviceProtocol.has(input.path)) {
|
|
501
|
-
const currentDevice = (
|
|
353
|
+
const currentDevice = (_c = this.deviceList.find(d => d.path === input.path)) === null || _c === void 0 ? void 0 : _c.device;
|
|
502
354
|
if (!currentDevice || currentDevice !== this.probedDeviceObjects.get(input.path)) {
|
|
503
355
|
this.deviceProtocol.delete(input.path);
|
|
504
356
|
}
|
|
@@ -511,32 +363,26 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
511
363
|
this.deviceProtocol.delete(input.path);
|
|
512
364
|
}
|
|
513
365
|
if (!this.deviceProtocol.has(input.path)) {
|
|
514
|
-
const usbDevice = (
|
|
366
|
+
const usbDevice = (_d = this.deviceList.find(device => device.path === input.path)) === null || _d === void 0 ? void 0 : _d.device;
|
|
515
367
|
const protocolHint = input.expectedProtocol
|
|
516
368
|
? undefined
|
|
517
|
-
: (
|
|
369
|
+
: (_f = (_e = input.protocolHint) !== null && _e !== void 0 ? _e : this.deviceProtocolHints.get(input.path)) !== null && _f !== void 0 ? _f : hdShared.inferProtocolHintFromUsbId(usbDevice === null || usbDevice === void 0 ? void 0 : usbDevice.vendorId, usbDevice === null || usbDevice === void 0 ? void 0 : usbDevice.productId);
|
|
518
370
|
if (protocolHint) {
|
|
519
371
|
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
520
372
|
}
|
|
521
373
|
const detectedProtocol = yield this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
|
|
522
374
|
this.assertRunning();
|
|
523
375
|
this.confirmedDeviceProtocols.set(input.path, detectedProtocol);
|
|
524
|
-
const probedDevice = (
|
|
376
|
+
const probedDevice = (_g = this.deviceList.find(d => d.path === input.path)) === null || _g === void 0 ? void 0 : _g.device;
|
|
525
377
|
if (probedDevice) {
|
|
526
378
|
this.probedDeviceObjects.set(input.path, probedDevice);
|
|
527
379
|
}
|
|
528
380
|
}
|
|
529
381
|
this.assertRunning();
|
|
530
382
|
this.acquiredPaths.add(input.path);
|
|
531
|
-
this.logLifecycle('acquire', {
|
|
532
|
-
phase: 'success',
|
|
533
|
-
durationMs: Date.now() - startedAt,
|
|
534
|
-
protocol: (_k = this.deviceProtocol.get(input.path)) !== null && _k !== void 0 ? _k : null,
|
|
535
|
-
});
|
|
536
383
|
return yield Promise.resolve(input.path);
|
|
537
384
|
}
|
|
538
385
|
catch (e) {
|
|
539
|
-
this.logLifecycle('acquire', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(e, input.path)));
|
|
540
386
|
this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
|
|
541
387
|
this.acquiredPaths.delete(input.path);
|
|
542
388
|
try {
|
|
@@ -626,48 +472,20 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
626
472
|
return device.device;
|
|
627
473
|
});
|
|
628
474
|
}
|
|
629
|
-
connect(path, first
|
|
475
|
+
connect(path, first) {
|
|
630
476
|
return __awaiter(this, void 0, void 0, function* () {
|
|
631
477
|
const maxRetries = 5;
|
|
632
478
|
for (let i = 0; i < maxRetries; i++) {
|
|
633
479
|
this.assertRunning();
|
|
634
|
-
const attempt = i + 1;
|
|
635
|
-
const startedAt = Date.now();
|
|
636
|
-
const connectionStrategy = this.shouldUseLegacyV1Connection(path, options)
|
|
637
|
-
? 'protocol-v1-legacy-1.1.31'
|
|
638
|
-
: 'current';
|
|
639
|
-
this.logLifecycle('connect-attempt', {
|
|
640
|
-
phase: 'start',
|
|
641
|
-
attempt,
|
|
642
|
-
maxAttempts: maxRetries,
|
|
643
|
-
first,
|
|
644
|
-
connectionStrategy,
|
|
645
|
-
});
|
|
646
480
|
try {
|
|
647
|
-
|
|
648
|
-
this.logLifecycle('connect-attempt', {
|
|
649
|
-
phase: 'success',
|
|
650
|
-
attempt,
|
|
651
|
-
maxAttempts: maxRetries,
|
|
652
|
-
first,
|
|
653
|
-
connectionStrategy,
|
|
654
|
-
durationMs: Date.now() - startedAt,
|
|
655
|
-
});
|
|
656
|
-
return result;
|
|
481
|
+
return yield this.connectToDevice(path, first);
|
|
657
482
|
}
|
|
658
483
|
catch (e) {
|
|
659
484
|
this.assertRunning();
|
|
660
|
-
|
|
661
|
-
(e instanceof hdShared.HardwareError &&
|
|
662
|
-
(e.errorCode === hdShared.HardwareErrorCode.BridgeNeedsPermission ||
|
|
663
|
-
e.errorCode === hdShared.HardwareErrorCode.WebUsbDeviceAccessError));
|
|
664
|
-
const willRetry = !isTerminalError && attempt < maxRetries;
|
|
665
|
-
this.logLifecycle('connect-attempt', Object.assign({ phase: 'error', attempt, maxAttempts: maxRetries, first,
|
|
666
|
-
connectionStrategy, durationMs: Date.now() - startedAt, willRetry }, this.getDiagnosticError(e, path)));
|
|
667
|
-
if (isTerminalError) {
|
|
485
|
+
if (e instanceof hdShared.HardwareError && e.errorCode === hdShared.HardwareErrorCode.BridgeNeedsPermission) {
|
|
668
486
|
throw e;
|
|
669
487
|
}
|
|
670
|
-
if (
|
|
488
|
+
if (i === maxRetries - 1) {
|
|
671
489
|
throw e;
|
|
672
490
|
}
|
|
673
491
|
yield hdShared.wait(i * 200);
|
|
@@ -675,11 +493,6 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
675
493
|
}
|
|
676
494
|
});
|
|
677
495
|
}
|
|
678
|
-
shouldUseLegacyV1Connection(path, options) {
|
|
679
|
-
if (options.expectedProtocol)
|
|
680
|
-
return options.expectedProtocol === 'V1';
|
|
681
|
-
return !options.forceProtocolDetection && this.deviceProtocol.get(path) === 'V1';
|
|
682
|
-
}
|
|
683
496
|
discoverEndpoints(device) {
|
|
684
497
|
var _a, _b;
|
|
685
498
|
for (const config of device.configurations) {
|
|
@@ -708,7 +521,8 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
708
521
|
endpointOut: this.endpointId,
|
|
709
522
|
};
|
|
710
523
|
}
|
|
711
|
-
connectToDevice(path, first
|
|
524
|
+
connectToDevice(path, first) {
|
|
525
|
+
var _a;
|
|
712
526
|
return __awaiter(this, void 0, void 0, function* () {
|
|
713
527
|
this.assertRunning();
|
|
714
528
|
let device = yield this.findDevice(path);
|
|
@@ -723,12 +537,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
723
537
|
if (!device.opened) {
|
|
724
538
|
openingHandles.add(device);
|
|
725
539
|
try {
|
|
726
|
-
yield this.
|
|
727
|
-
operation: 'open',
|
|
728
|
-
device,
|
|
729
|
-
path,
|
|
730
|
-
task: () => device.open(),
|
|
731
|
-
});
|
|
540
|
+
yield this.runHandleOperation(() => device.open());
|
|
732
541
|
}
|
|
733
542
|
catch (error) {
|
|
734
543
|
return yield this.throwWebUsbIoError(path, 'open', error);
|
|
@@ -737,42 +546,13 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
737
546
|
openingHandles.delete(device);
|
|
738
547
|
}
|
|
739
548
|
}
|
|
740
|
-
if (this.shouldUseLegacyV1Connection(path, options)) {
|
|
741
|
-
if (first) {
|
|
742
|
-
yield this.runLoggedHandleOperation({
|
|
743
|
-
operation: 'selectConfiguration',
|
|
744
|
-
device,
|
|
745
|
-
path,
|
|
746
|
-
task: () => device.selectConfiguration(this.configurationId),
|
|
747
|
-
});
|
|
748
|
-
try {
|
|
749
|
-
yield this.runLoggedHandleOperation({
|
|
750
|
-
operation: 'reset',
|
|
751
|
-
device,
|
|
752
|
-
path,
|
|
753
|
-
task: () => device.reset(),
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
catch (_a) {
|
|
757
|
-
this.assertRunning();
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
const legacyEndpoints = this.discoverEndpoints(device);
|
|
761
|
-
this.deviceEndpoints.set(path, legacyEndpoints);
|
|
762
|
-
yield this.claimDeviceInterface(path, device, legacyEndpoints);
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
549
|
if (first || this.deviceProtocol.get(path) !== 'V1') {
|
|
766
550
|
try {
|
|
767
|
-
yield this.
|
|
768
|
-
operation: 'reset',
|
|
769
|
-
device,
|
|
770
|
-
path,
|
|
771
|
-
task: () => device.reset(),
|
|
772
|
-
});
|
|
551
|
+
yield this.runHandleOperation(() => device.reset());
|
|
773
552
|
}
|
|
774
|
-
catch (
|
|
553
|
+
catch (error) {
|
|
775
554
|
this.assertRunning();
|
|
555
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] reset before claim failed, continuing:', error);
|
|
776
556
|
}
|
|
777
557
|
}
|
|
778
558
|
yield this.getConnectedDevices();
|
|
@@ -788,12 +568,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
788
568
|
if (!device.opened) {
|
|
789
569
|
openingHandles.add(device);
|
|
790
570
|
try {
|
|
791
|
-
yield this.
|
|
792
|
-
operation: 'open',
|
|
793
|
-
device,
|
|
794
|
-
path,
|
|
795
|
-
task: () => device.open(),
|
|
796
|
-
});
|
|
571
|
+
yield this.runHandleOperation(() => device.open());
|
|
797
572
|
}
|
|
798
573
|
catch (error) {
|
|
799
574
|
return yield this.throwWebUsbIoError(path, 'open', error);
|
|
@@ -805,34 +580,18 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
805
580
|
if (first ||
|
|
806
581
|
!device.configuration ||
|
|
807
582
|
device.configuration.configurationValue !== this.configurationId) {
|
|
808
|
-
yield this.
|
|
809
|
-
operation: 'selectConfiguration',
|
|
810
|
-
device,
|
|
811
|
-
path,
|
|
812
|
-
task: () => device.selectConfiguration(this.configurationId),
|
|
813
|
-
});
|
|
583
|
+
yield this.runHandleOperation(() => device.selectConfiguration(this.configurationId));
|
|
814
584
|
}
|
|
815
585
|
const endpoints = this.discoverEndpoints(device);
|
|
816
586
|
this.deviceEndpoints.set(path, endpoints);
|
|
817
|
-
yield this.claimDeviceInterface(path, device, endpoints);
|
|
818
|
-
yield this.clearEndpointHalt(path, device, 'in', endpoints.endpointIn);
|
|
819
|
-
yield this.clearEndpointHalt(path, device, 'out', endpoints.endpointOut);
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
claimDeviceInterface(path, device, endpoints) {
|
|
823
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
824
587
|
try {
|
|
825
|
-
yield this.
|
|
826
|
-
operation: 'claimInterface',
|
|
827
|
-
device,
|
|
828
|
-
path,
|
|
829
|
-
interfaceNumber: endpoints.interfaceNumber,
|
|
830
|
-
task: () => device.claimInterface(endpoints.interfaceNumber),
|
|
831
|
-
});
|
|
588
|
+
yield this.runHandleOperation(() => device.claimInterface(endpoints.interfaceNumber));
|
|
832
589
|
}
|
|
833
590
|
catch (error) {
|
|
834
591
|
return this.throwWebUsbIoError(path, 'claimInterface', error);
|
|
835
592
|
}
|
|
593
|
+
yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
|
|
594
|
+
yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
|
|
836
595
|
});
|
|
837
596
|
}
|
|
838
597
|
assertHandleAvailable(device) {
|
|
@@ -853,7 +612,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
853
612
|
if (this.stopped)
|
|
854
613
|
return;
|
|
855
614
|
for (const [device, ownedPath] of this.normalDevices) {
|
|
856
|
-
if (ownedPath === path
|
|
615
|
+
if (ownedPath === path) {
|
|
857
616
|
normalHandleOwners.delete(device);
|
|
858
617
|
this.normalDevices.delete(device);
|
|
859
618
|
}
|
|
@@ -889,82 +648,41 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
889
648
|
this.identityProbeCleanupPaths.delete(path);
|
|
890
649
|
}
|
|
891
650
|
closeOpenDevice(path) {
|
|
651
|
+
var _a, _b, _c, _d;
|
|
892
652
|
return __awaiter(this, void 0, void 0, function* () {
|
|
893
653
|
if (this.stopped)
|
|
894
654
|
return;
|
|
895
|
-
const
|
|
896
|
-
?
|
|
897
|
-
:
|
|
898
|
-
|
|
899
|
-
.map(([device]) => device);
|
|
900
|
-
let firstCloseError;
|
|
901
|
-
for (const device of devices) {
|
|
902
|
-
try {
|
|
903
|
-
yield this.closeDeviceHandle(path, device);
|
|
904
|
-
}
|
|
905
|
-
catch (error) {
|
|
906
|
-
firstCloseError !== null && firstCloseError !== void 0 ? firstCloseError : (firstCloseError = error);
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
if (firstCloseError) {
|
|
910
|
-
throw firstCloseError instanceof Error
|
|
911
|
-
? firstCloseError
|
|
912
|
-
: new Error(this.getErrorMessage(firstCloseError));
|
|
913
|
-
}
|
|
914
|
-
});
|
|
915
|
-
}
|
|
916
|
-
closeDeviceHandle(path, current) {
|
|
917
|
-
var _a, _b, _c;
|
|
918
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
919
|
-
if (!current.opened)
|
|
655
|
+
const current = this.identityProbe
|
|
656
|
+
? this.identityProbeDevices.get(path)
|
|
657
|
+
: (_a = this.deviceList.find(device => device.path === path)) === null || _a === void 0 ? void 0 : _a.device;
|
|
658
|
+
if (!(current === null || current === void 0 ? void 0 : current.opened))
|
|
920
659
|
return;
|
|
921
660
|
this.assertHandleAvailable(current);
|
|
922
661
|
const endpoints = this.deviceEndpoints.get(path);
|
|
923
|
-
const ifaceNum = (
|
|
924
|
-
|
|
925
|
-
this.
|
|
662
|
+
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
663
|
+
try {
|
|
664
|
+
yield this.runHandleOperation(() => current.releaseInterface(ifaceNum));
|
|
926
665
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
yield this.runLoggedHandleOperation({
|
|
930
|
-
operation: 'releaseInterface',
|
|
931
|
-
device: current,
|
|
932
|
-
path,
|
|
933
|
-
interfaceNumber: ifaceNum,
|
|
934
|
-
task: () => current.releaseInterface(ifaceNum),
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
catch (error) {
|
|
938
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
939
|
-
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
940
668
|
}
|
|
941
669
|
this.assertHandleAvailable(current);
|
|
942
670
|
try {
|
|
943
|
-
yield this.
|
|
944
|
-
operation: 'close',
|
|
945
|
-
device: current,
|
|
946
|
-
path,
|
|
947
|
-
task: () => current.close(),
|
|
948
|
-
});
|
|
671
|
+
yield this.runHandleOperation(() => current.close());
|
|
949
672
|
}
|
|
950
673
|
catch (error) {
|
|
951
|
-
(
|
|
952
|
-
|
|
674
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[WebUsbTransport] close before reconnect failed:', error);
|
|
675
|
+
if (this.identityProbe)
|
|
676
|
+
throw error;
|
|
953
677
|
}
|
|
954
678
|
});
|
|
955
679
|
}
|
|
956
|
-
clearEndpointHalt(
|
|
680
|
+
clearEndpointHalt(device, direction, endpointNumber) {
|
|
957
681
|
var _a;
|
|
958
682
|
return __awaiter(this, void 0, void 0, function* () {
|
|
959
683
|
this.assertHandleAvailable(device);
|
|
960
684
|
try {
|
|
961
|
-
yield this.
|
|
962
|
-
operation: direction === 'in' ? 'clearHaltIn' : 'clearHaltOut',
|
|
963
|
-
device,
|
|
964
|
-
path,
|
|
965
|
-
endpointNumber,
|
|
966
|
-
task: () => device.clearHalt(direction, endpointNumber),
|
|
967
|
-
});
|
|
685
|
+
yield this.runHandleOperation(() => device.clearHalt(direction, endpointNumber));
|
|
968
686
|
}
|
|
969
687
|
catch (error) {
|
|
970
688
|
this.assertRunning();
|
|
@@ -1093,30 +811,14 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
1093
811
|
if (currentDevice.opened) {
|
|
1094
812
|
const endpoints = this.deviceEndpoints.get(path);
|
|
1095
813
|
const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
|
|
1096
|
-
|
|
1097
|
-
this.
|
|
814
|
+
try {
|
|
815
|
+
yield this.runHandleOperation(() => currentDevice.releaseInterface(ifaceNum));
|
|
1098
816
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
yield this.runLoggedHandleOperation({
|
|
1102
|
-
operation: 'releaseInterface',
|
|
1103
|
-
device: currentDevice,
|
|
1104
|
-
path,
|
|
1105
|
-
interfaceNumber: ifaceNum,
|
|
1106
|
-
task: () => currentDevice.releaseInterface(ifaceNum),
|
|
1107
|
-
});
|
|
1108
|
-
}
|
|
1109
|
-
catch (releaseError) {
|
|
1110
|
-
this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
|
|
1111
|
-
}
|
|
817
|
+
catch (releaseError) {
|
|
818
|
+
this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
|
|
1112
819
|
}
|
|
1113
820
|
this.assertHandleAvailable(currentDevice);
|
|
1114
|
-
yield this.
|
|
1115
|
-
operation: 'close',
|
|
1116
|
-
device: currentDevice,
|
|
1117
|
-
path,
|
|
1118
|
-
task: () => currentDevice.close(),
|
|
1119
|
-
});
|
|
821
|
+
yield this.runHandleOperation(() => currentDevice.close());
|
|
1120
822
|
}
|
|
1121
823
|
}
|
|
1122
824
|
catch (closeError) {
|
|
@@ -1427,20 +1129,10 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
1427
1129
|
}
|
|
1428
1130
|
release(path) {
|
|
1429
1131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1430
|
-
const startedAt = Date.now();
|
|
1431
|
-
this.logLifecycle('release', { phase: 'start' });
|
|
1432
1132
|
this.acquiredPaths.delete(path);
|
|
1433
1133
|
try {
|
|
1434
1134
|
yield this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
|
|
1435
1135
|
yield this.closeOpenDevice(path);
|
|
1436
|
-
this.logLifecycle('release', {
|
|
1437
|
-
phase: 'success',
|
|
1438
|
-
durationMs: Date.now() - startedAt,
|
|
1439
|
-
});
|
|
1440
|
-
}
|
|
1441
|
-
catch (error) {
|
|
1442
|
-
this.logLifecycle('release', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(error, path)));
|
|
1443
|
-
throw error;
|
|
1444
1136
|
}
|
|
1445
1137
|
finally {
|
|
1446
1138
|
this.releaseIdentityProbeHandle(path);
|