@trezor/connect 9.3.1-beta.1 → 9.3.1-beta.2
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/CHANGELOG.md +88 -30
- package/README.md +1 -1
- package/lib/api/ethereum/api/ethereumSignTypedData.js +3 -1
- package/lib/core/index.js +72 -107
- package/lib/data/version.d.ts +2 -1
- package/lib/data/version.js +3 -2
- package/lib/device/Device.d.ts +1 -0
- package/lib/device/Device.js +8 -3
- package/lib/device/DeviceCommands.js +1 -1
- package/lib/device/DeviceList.d.ts +42 -27
- package/lib/device/DeviceList.js +249 -233
- package/lib/events/popup.d.ts +1 -0
- package/lib/utils/promiseUtils.d.ts +3 -3
- package/lib/utils/promiseUtils.js +7 -5
- package/package.json +14 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypedEmitter } from '@trezor/utils';
|
|
2
|
-
import { Transport, TRANSPORT
|
|
2
|
+
import { Transport, TRANSPORT } from '@trezor/transport';
|
|
3
3
|
import { DEVICE, TransportInfo } from '../events';
|
|
4
4
|
import { Device } from './Device';
|
|
5
5
|
import type { ConnectSettings, Device as DeviceTyped } from '../types';
|
|
@@ -13,28 +13,44 @@ interface DeviceListEvents {
|
|
|
13
13
|
[DEVICE.RELEASED]: DeviceTyped;
|
|
14
14
|
[DEVICE.ACQUIRED]: DeviceTyped;
|
|
15
15
|
}
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
16
|
+
export interface IDeviceList {
|
|
17
|
+
isConnected(): this is DeviceList;
|
|
18
|
+
assertConnected(): asserts this is DeviceList;
|
|
19
|
+
pendingConnection(): Promise<void> | undefined;
|
|
20
|
+
setTransports: DeviceList['setTransports'];
|
|
21
|
+
addAuthPenalty: DeviceList['addAuthPenalty'];
|
|
22
|
+
removeAuthPenalty: DeviceList['removeAuthPenalty'];
|
|
23
|
+
on: DeviceList['on'];
|
|
24
|
+
once: DeviceList['once'];
|
|
25
|
+
init: DeviceList['init'];
|
|
26
|
+
dispose: DeviceList['dispose'];
|
|
27
|
+
}
|
|
28
|
+
type ConstructorParams = Pick<ConnectSettings, 'priority' | 'debug'> & {
|
|
29
|
+
messages: Record<string, any>;
|
|
30
|
+
};
|
|
31
|
+
type InitParams = Pick<ConnectSettings, 'pendingTransportEvent' | 'transportReconnect'>;
|
|
32
|
+
export declare class DeviceList extends TypedEmitter<DeviceListEvents> implements IDeviceList {
|
|
33
|
+
private transport;
|
|
34
|
+
private transports;
|
|
35
|
+
private devices;
|
|
36
|
+
private creatingDevicesDescriptors;
|
|
37
|
+
private readonly authPenaltyManager;
|
|
38
|
+
private initPromise?;
|
|
39
|
+
private rejectPending?;
|
|
40
|
+
private transportCommonArgs;
|
|
41
|
+
isConnected(): this is DeviceList;
|
|
42
|
+
assertConnected(): asserts this is DeviceList;
|
|
43
|
+
pendingConnection(): Promise<void> | undefined;
|
|
44
|
+
constructor({ messages, priority, debug }: ConstructorParams);
|
|
45
|
+
private createTransport;
|
|
46
|
+
setTransports(transports: ConnectSettings['transports']): void;
|
|
47
|
+
private onTransportUpdate;
|
|
48
|
+
init(initParams?: InitParams): Promise<void>;
|
|
49
|
+
private createInitPromise;
|
|
50
|
+
private createReconnectPromise;
|
|
51
|
+
private selectTransport;
|
|
52
|
+
private initializeTransport;
|
|
53
|
+
private waitForDevices;
|
|
38
54
|
private _createAndSaveDevice;
|
|
39
55
|
private _createUnacquiredDevice;
|
|
40
56
|
private _createUnreadableDevice;
|
|
@@ -45,11 +61,10 @@ export declare class DeviceList extends TypedEmitter<DeviceListEvents> {
|
|
|
45
61
|
length(): number;
|
|
46
62
|
transportType(): "BridgeTransport" | "NodeUsbTransport" | "WebUsbTransport" | "UdpTransport";
|
|
47
63
|
getTransportInfo(): TransportInfo;
|
|
48
|
-
dispose(): void
|
|
49
|
-
|
|
50
|
-
enumerate(): Promise<void>;
|
|
64
|
+
dispose(): Promise<void>;
|
|
65
|
+
cleanup(): Promise<void>;
|
|
66
|
+
enumerate(transport?: Transport): Promise<void>;
|
|
51
67
|
addAuthPenalty(device: Device): void;
|
|
52
|
-
private getAuthPenalty;
|
|
53
68
|
removeAuthPenalty(device: Device): void;
|
|
54
69
|
private handle;
|
|
55
70
|
private _takeAndCreateDevice;
|
package/lib/device/DeviceList.js
CHANGED
|
@@ -10,239 +10,264 @@ const transportInfo_1 = require("../data/transportInfo");
|
|
|
10
10
|
const debug_1 = require("../utils/debug");
|
|
11
11
|
const promiseUtils_1 = require("../utils/promiseUtils");
|
|
12
12
|
const _log = (0, debug_1.initLog)('DeviceList');
|
|
13
|
-
|
|
13
|
+
const createAuthPenaltyManager = (priority) => {
|
|
14
|
+
const penalizedDevices = {};
|
|
15
|
+
const get = () => 100 * priority +
|
|
16
|
+
Object.keys(penalizedDevices).reduce((penalty, key) => Math.max(penalty, penalizedDevices[key]), 0);
|
|
17
|
+
const add = (device) => {
|
|
18
|
+
if (!device.isInitialized() || device.isBootloader() || !device.features.device_id)
|
|
19
|
+
return;
|
|
20
|
+
const deviceID = device.features.device_id;
|
|
21
|
+
const penalty = penalizedDevices[deviceID] ? penalizedDevices[deviceID] + 500 : 2000;
|
|
22
|
+
penalizedDevices[deviceID] = Math.min(penalty, 5000);
|
|
23
|
+
};
|
|
24
|
+
const remove = (device) => {
|
|
25
|
+
if (!device.isInitialized() || device.isBootloader() || !device.features.device_id)
|
|
26
|
+
return;
|
|
27
|
+
const deviceID = device.features.device_id;
|
|
28
|
+
delete penalizedDevices[deviceID];
|
|
29
|
+
};
|
|
30
|
+
const clear = () => Object.keys(penalizedDevices).forEach(key => delete penalizedDevices[key]);
|
|
31
|
+
return { get, add, remove, clear };
|
|
32
|
+
};
|
|
14
33
|
class DeviceList extends utils_1.TypedEmitter {
|
|
15
|
-
|
|
34
|
+
isConnected() {
|
|
35
|
+
return !!this.transport;
|
|
36
|
+
}
|
|
37
|
+
assertConnected() {
|
|
38
|
+
if (!this.transport)
|
|
39
|
+
throw constants_1.ERRORS.TypedError('Transport_Missing');
|
|
40
|
+
}
|
|
41
|
+
pendingConnection() {
|
|
42
|
+
return this.initPromise;
|
|
43
|
+
}
|
|
44
|
+
constructor({ messages, priority, debug }) {
|
|
16
45
|
super();
|
|
17
|
-
this.transports = [];
|
|
18
46
|
this.devices = {};
|
|
19
47
|
this.creatingDevicesDescriptors = {};
|
|
20
|
-
|
|
21
|
-
this.penalizedDevices = {};
|
|
22
|
-
this.settings = settings;
|
|
23
|
-
const transports = [...(settings.transports || [])];
|
|
24
|
-
if (!transports.length) {
|
|
25
|
-
transports.push('BridgeTransport');
|
|
26
|
-
}
|
|
27
|
-
const transportLogger = (0, debug_1.initLog)('@trezor/transport', this.settings.debug);
|
|
48
|
+
const transportLogger = (0, debug_1.initLog)('@trezor/transport', debug);
|
|
28
49
|
const abortController = new AbortController();
|
|
29
|
-
|
|
50
|
+
this.authPenaltyManager = createAuthPenaltyManager(priority);
|
|
51
|
+
this.transportCommonArgs = {
|
|
30
52
|
messages,
|
|
31
53
|
logger: transportLogger,
|
|
32
54
|
signal: abortController.signal,
|
|
33
55
|
};
|
|
34
|
-
transports
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
this.transports = [
|
|
57
|
+
new transport_1.BridgeTransport({
|
|
58
|
+
latestVersion: (0, transportInfo_1.getBridgeInfo)().version.join('.'),
|
|
59
|
+
...this.transportCommonArgs,
|
|
60
|
+
}),
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
createTransport(transportType) {
|
|
64
|
+
const { transportCommonArgs } = this;
|
|
65
|
+
if (typeof transportType === 'string') {
|
|
66
|
+
switch (transportType) {
|
|
67
|
+
case 'WebUsbTransport':
|
|
68
|
+
return new transport_1.WebUsbTransport(transportCommonArgs);
|
|
69
|
+
case 'NodeUsbTransport':
|
|
70
|
+
return new transport_1.NodeUsbTransport(transportCommonArgs);
|
|
71
|
+
case 'BridgeTransport':
|
|
72
|
+
return new transport_1.BridgeTransport({
|
|
73
|
+
latestVersion: (0, transportInfo_1.getBridgeInfo)().version.join('.'),
|
|
74
|
+
...transportCommonArgs,
|
|
75
|
+
});
|
|
76
|
+
case 'UdpTransport':
|
|
77
|
+
return new transport_1.UdpTransport(transportCommonArgs);
|
|
55
78
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
}
|
|
80
|
+
else if (typeof transportType === 'function' && 'prototype' in transportType) {
|
|
81
|
+
const transportInstance = new transportType(transportCommonArgs);
|
|
82
|
+
if ((0, transport_1.isTransportInstance)(transportInstance)) {
|
|
83
|
+
return transportInstance;
|
|
61
84
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.transports.push(transportType);
|
|
85
|
+
}
|
|
86
|
+
else if ((0, transport_1.isTransportInstance)(transportType)) {
|
|
87
|
+
if (!transportType.getMessage()) {
|
|
88
|
+
transportType.updateMessages(transportCommonArgs.messages);
|
|
67
89
|
}
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
return transportType;
|
|
91
|
+
}
|
|
92
|
+
throw constants_1.ERRORS.TypedError('Runtime', `DeviceList.init: transports[] of unexpected type: ${transportType}`);
|
|
93
|
+
}
|
|
94
|
+
setTransports(transports) {
|
|
95
|
+
const transportTypes = (transports === null || transports === void 0 ? void 0 : transports.length) ? transports : ['BridgeTransport'];
|
|
96
|
+
this.transports = transportTypes.map(this.createTransport.bind(this));
|
|
97
|
+
}
|
|
98
|
+
onTransportUpdate(diff, transport) {
|
|
99
|
+
diff.disconnected.forEach(descriptor => {
|
|
100
|
+
const path = descriptor.path.toString();
|
|
101
|
+
const device = this.devices[path];
|
|
102
|
+
if (device) {
|
|
103
|
+
device.disconnect();
|
|
104
|
+
delete this.devices[path];
|
|
105
|
+
this.emit(events_1.DEVICE.DISCONNECT, device.toMessageObject());
|
|
70
106
|
}
|
|
71
107
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.transport = transport;
|
|
79
|
-
const result = await this.transport.init().promise;
|
|
80
|
-
if (result.success) {
|
|
81
|
-
lastError = undefined;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
lastError = result.error;
|
|
86
|
-
}
|
|
108
|
+
diff.connected.forEach(async (descriptor) => {
|
|
109
|
+
const path = descriptor.path.toString();
|
|
110
|
+
this.creatingDevicesDescriptors[path] = descriptor;
|
|
111
|
+
const penalty = this.authPenaltyManager.get();
|
|
112
|
+
if (penalty) {
|
|
113
|
+
await (0, promiseUtils_1.resolveAfter)(501 + penalty, null).promise;
|
|
87
114
|
}
|
|
88
|
-
if (
|
|
89
|
-
this.
|
|
90
|
-
return;
|
|
115
|
+
if (this.creatingDevicesDescriptors[path].session == null) {
|
|
116
|
+
await this._createAndSaveDevice(descriptor, transport);
|
|
91
117
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (device) {
|
|
97
|
-
device.disconnect();
|
|
98
|
-
delete this.devices[path];
|
|
99
|
-
this.emit(events_1.DEVICE.DISCONNECT, device.toMessageObject());
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
diff.connected.forEach(async (descriptor) => {
|
|
103
|
-
const path = descriptor.path.toString();
|
|
104
|
-
this.creatingDevicesDescriptors[path] = descriptor;
|
|
105
|
-
const { priority } = this.settings;
|
|
106
|
-
const penalty = this.getAuthPenalty();
|
|
107
|
-
if (priority || penalty) {
|
|
108
|
-
await (0, promiseUtils_1.resolveAfter)(501 + penalty + 100 * priority, null).promise;
|
|
109
|
-
}
|
|
110
|
-
if (this.creatingDevicesDescriptors[path].session == null) {
|
|
111
|
-
await this._createAndSaveDevice(descriptor);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
const device = this._createUnacquiredDevice(descriptor);
|
|
115
|
-
this.devices[path] = device;
|
|
116
|
-
this.emit(events_1.DEVICE.CONNECT_UNACQUIRED, device.toMessageObject());
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
diff.acquiredElsewhere.forEach((descriptor) => {
|
|
120
|
-
const path = descriptor.path.toString();
|
|
121
|
-
const device = this.devices[path];
|
|
122
|
-
if (device) {
|
|
123
|
-
device.featuresNeedsReload = true;
|
|
124
|
-
device.interruptionFromOutside();
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
diff.released.forEach(descriptor => {
|
|
128
|
-
var _a;
|
|
129
|
-
const path = descriptor.path.toString();
|
|
130
|
-
const device = this.devices[path];
|
|
131
|
-
const methodStillRunning = !((_a = device === null || device === void 0 ? void 0 : device.commands) === null || _a === void 0 ? void 0 : _a.disposed);
|
|
132
|
-
if (device && methodStillRunning) {
|
|
133
|
-
device.keepSession = false;
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
diff.releasedElsewhere.forEach(async (descriptor) => {
|
|
137
|
-
const path = descriptor.path.toString();
|
|
138
|
-
const device = this.devices[path];
|
|
139
|
-
await (0, promiseUtils_1.resolveAfter)(1000, null).promise;
|
|
140
|
-
if (device) {
|
|
141
|
-
if (!device.isUsed() && device.isUnacquired() && !device.isInconsistent()) {
|
|
142
|
-
_log.debug('Create device from unacquired', device.toMessageObject());
|
|
143
|
-
await this._createAndSaveDevice(descriptor);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
const events = [
|
|
148
|
-
{
|
|
149
|
-
d: diff.changedSessions,
|
|
150
|
-
e: events_1.DEVICE.CHANGED,
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
d: diff.acquired,
|
|
154
|
-
e: events_1.DEVICE.ACQUIRED,
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
d: diff.released,
|
|
158
|
-
e: events_1.DEVICE.RELEASED,
|
|
159
|
-
},
|
|
160
|
-
];
|
|
161
|
-
events.forEach(({ d, e }) => {
|
|
162
|
-
d.forEach(descriptor => {
|
|
163
|
-
const path = descriptor.path.toString();
|
|
164
|
-
const device = this.devices[path];
|
|
165
|
-
if (device) {
|
|
166
|
-
_log.debug('Event', e, device.toMessageObject());
|
|
167
|
-
this.emit(e, device.toMessageObject());
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
diff.descriptors.forEach(d => {
|
|
172
|
-
this.creatingDevicesDescriptors[d.path] = d;
|
|
173
|
-
if (this.devices[d.path]) {
|
|
174
|
-
this.devices[d.path].originalDescriptor = {
|
|
175
|
-
session: d.session,
|
|
176
|
-
path: d.path,
|
|
177
|
-
product: d.product,
|
|
178
|
-
type: d.type,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
this.transport.on(transport_1.TRANSPORT.ERROR, error => {
|
|
184
|
-
this.emit(transport_1.TRANSPORT.ERROR, error);
|
|
185
|
-
});
|
|
186
|
-
const enumerateResult = await this.transport.enumerate().promise;
|
|
187
|
-
if (!enumerateResult.success) {
|
|
188
|
-
this.emit(transport_1.TRANSPORT.ERROR, enumerateResult.error);
|
|
189
|
-
return;
|
|
118
|
+
else {
|
|
119
|
+
const device = this._createUnacquiredDevice(descriptor, transport);
|
|
120
|
+
this.devices[path] = device;
|
|
121
|
+
this.emit(events_1.DEVICE.CONNECT_UNACQUIRED, device.toMessageObject());
|
|
190
122
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}, 10000);
|
|
123
|
+
});
|
|
124
|
+
diff.acquiredElsewhere.forEach((descriptor) => {
|
|
125
|
+
const path = descriptor.path.toString();
|
|
126
|
+
const device = this.devices[path];
|
|
127
|
+
if (device) {
|
|
128
|
+
device.featuresNeedsReload = true;
|
|
129
|
+
device.interruptionFromOutside();
|
|
199
130
|
}
|
|
200
|
-
|
|
201
|
-
|
|
131
|
+
});
|
|
132
|
+
diff.released.forEach(descriptor => {
|
|
133
|
+
var _a;
|
|
134
|
+
const path = descriptor.path.toString();
|
|
135
|
+
const device = this.devices[path];
|
|
136
|
+
const methodStillRunning = !((_a = device === null || device === void 0 ? void 0 : device.commands) === null || _a === void 0 ? void 0 : _a.isDisposed());
|
|
137
|
+
if (device && methodStillRunning) {
|
|
138
|
+
device.keepSession = false;
|
|
202
139
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
140
|
+
});
|
|
141
|
+
diff.releasedElsewhere.forEach(async (descriptor) => {
|
|
142
|
+
const path = descriptor.path.toString();
|
|
143
|
+
const device = this.devices[path];
|
|
144
|
+
await (0, promiseUtils_1.resolveAfter)(1000, null).promise;
|
|
145
|
+
if (device) {
|
|
146
|
+
if (!device.isUsed() && device.isUnacquired() && !device.isInconsistent()) {
|
|
147
|
+
_log.debug('Create device from unacquired', device.toMessageObject());
|
|
148
|
+
await this._createAndSaveDevice(descriptor, transport);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
const forEachDescriptor = (d, e) => {
|
|
153
|
+
d.forEach(descriptor => {
|
|
154
|
+
const path = descriptor.path.toString();
|
|
155
|
+
const device = this.devices[path];
|
|
156
|
+
if (device) {
|
|
157
|
+
_log.debug('Event', e, device.toMessageObject());
|
|
158
|
+
this.emit(e, device.toMessageObject());
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
forEachDescriptor(diff.changedSessions, events_1.DEVICE.CHANGED);
|
|
163
|
+
forEachDescriptor(diff.acquired, events_1.DEVICE.ACQUIRED);
|
|
164
|
+
forEachDescriptor(diff.released, events_1.DEVICE.RELEASED);
|
|
165
|
+
diff.descriptors.forEach(d => {
|
|
166
|
+
this.creatingDevicesDescriptors[d.path] = d;
|
|
167
|
+
if (this.devices[d.path]) {
|
|
168
|
+
this.devices[d.path].originalDescriptor = {
|
|
169
|
+
session: d.session,
|
|
170
|
+
path: d.path,
|
|
171
|
+
product: d.product,
|
|
172
|
+
type: d.type,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
209
176
|
}
|
|
210
|
-
|
|
211
|
-
this.
|
|
212
|
-
|
|
213
|
-
|
|
177
|
+
init(initParams = {}) {
|
|
178
|
+
if (!this.initPromise) {
|
|
179
|
+
_log.debug('Initializing transports');
|
|
180
|
+
this.initPromise = this.createInitPromise(initParams);
|
|
214
181
|
}
|
|
215
|
-
|
|
182
|
+
return this.initPromise;
|
|
183
|
+
}
|
|
184
|
+
createInitPromise(initParams) {
|
|
185
|
+
return this.selectTransport(this.transports)
|
|
186
|
+
.then(transport => this.initializeTransport(transport, initParams))
|
|
187
|
+
.then(transport => {
|
|
188
|
+
this.transport = transport;
|
|
216
189
|
this.emit(transport_1.TRANSPORT.START, this.getTransportInfo());
|
|
190
|
+
this.initPromise = undefined;
|
|
191
|
+
})
|
|
192
|
+
.catch(error => {
|
|
193
|
+
this.cleanup();
|
|
194
|
+
this.emit(transport_1.TRANSPORT.ERROR, error);
|
|
195
|
+
this.initPromise = initParams.transportReconnect
|
|
196
|
+
? this.createReconnectPromise(initParams)
|
|
197
|
+
: undefined;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
createReconnectPromise(initParams) {
|
|
201
|
+
const { promise, reject } = (0, promiseUtils_1.resolveAfter)(1000, initParams);
|
|
202
|
+
this.rejectPending = reject;
|
|
203
|
+
return promise.then(this.createInitPromise.bind(this));
|
|
204
|
+
}
|
|
205
|
+
async selectTransport([transport, ...rest]) {
|
|
206
|
+
const result = await transport.init().promise;
|
|
207
|
+
if (result.success)
|
|
208
|
+
return transport;
|
|
209
|
+
else if (rest.length)
|
|
210
|
+
return this.selectTransport(rest);
|
|
211
|
+
else
|
|
212
|
+
throw new Error(result.error);
|
|
213
|
+
}
|
|
214
|
+
async initializeTransport(transport, initParams) {
|
|
215
|
+
transport.on(transport_1.TRANSPORT.UPDATE, diff => this.onTransportUpdate(diff, transport));
|
|
216
|
+
transport.on(transport_1.TRANSPORT.ERROR, error => {
|
|
217
|
+
this.cleanup();
|
|
218
|
+
this.emit(transport_1.TRANSPORT.ERROR, error);
|
|
219
|
+
if (initParams.transportReconnect) {
|
|
220
|
+
this.initPromise = this.createReconnectPromise(initParams);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const enumerateResult = await transport.enumerate().promise;
|
|
224
|
+
if (!enumerateResult.success) {
|
|
225
|
+
throw new Error(enumerateResult.error);
|
|
226
|
+
}
|
|
227
|
+
const descriptors = enumerateResult.payload;
|
|
228
|
+
transport.handleDescriptorsChange(descriptors);
|
|
229
|
+
transport.listen();
|
|
230
|
+
const awaitedDevices = descriptors.length - Object.keys(this.devices).length;
|
|
231
|
+
if (awaitedDevices > 0 && initParams.pendingTransportEvent) {
|
|
232
|
+
await this.waitForDevices(awaitedDevices, 10000);
|
|
217
233
|
}
|
|
234
|
+
return transport;
|
|
218
235
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
236
|
+
waitForDevices(deviceCount, autoResolveMs) {
|
|
237
|
+
const { promise, resolve, reject } = (0, utils_1.createDeferred)();
|
|
238
|
+
let transportStartPending = deviceCount;
|
|
239
|
+
const autoResolveTransportEventTimeout = setTimeout(resolve, autoResolveMs);
|
|
240
|
+
this.rejectPending = reject;
|
|
241
|
+
const onDeviceConnect = () => {
|
|
242
|
+
transportStartPending--;
|
|
243
|
+
if (transportStartPending === 0) {
|
|
224
244
|
resolve();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
this.on(events_1.DEVICE.CONNECT, onDeviceConnect);
|
|
248
|
+
this.on(events_1.DEVICE.CONNECT_UNACQUIRED, onDeviceConnect);
|
|
249
|
+
return promise.finally(() => {
|
|
250
|
+
this.rejectPending = undefined;
|
|
251
|
+
clearTimeout(autoResolveTransportEventTimeout);
|
|
252
|
+
this.off(events_1.DEVICE.CONNECT, onDeviceConnect);
|
|
253
|
+
this.off(events_1.DEVICE.CONNECT_UNACQUIRED, onDeviceConnect);
|
|
228
254
|
});
|
|
229
|
-
await this.transportFirstEventPromise;
|
|
230
255
|
}
|
|
231
|
-
async _createAndSaveDevice(descriptor) {
|
|
256
|
+
async _createAndSaveDevice(descriptor, transport) {
|
|
232
257
|
_log.debug('Creating Device', descriptor);
|
|
233
|
-
await this.handle(descriptor);
|
|
258
|
+
await this.handle(descriptor, transport);
|
|
234
259
|
}
|
|
235
|
-
_createUnacquiredDevice(descriptor) {
|
|
260
|
+
_createUnacquiredDevice(descriptor, transport) {
|
|
236
261
|
_log.debug('Creating Unacquired Device', descriptor);
|
|
237
|
-
const device = Device_1.Device.createUnacquired(
|
|
262
|
+
const device = Device_1.Device.createUnacquired(transport, descriptor);
|
|
238
263
|
device.once(events_1.DEVICE.ACQUIRED, () => {
|
|
239
264
|
this.emit(events_1.DEVICE.CONNECT, device.toMessageObject());
|
|
240
265
|
});
|
|
241
266
|
return device;
|
|
242
267
|
}
|
|
243
|
-
_createUnreadableDevice(descriptor, unreadableError) {
|
|
268
|
+
_createUnreadableDevice(descriptor, transport, unreadableError) {
|
|
244
269
|
_log.debug('Creating Unreadable Device', descriptor, unreadableError);
|
|
245
|
-
return Device_1.Device.createUnacquired(
|
|
270
|
+
return Device_1.Device.createUnacquired(transport, descriptor, unreadableError);
|
|
246
271
|
}
|
|
247
272
|
getDevice(path) {
|
|
248
273
|
return this.devices[path];
|
|
@@ -271,20 +296,24 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
271
296
|
}
|
|
272
297
|
dispose() {
|
|
273
298
|
this.removeAllListeners();
|
|
274
|
-
|
|
275
|
-
clearTimeout(autoResolveTransportEventTimeout);
|
|
276
|
-
}
|
|
277
|
-
Promise.all(this.allDevices().map(device => device.dispose())).then(() => {
|
|
278
|
-
this.transport.stop();
|
|
279
|
-
});
|
|
299
|
+
return this.cleanup();
|
|
280
300
|
}
|
|
281
|
-
|
|
282
|
-
|
|
301
|
+
async cleanup() {
|
|
302
|
+
var _a;
|
|
303
|
+
const { transport } = this;
|
|
304
|
+
const devices = this.allDevices();
|
|
305
|
+
this.transport = undefined;
|
|
306
|
+
this.authPenaltyManager.clear();
|
|
307
|
+
Object.keys(this.devices).forEach(key => delete this.devices[key]);
|
|
308
|
+
(_a = this.rejectPending) === null || _a === void 0 ? void 0 : _a.call(this, new Error('Disposed'));
|
|
309
|
+
devices.forEach(device => {
|
|
283
310
|
this.emit(events_1.DEVICE.DISCONNECT, device.toMessageObject());
|
|
284
311
|
});
|
|
312
|
+
await Promise.all(devices.map(device => device.dispose()));
|
|
313
|
+
transport === null || transport === void 0 ? void 0 : transport.stop();
|
|
285
314
|
}
|
|
286
|
-
async enumerate() {
|
|
287
|
-
const res = await
|
|
315
|
+
async enumerate(transport = this.transport) {
|
|
316
|
+
const res = await transport.enumerate().promise;
|
|
288
317
|
if (!res.success) {
|
|
289
318
|
return;
|
|
290
319
|
}
|
|
@@ -301,29 +330,16 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
301
330
|
});
|
|
302
331
|
}
|
|
303
332
|
addAuthPenalty(device) {
|
|
304
|
-
|
|
305
|
-
return;
|
|
306
|
-
const deviceID = device.features.device_id;
|
|
307
|
-
const penalty = this.penalizedDevices[deviceID]
|
|
308
|
-
? this.penalizedDevices[deviceID] + 500
|
|
309
|
-
: 2000;
|
|
310
|
-
this.penalizedDevices[deviceID] = Math.min(penalty, 5000);
|
|
311
|
-
}
|
|
312
|
-
getAuthPenalty() {
|
|
313
|
-
const { penalizedDevices } = this;
|
|
314
|
-
return Object.keys(penalizedDevices).reduce((penalty, key) => Math.max(penalty, penalizedDevices[key]), 0);
|
|
333
|
+
return this.authPenaltyManager.add(device);
|
|
315
334
|
}
|
|
316
335
|
removeAuthPenalty(device) {
|
|
317
|
-
|
|
318
|
-
return;
|
|
319
|
-
const deviceID = device.features.device_id;
|
|
320
|
-
delete this.penalizedDevices[deviceID];
|
|
336
|
+
return this.authPenaltyManager.remove(device);
|
|
321
337
|
}
|
|
322
|
-
async handle(descriptor) {
|
|
338
|
+
async handle(descriptor, transport) {
|
|
323
339
|
var _a;
|
|
324
340
|
const path = descriptor.path.toString();
|
|
325
341
|
try {
|
|
326
|
-
await this._takeAndCreateDevice(descriptor);
|
|
342
|
+
await this._takeAndCreateDevice(descriptor, transport);
|
|
327
343
|
}
|
|
328
344
|
catch (error) {
|
|
329
345
|
_log.debug('Cannot create device', error);
|
|
@@ -336,37 +352,37 @@ class DeviceList extends utils_1.TypedEmitter {
|
|
|
336
352
|
delete this.devices[path];
|
|
337
353
|
}
|
|
338
354
|
else if (error.message === transport_1.TRANSPORT_ERROR.SESSION_WRONG_PREVIOUS) {
|
|
339
|
-
this.enumerate();
|
|
340
|
-
this._handleUsedElsewhere(descriptor);
|
|
355
|
+
this.enumerate(transport);
|
|
356
|
+
this._handleUsedElsewhere(descriptor, transport);
|
|
341
357
|
}
|
|
342
358
|
else if (error.message === transport_1.TRANSPORT_ERROR.INTERFACE_UNABLE_TO_OPEN_DEVICE ||
|
|
343
359
|
((_a = error.message) === null || _a === void 0 ? void 0 : _a.indexOf(constants_1.ERRORS.LIBUSB_ERROR_MESSAGE)) >= 0 ||
|
|
344
360
|
error.code === 'Device_InitializeFailed') {
|
|
345
|
-
const device = this._createUnreadableDevice(this.creatingDevicesDescriptors[path], error.message);
|
|
361
|
+
const device = this._createUnreadableDevice(this.creatingDevicesDescriptors[path], transport, error.message);
|
|
346
362
|
this.devices[path] = device;
|
|
347
363
|
this.emit(events_1.DEVICE.CONNECT_UNACQUIRED, device.toMessageObject());
|
|
348
364
|
}
|
|
349
365
|
else if (error.code === 'Device_UsedElsewhere') {
|
|
350
|
-
this._handleUsedElsewhere(descriptor);
|
|
366
|
+
this._handleUsedElsewhere(descriptor, transport);
|
|
351
367
|
}
|
|
352
368
|
else {
|
|
353
369
|
await (0, promiseUtils_1.resolveAfter)(501, null).promise;
|
|
354
|
-
await this.handle(descriptor);
|
|
370
|
+
await this.handle(descriptor, transport);
|
|
355
371
|
}
|
|
356
372
|
}
|
|
357
373
|
delete this.creatingDevicesDescriptors[path];
|
|
358
374
|
}
|
|
359
|
-
async _takeAndCreateDevice(descriptor) {
|
|
360
|
-
const device = Device_1.Device.fromDescriptor(
|
|
375
|
+
async _takeAndCreateDevice(descriptor, transport) {
|
|
376
|
+
const device = Device_1.Device.fromDescriptor(transport, descriptor);
|
|
361
377
|
const path = descriptor.path.toString();
|
|
362
378
|
this.devices[path] = device;
|
|
363
379
|
const promise = device.run();
|
|
364
380
|
await promise;
|
|
365
381
|
this.emit(events_1.DEVICE.CONNECT, device.toMessageObject());
|
|
366
382
|
}
|
|
367
|
-
_handleUsedElsewhere(descriptor) {
|
|
383
|
+
_handleUsedElsewhere(descriptor, transport) {
|
|
368
384
|
const path = descriptor.path.toString();
|
|
369
|
-
const device = this._createUnacquiredDevice(this.creatingDevicesDescriptors[path]);
|
|
385
|
+
const device = this._createUnacquiredDevice(this.creatingDevicesDescriptors[path], transport);
|
|
370
386
|
this.devices[path] = device;
|
|
371
387
|
this.emit(events_1.DEVICE.CONNECT_UNACQUIRED, device.toMessageObject());
|
|
372
388
|
}
|