@onekeyfe/hd-transport-web-device 1.2.8-alpha.102 → 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-protocol-cache.test.ts +1 -197
- package/dist/index.d.ts +2 -20
- package/dist/index.js +65 -377
- 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 -496
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,46 +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 = {
|
|
761
|
-
interfaceNumber: this.interfaceId,
|
|
762
|
-
endpointIn: this.endpointId,
|
|
763
|
-
endpointOut: this.endpointId,
|
|
764
|
-
};
|
|
765
|
-
this.deviceEndpoints.set(path, legacyEndpoints);
|
|
766
|
-
yield this.claimDeviceInterface(path, device, legacyEndpoints);
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
549
|
if (first || this.deviceProtocol.get(path) !== 'V1') {
|
|
770
550
|
try {
|
|
771
|
-
yield this.
|
|
772
|
-
operation: 'reset',
|
|
773
|
-
device,
|
|
774
|
-
path,
|
|
775
|
-
task: () => device.reset(),
|
|
776
|
-
});
|
|
551
|
+
yield this.runHandleOperation(() => device.reset());
|
|
777
552
|
}
|
|
778
|
-
catch (
|
|
553
|
+
catch (error) {
|
|
779
554
|
this.assertRunning();
|
|
555
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] reset before claim failed, continuing:', error);
|
|
780
556
|
}
|
|
781
557
|
}
|
|
782
558
|
yield this.getConnectedDevices();
|
|
@@ -792,12 +568,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
792
568
|
if (!device.opened) {
|
|
793
569
|
openingHandles.add(device);
|
|
794
570
|
try {
|
|
795
|
-
yield this.
|
|
796
|
-
operation: 'open',
|
|
797
|
-
device,
|
|
798
|
-
path,
|
|
799
|
-
task: () => device.open(),
|
|
800
|
-
});
|
|
571
|
+
yield this.runHandleOperation(() => device.open());
|
|
801
572
|
}
|
|
802
573
|
catch (error) {
|
|
803
574
|
return yield this.throwWebUsbIoError(path, 'open', error);
|
|
@@ -809,34 +580,18 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
809
580
|
if (first ||
|
|
810
581
|
!device.configuration ||
|
|
811
582
|
device.configuration.configurationValue !== this.configurationId) {
|
|
812
|
-
yield this.
|
|
813
|
-
operation: 'selectConfiguration',
|
|
814
|
-
device,
|
|
815
|
-
path,
|
|
816
|
-
task: () => device.selectConfiguration(this.configurationId),
|
|
817
|
-
});
|
|
583
|
+
yield this.runHandleOperation(() => device.selectConfiguration(this.configurationId));
|
|
818
584
|
}
|
|
819
585
|
const endpoints = this.discoverEndpoints(device);
|
|
820
586
|
this.deviceEndpoints.set(path, endpoints);
|
|
821
|
-
yield this.claimDeviceInterface(path, device, endpoints);
|
|
822
|
-
yield this.clearEndpointHalt(path, device, 'in', endpoints.endpointIn);
|
|
823
|
-
yield this.clearEndpointHalt(path, device, 'out', endpoints.endpointOut);
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
claimDeviceInterface(path, device, endpoints) {
|
|
827
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
828
587
|
try {
|
|
829
|
-
yield this.
|
|
830
|
-
operation: 'claimInterface',
|
|
831
|
-
device,
|
|
832
|
-
path,
|
|
833
|
-
interfaceNumber: endpoints.interfaceNumber,
|
|
834
|
-
task: () => device.claimInterface(endpoints.interfaceNumber),
|
|
835
|
-
});
|
|
588
|
+
yield this.runHandleOperation(() => device.claimInterface(endpoints.interfaceNumber));
|
|
836
589
|
}
|
|
837
590
|
catch (error) {
|
|
838
591
|
return this.throwWebUsbIoError(path, 'claimInterface', error);
|
|
839
592
|
}
|
|
593
|
+
yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
|
|
594
|
+
yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
|
|
840
595
|
});
|
|
841
596
|
}
|
|
842
597
|
assertHandleAvailable(device) {
|
|
@@ -857,7 +612,7 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
857
612
|
if (this.stopped)
|
|
858
613
|
return;
|
|
859
614
|
for (const [device, ownedPath] of this.normalDevices) {
|
|
860
|
-
if (ownedPath === path
|
|
615
|
+
if (ownedPath === path) {
|
|
861
616
|
normalHandleOwners.delete(device);
|
|
862
617
|
this.normalDevices.delete(device);
|
|
863
618
|
}
|
|
@@ -893,82 +648,41 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
893
648
|
this.identityProbeCleanupPaths.delete(path);
|
|
894
649
|
}
|
|
895
650
|
closeOpenDevice(path) {
|
|
651
|
+
var _a, _b, _c, _d;
|
|
896
652
|
return __awaiter(this, void 0, void 0, function* () {
|
|
897
653
|
if (this.stopped)
|
|
898
654
|
return;
|
|
899
|
-
const
|
|
900
|
-
?
|
|
901
|
-
:
|
|
902
|
-
|
|
903
|
-
.map(([device]) => device);
|
|
904
|
-
let firstCloseError;
|
|
905
|
-
for (const device of devices) {
|
|
906
|
-
try {
|
|
907
|
-
yield this.closeDeviceHandle(path, device);
|
|
908
|
-
}
|
|
909
|
-
catch (error) {
|
|
910
|
-
firstCloseError !== null && firstCloseError !== void 0 ? firstCloseError : (firstCloseError = error);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
if (firstCloseError) {
|
|
914
|
-
throw firstCloseError instanceof Error
|
|
915
|
-
? firstCloseError
|
|
916
|
-
: new Error(this.getErrorMessage(firstCloseError));
|
|
917
|
-
}
|
|
918
|
-
});
|
|
919
|
-
}
|
|
920
|
-
closeDeviceHandle(path, current) {
|
|
921
|
-
var _a, _b, _c;
|
|
922
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
923
|
-
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))
|
|
924
659
|
return;
|
|
925
660
|
this.assertHandleAvailable(current);
|
|
926
661
|
const endpoints = this.deviceEndpoints.get(path);
|
|
927
|
-
const ifaceNum = (
|
|
928
|
-
|
|
929
|
-
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));
|
|
930
665
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
yield this.runLoggedHandleOperation({
|
|
934
|
-
operation: 'releaseInterface',
|
|
935
|
-
device: current,
|
|
936
|
-
path,
|
|
937
|
-
interfaceNumber: ifaceNum,
|
|
938
|
-
task: () => current.releaseInterface(ifaceNum),
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
catch (error) {
|
|
942
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
943
|
-
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
944
668
|
}
|
|
945
669
|
this.assertHandleAvailable(current);
|
|
946
670
|
try {
|
|
947
|
-
yield this.
|
|
948
|
-
operation: 'close',
|
|
949
|
-
device: current,
|
|
950
|
-
path,
|
|
951
|
-
task: () => current.close(),
|
|
952
|
-
});
|
|
671
|
+
yield this.runHandleOperation(() => current.close());
|
|
953
672
|
}
|
|
954
673
|
catch (error) {
|
|
955
|
-
(
|
|
956
|
-
|
|
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;
|
|
957
677
|
}
|
|
958
678
|
});
|
|
959
679
|
}
|
|
960
|
-
clearEndpointHalt(
|
|
680
|
+
clearEndpointHalt(device, direction, endpointNumber) {
|
|
961
681
|
var _a;
|
|
962
682
|
return __awaiter(this, void 0, void 0, function* () {
|
|
963
683
|
this.assertHandleAvailable(device);
|
|
964
684
|
try {
|
|
965
|
-
yield this.
|
|
966
|
-
operation: direction === 'in' ? 'clearHaltIn' : 'clearHaltOut',
|
|
967
|
-
device,
|
|
968
|
-
path,
|
|
969
|
-
endpointNumber,
|
|
970
|
-
task: () => device.clearHalt(direction, endpointNumber),
|
|
971
|
-
});
|
|
685
|
+
yield this.runHandleOperation(() => device.clearHalt(direction, endpointNumber));
|
|
972
686
|
}
|
|
973
687
|
catch (error) {
|
|
974
688
|
this.assertRunning();
|
|
@@ -1097,30 +811,14 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
1097
811
|
if (currentDevice.opened) {
|
|
1098
812
|
const endpoints = this.deviceEndpoints.get(path);
|
|
1099
813
|
const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
|
|
1100
|
-
|
|
1101
|
-
this.
|
|
814
|
+
try {
|
|
815
|
+
yield this.runHandleOperation(() => currentDevice.releaseInterface(ifaceNum));
|
|
1102
816
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
yield this.runLoggedHandleOperation({
|
|
1106
|
-
operation: 'releaseInterface',
|
|
1107
|
-
device: currentDevice,
|
|
1108
|
-
path,
|
|
1109
|
-
interfaceNumber: ifaceNum,
|
|
1110
|
-
task: () => currentDevice.releaseInterface(ifaceNum),
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
catch (releaseError) {
|
|
1114
|
-
this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
|
|
1115
|
-
}
|
|
817
|
+
catch (releaseError) {
|
|
818
|
+
this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
|
|
1116
819
|
}
|
|
1117
820
|
this.assertHandleAvailable(currentDevice);
|
|
1118
|
-
yield this.
|
|
1119
|
-
operation: 'close',
|
|
1120
|
-
device: currentDevice,
|
|
1121
|
-
path,
|
|
1122
|
-
task: () => currentDevice.close(),
|
|
1123
|
-
});
|
|
821
|
+
yield this.runHandleOperation(() => currentDevice.close());
|
|
1124
822
|
}
|
|
1125
823
|
}
|
|
1126
824
|
catch (closeError) {
|
|
@@ -1431,20 +1129,10 @@ class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
|
1431
1129
|
}
|
|
1432
1130
|
release(path) {
|
|
1433
1131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1434
|
-
const startedAt = Date.now();
|
|
1435
|
-
this.logLifecycle('release', { phase: 'start' });
|
|
1436
1132
|
this.acquiredPaths.delete(path);
|
|
1437
1133
|
try {
|
|
1438
1134
|
yield this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
|
|
1439
1135
|
yield this.closeOpenDevice(path);
|
|
1440
|
-
this.logLifecycle('release', {
|
|
1441
|
-
phase: 'success',
|
|
1442
|
-
durationMs: Date.now() - startedAt,
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
catch (error) {
|
|
1446
|
-
this.logLifecycle('release', Object.assign({ phase: 'error', durationMs: Date.now() - startedAt }, this.getDiagnosticError(error, path)));
|
|
1447
|
-
throw error;
|
|
1448
1136
|
}
|
|
1449
1137
|
finally {
|
|
1450
1138
|
this.releaseIdentityProbeHandle(path);
|