@onekeyfe/hd-core 1.2.2-alpha.112 → 1.2.2-alpha.114
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__/core-error-output.test.ts +77 -0
- package/__tests__/device-lifecycle-events.test.ts +8 -8
- package/__tests__/search-devices.test.ts +131 -8
- package/dist/api/SearchDevices.d.ts +2 -15
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts +2 -0
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/index.js +131 -38
- package/package.json +4 -4
- package/src/api/SearchDevices.ts +86 -27
- package/src/core/index.ts +58 -19
- package/src/data-manager/TransportManager.ts +14 -3
|
@@ -4,6 +4,8 @@ import { initConnector, initCore } from '../src/core';
|
|
|
4
4
|
import { DataManager } from '../src/data-manager';
|
|
5
5
|
import TransportManager from '../src/data-manager/TransportManager';
|
|
6
6
|
import { IFRAME } from '../src/events';
|
|
7
|
+
import SearchDevices from '../src/api/SearchDevices';
|
|
8
|
+
import { DeviceList } from '../src/device/DeviceList';
|
|
7
9
|
|
|
8
10
|
jest.mock('../src/data/config', () => ({
|
|
9
11
|
getSDKVersion: jest.fn(() => '1.0.0-test'),
|
|
@@ -24,6 +26,81 @@ describe('Core 错误输出边界', () => {
|
|
|
24
26
|
jest.restoreAllMocks();
|
|
25
27
|
});
|
|
26
28
|
|
|
29
|
+
test.each([
|
|
30
|
+
['webusb', false],
|
|
31
|
+
['desktop-webusb', false],
|
|
32
|
+
['desktop-webusb', true],
|
|
33
|
+
] as const)(
|
|
34
|
+
'%s waits for discovery without masking initialization or cancellation (cancel=%s)',
|
|
35
|
+
async (env, shouldCancel) => {
|
|
36
|
+
jest.spyOn(DataManager, 'getSettings').mockReturnValue(env as never);
|
|
37
|
+
const error = ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed, 'probe failed');
|
|
38
|
+
let finishSearch!: () => void;
|
|
39
|
+
let searchStarted!: () => void;
|
|
40
|
+
const started = new Promise<void>(resolve => {
|
|
41
|
+
searchStarted = resolve;
|
|
42
|
+
});
|
|
43
|
+
const search = jest.spyOn(SearchDevices.prototype, 'run').mockImplementation(async () => {
|
|
44
|
+
searchStarted();
|
|
45
|
+
await new Promise<void>(resolve => {
|
|
46
|
+
finishSearch = resolve;
|
|
47
|
+
});
|
|
48
|
+
return [];
|
|
49
|
+
});
|
|
50
|
+
const initialize = jest
|
|
51
|
+
.spyOn(DeviceList.prototype, 'getDeviceLists')
|
|
52
|
+
.mockRejectedValue(error);
|
|
53
|
+
const core = initCore();
|
|
54
|
+
initConnector();
|
|
55
|
+
try {
|
|
56
|
+
const discovery = core.handleMessage({
|
|
57
|
+
id: 10,
|
|
58
|
+
type: IFRAME.CALL,
|
|
59
|
+
payload: { method: 'searchDevices' },
|
|
60
|
+
} as never);
|
|
61
|
+
await started;
|
|
62
|
+
const request = core.handleMessage({
|
|
63
|
+
id: 11,
|
|
64
|
+
type: IFRAME.CALL,
|
|
65
|
+
payload: {
|
|
66
|
+
method: 'getDeviceState',
|
|
67
|
+
connectId: 'serial-V2',
|
|
68
|
+
retryCount: 1,
|
|
69
|
+
pollIntervalTime: 1,
|
|
70
|
+
timeout: 1000,
|
|
71
|
+
},
|
|
72
|
+
} as never);
|
|
73
|
+
await new Promise(resolve => {
|
|
74
|
+
setTimeout(resolve, 0);
|
|
75
|
+
});
|
|
76
|
+
expect(initialize).not.toHaveBeenCalled();
|
|
77
|
+
if (shouldCancel) {
|
|
78
|
+
await core.handleMessage({
|
|
79
|
+
type: IFRAME.CANCEL,
|
|
80
|
+
payload: { connectId: 'serial-V2' },
|
|
81
|
+
} as never);
|
|
82
|
+
}
|
|
83
|
+
finishSearch();
|
|
84
|
+
await expect(discovery).resolves.toMatchObject({ success: true });
|
|
85
|
+
const expectedError = shouldCancel
|
|
86
|
+
? ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled)
|
|
87
|
+
: error;
|
|
88
|
+
await expect(request).resolves.toMatchObject({
|
|
89
|
+
success: false,
|
|
90
|
+
payload: { code: expectedError.errorCode, error: expectedError.message },
|
|
91
|
+
});
|
|
92
|
+
await new Promise(resolve => {
|
|
93
|
+
setTimeout(resolve, 0);
|
|
94
|
+
});
|
|
95
|
+
expect(search).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(initialize).toHaveBeenCalledTimes(shouldCancel ? 0 : 2);
|
|
97
|
+
} finally {
|
|
98
|
+
finishSearch?.();
|
|
99
|
+
await core.dispose();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
27
104
|
test.each([
|
|
28
105
|
HardwareErrorCode.BleDeviceNotBonded,
|
|
29
106
|
HardwareErrorCode.BleDeviceBondedCanceled,
|
|
@@ -362,12 +362,12 @@ describe('public device lifecycle events', () => {
|
|
|
362
362
|
}
|
|
363
363
|
);
|
|
364
364
|
|
|
365
|
-
test('
|
|
365
|
+
test('clears the cleanup barrier when its deadline expires', async () => {
|
|
366
366
|
const realSetTimeout = setTimeout;
|
|
367
367
|
jest
|
|
368
368
|
.spyOn(global, 'setTimeout')
|
|
369
369
|
.mockImplementation((callback, delay, ...args) =>
|
|
370
|
-
realSetTimeout(callback, delay ===
|
|
370
|
+
realSetTimeout(callback, delay === 5_000 ? 0 : delay, ...args)
|
|
371
371
|
);
|
|
372
372
|
{
|
|
373
373
|
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
@@ -382,13 +382,13 @@ describe('public device lifecycle events', () => {
|
|
|
382
382
|
type: IFRAME.CALL,
|
|
383
383
|
payload: { method: 'getDeviceState', connectId: 'draining-device', connectProtocol: 'V2' },
|
|
384
384
|
} as CoreMessage);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
payload: { code: HardwareErrorCode.DeviceBusy },
|
|
388
|
-
});
|
|
389
|
-
expect(acquire).not.toHaveBeenCalled();
|
|
390
|
-
expect(context.getPrePendingCallPromise('draining-device')).toBe(gate.promise);
|
|
385
|
+
setImmediate(() => cancel(context, 'draining-device'));
|
|
386
|
+
await expect(result).resolves.toBeDefined();
|
|
391
387
|
gate.resolve();
|
|
388
|
+
await new Promise(resolve => {
|
|
389
|
+
setImmediate(resolve);
|
|
390
|
+
});
|
|
391
|
+
expect(context.getPrePendingCallPromise('draining-device')).toBeUndefined();
|
|
392
392
|
}
|
|
393
393
|
});
|
|
394
394
|
|
|
@@ -4,6 +4,7 @@ jest.mock('../src/data-manager/TransportManager', () => ({
|
|
|
4
4
|
__esModule: true,
|
|
5
5
|
default: {
|
|
6
6
|
configure: jest.fn(),
|
|
7
|
+
ensureInitialized: jest.fn(),
|
|
7
8
|
},
|
|
8
9
|
}));
|
|
9
10
|
|
|
@@ -17,29 +18,151 @@ jest.mock('../src/data-manager', () => ({
|
|
|
17
18
|
jest.mock('../src/device/DevicePool', () => ({
|
|
18
19
|
DevicePool: {
|
|
19
20
|
getDevices: jest.fn(),
|
|
21
|
+
getDeviceByPath: jest.fn(),
|
|
20
22
|
},
|
|
21
23
|
}));
|
|
22
24
|
|
|
23
|
-
const transportManagerMock: {
|
|
24
|
-
|
|
25
|
-
);
|
|
26
|
-
const devicePoolMock: {
|
|
27
|
-
|
|
28
|
-
);
|
|
25
|
+
const transportManagerMock: {
|
|
26
|
+
default: { configure: jest.Mock; ensureInitialized: jest.Mock };
|
|
27
|
+
} = jest.requireMock('../src/data-manager/TransportManager');
|
|
28
|
+
const devicePoolMock: {
|
|
29
|
+
DevicePool: { getDevices: jest.Mock; getDeviceByPath: jest.Mock };
|
|
30
|
+
} = jest.requireMock('../src/device/DevicePool');
|
|
29
31
|
const dataManagerMock: {
|
|
30
32
|
DataManager: {
|
|
31
33
|
getSettings: jest.Mock;
|
|
32
34
|
isBleConnect: jest.Mock;
|
|
33
35
|
};
|
|
34
36
|
} = jest.requireMock('../src/data-manager');
|
|
35
|
-
const { configure: mockConfigureTransport } =
|
|
36
|
-
|
|
37
|
+
const { configure: mockConfigureTransport, ensureInitialized: mockEnsureInitialized } =
|
|
38
|
+
transportManagerMock.default;
|
|
39
|
+
const { getDevices: mockGetDevices, getDeviceByPath: mockGetDeviceByPath } =
|
|
40
|
+
devicePoolMock.DevicePool;
|
|
37
41
|
const { isBleConnect: mockIsBleConnect } = dataManagerMock.DataManager;
|
|
38
42
|
|
|
39
43
|
describe('SearchDevices', () => {
|
|
40
44
|
beforeEach(() => {
|
|
41
45
|
jest.clearAllMocks();
|
|
42
46
|
mockIsBleConnect.mockReturnValue(false);
|
|
47
|
+
dataManagerMock.DataManager.getSettings.mockReturnValue('webusb');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test.each(['webusb', 'desktop-webusb'])(
|
|
51
|
+
'%s discovery leaves active V1/V2 requests and their schemas untouched',
|
|
52
|
+
async env => {
|
|
53
|
+
dataManagerMock.DataManager.getSettings.mockReturnValue(env);
|
|
54
|
+
const devices = ['V1', 'V2'].map(protocol => ({
|
|
55
|
+
features: { protocol },
|
|
56
|
+
toMessageObject: () => ({ connectId: `serial-${protocol}` }),
|
|
57
|
+
}));
|
|
58
|
+
mockGetDeviceByPath.mockImplementation(
|
|
59
|
+
(path: string) => devices[['usb-V1', 'usb-V2'].indexOf(path)]
|
|
60
|
+
);
|
|
61
|
+
const extraDevice = {
|
|
62
|
+
toMessageObject: () => ({ connectId: 'not-initialized' }),
|
|
63
|
+
};
|
|
64
|
+
mockGetDevices.mockResolvedValue({
|
|
65
|
+
devices: { 'not-initialized': extraDevice },
|
|
66
|
+
deviceList: [extraDevice],
|
|
67
|
+
});
|
|
68
|
+
const method = new SearchDevices({
|
|
69
|
+
id: 1,
|
|
70
|
+
payload: { method: 'searchDevices' },
|
|
71
|
+
} as never);
|
|
72
|
+
method.init();
|
|
73
|
+
method.context = {
|
|
74
|
+
requestQueue: {
|
|
75
|
+
getRequestTasksId: () => [2],
|
|
76
|
+
getRequestTasksIdByConnectId: (connectId: string) =>
|
|
77
|
+
connectId === 'usb-V1' || connectId === 'usb-V2' ? [2] : [],
|
|
78
|
+
},
|
|
79
|
+
} as never;
|
|
80
|
+
method.connector = {
|
|
81
|
+
enumerate: jest.fn().mockResolvedValue({
|
|
82
|
+
descriptors: [
|
|
83
|
+
{ path: 'usb-V1', commType: 'webusb' },
|
|
84
|
+
{ path: 'usb-V2', commType: 'webusb' },
|
|
85
|
+
{ path: 'not-initialized', commType: 'webusb' },
|
|
86
|
+
],
|
|
87
|
+
}),
|
|
88
|
+
} as never;
|
|
89
|
+
|
|
90
|
+
await expect(method.run()).resolves.toEqual([
|
|
91
|
+
{ connectId: 'serial-V1' },
|
|
92
|
+
{ connectId: 'serial-V2' },
|
|
93
|
+
{ connectId: 'not-initialized' },
|
|
94
|
+
]);
|
|
95
|
+
expect(mockGetDevices).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(mockGetDevices).toHaveBeenCalledWith(
|
|
97
|
+
[{ path: 'not-initialized', commType: 'webusb' }],
|
|
98
|
+
'not-initialized',
|
|
99
|
+
{
|
|
100
|
+
connectProtocol: undefined,
|
|
101
|
+
forceProtocolDetection: true,
|
|
102
|
+
refreshRuntimeState: true,
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
expect(mockConfigureTransport).not.toHaveBeenCalled();
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
test('owned WebUSB cache miss still reports a SearchDevice without probing', async () => {
|
|
110
|
+
mockGetDeviceByPath.mockReturnValue(undefined);
|
|
111
|
+
const usbDevice = { vendorId: 0x1209, productId: 0x4f4c };
|
|
112
|
+
const method = new SearchDevices({
|
|
113
|
+
id: 1,
|
|
114
|
+
payload: { method: 'searchDevices' },
|
|
115
|
+
} as never);
|
|
116
|
+
method.init();
|
|
117
|
+
method.context = {
|
|
118
|
+
requestQueue: {
|
|
119
|
+
getRequestTasksId: () => [2],
|
|
120
|
+
getRequestTasksIdByConnectId: (connectId: string) => (connectId === 'serial-V2' ? [2] : []),
|
|
121
|
+
},
|
|
122
|
+
} as never;
|
|
123
|
+
method.connector = {
|
|
124
|
+
enumerate: jest.fn().mockResolvedValue({
|
|
125
|
+
descriptors: [
|
|
126
|
+
{
|
|
127
|
+
path: 'serial-V2',
|
|
128
|
+
device: usbDevice,
|
|
129
|
+
commType: 'webusb',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
}),
|
|
133
|
+
} as never;
|
|
134
|
+
|
|
135
|
+
await expect(method.run()).resolves.toEqual([
|
|
136
|
+
{
|
|
137
|
+
connectId: 'serial-V2',
|
|
138
|
+
uuid: 'serial-V2',
|
|
139
|
+
serialNo: 'serial-V2',
|
|
140
|
+
deviceId: null,
|
|
141
|
+
deviceType: 'unknown',
|
|
142
|
+
name: 'serial-V2',
|
|
143
|
+
commType: 'webusb',
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
expect(mockGetDevices).not.toHaveBeenCalled();
|
|
147
|
+
expect(mockConfigureTransport).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('searchDevices resolves empty when WebUSB bring-up is unavailable', async () => {
|
|
151
|
+
mockEnsureInitialized.mockRejectedValueOnce(
|
|
152
|
+
new Error('WebUSB is not supported by current browsers')
|
|
153
|
+
);
|
|
154
|
+
const method = new SearchDevices({
|
|
155
|
+
id: 1,
|
|
156
|
+
payload: { method: 'searchDevices' },
|
|
157
|
+
} as never);
|
|
158
|
+
method.init();
|
|
159
|
+
method.connector = {
|
|
160
|
+
enumerate: jest.fn().mockResolvedValue({ descriptors: [] }),
|
|
161
|
+
} as never;
|
|
162
|
+
|
|
163
|
+
await expect(method.run()).resolves.toEqual([]);
|
|
164
|
+
expect(mockEnsureInitialized).toHaveBeenCalled();
|
|
165
|
+
expect(mockConfigureTransport).toHaveBeenCalledTimes(1);
|
|
43
166
|
});
|
|
44
167
|
|
|
45
168
|
test('搜索忽略调用方协议并主动探测,单个无响应设备不阻断后续结果', async () => {
|
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
import { BaseMethod } from './BaseMethod';
|
|
2
|
+
import type { SearchDevice } from '../types/device';
|
|
2
3
|
import type DeviceConnector from '../device/DeviceConnector';
|
|
3
4
|
export default class SearchDevices extends BaseMethod {
|
|
4
5
|
connector?: DeviceConnector;
|
|
5
6
|
init(): void;
|
|
6
|
-
run(): Promise<
|
|
7
|
-
connectId: string;
|
|
8
|
-
serialNo: null;
|
|
9
|
-
uuid: string;
|
|
10
|
-
deviceId: null;
|
|
11
|
-
name: string | null;
|
|
12
|
-
deviceType: import("..").IDeviceType;
|
|
13
|
-
commType: import("packages/hd-transport/dist").OneKeyDeviceCommType;
|
|
14
|
-
path: string;
|
|
15
|
-
session?: string | null | undefined;
|
|
16
|
-
debugSession?: string | null | undefined;
|
|
17
|
-
debug: boolean;
|
|
18
|
-
id: string;
|
|
19
|
-
protocolType?: import("packages/hd-transport/dist").ProtocolType | undefined;
|
|
20
|
-
}[]>;
|
|
7
|
+
run(): Promise<SearchDevice[]>;
|
|
21
8
|
}
|
|
22
9
|
//# sourceMappingURL=SearchDevices.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchDevices.d.ts","sourceRoot":"","sources":["../../src/api/SearchDevices.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,KAAK,eAAe,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"SearchDevices.d.ts","sourceRoot":"","sources":["../../src/api/SearchDevices.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,eAAe,MAAM,2BAA2B,CAAC;AAuC7D,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,UAAU;IACnD,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,IAAI;IAME,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;CAsFrC"}
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAEL,KAAK,6BAA6B,EAElC,KAAK,YAAY,EAIlB,MAAM,wBAAwB,CAAC;AAiChC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAYpD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AA0E7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,EAEL,KAAK,6BAA6B,EAElC,KAAK,YAAY,EAIlB,MAAM,wBAAwB,CAAC;AAiChC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAYpD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AA0E7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBA0FvE,CAAC;AA2FF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3F;AAunBD,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAWpF;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAoB/E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAQlF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,WAEzD;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,WAI3D;AAiKD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAMtF;AA2MD,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SA4G9D,CAAC;AA8GF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAiLF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,sBAAsB,CAAoC;IAElE,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IAuChB,aAAa,CAAC,OAAO,EAAE,WAAW;IAuExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAiBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
|
|
@@ -6,9 +6,11 @@ export default class TransportManager {
|
|
|
6
6
|
static defaultMessages: JSON | Record<string, any>;
|
|
7
7
|
static currentMessages: JSON | Record<string, any>;
|
|
8
8
|
static reactNativeInit: boolean;
|
|
9
|
+
static webUsbInit: boolean;
|
|
9
10
|
static protocolV1MessageSchema: ProtocolV1MessageSchema;
|
|
10
11
|
static plugin: LowlevelTransportSharedPlugin | null;
|
|
11
12
|
static load(): void;
|
|
13
|
+
static ensureInitialized(): Promise<void>;
|
|
12
14
|
static configure(): Promise<void>;
|
|
13
15
|
static reconfigure(features?: Features): Promise<void>;
|
|
14
16
|
static setTransport(TransportConstructor: any, plugin?: LowlevelTransportSharedPlugin): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransportManager.d.ts","sourceRoot":"","sources":["../../src/data-manager/TransportManager.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,KAAK,EAAE,6BAA6B,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAgBzC,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC;IAE5B,MAAM,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEnD,MAAM,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEnD,MAAM,CAAC,eAAe,UAAS;IAE/B,MAAM,CAAC,uBAAuB,EAAE,uBAAuB,CAAqB;IAE5E,MAAM,CAAC,MAAM,EAAE,6BAA6B,GAAG,IAAI,CAAQ;IAE3D,MAAM,CAAC,IAAI;
|
|
1
|
+
{"version":3,"file":"TransportManager.d.ts","sourceRoot":"","sources":["../../src/data-manager/TransportManager.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,KAAK,EAAE,6BAA6B,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAgBzC,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC;IAE5B,MAAM,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEnD,MAAM,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEnD,MAAM,CAAC,eAAe,UAAS;IAE/B,MAAM,CAAC,UAAU,UAAS;IAE1B,MAAM,CAAC,uBAAuB,EAAE,uBAAuB,CAAqB;IAE5E,MAAM,CAAC,MAAM,EAAE,6BAA6B,GAAG,IAAI,CAAQ;IAE3D,MAAM,CAAC,IAAI;WAQE,iBAAiB;WAUjB,SAAS;WAmDT,WAAW,CAAC,QAAQ,CAAC,EAAE,QAAQ;IAyB5C,MAAM,CAAC,YAAY,CAAC,oBAAoB,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,6BAA6B;IA6BrF,MAAM,CAAC,YAAY;mBAIE,2BAA2B;IAShD,MAAM,CAAC,kBAAkB;IAIzB,MAAM,CAAC,kBAAkB;IAIzB,MAAM,CAAC,0BAA0B;CAGlC"}
|
package/dist/index.js
CHANGED
|
@@ -43705,6 +43705,18 @@ class TransportManager {
|
|
|
43705
43705
|
this.defaultMessages = DataManager.getProtobufMessages();
|
|
43706
43706
|
this.currentMessages = this.defaultMessages;
|
|
43707
43707
|
this.protocolV1MessageSchema = 'v1CurrentSchema';
|
|
43708
|
+
this.webUsbInit = false;
|
|
43709
|
+
}
|
|
43710
|
+
static ensureInitialized() {
|
|
43711
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43712
|
+
const env = DataManager.getSettings('env');
|
|
43713
|
+
if (env !== 'webusb' && env !== 'desktop-webusb')
|
|
43714
|
+
return;
|
|
43715
|
+
if (this.webUsbInit)
|
|
43716
|
+
return;
|
|
43717
|
+
yield this.transport.init(WebUsbLogger, DevicePool.emitter);
|
|
43718
|
+
this.webUsbInit = true;
|
|
43719
|
+
});
|
|
43708
43720
|
}
|
|
43709
43721
|
static configure() {
|
|
43710
43722
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -43733,7 +43745,7 @@ class TransportManager {
|
|
|
43733
43745
|
yield this.transport.init(WebBleLogger, DevicePool.emitter);
|
|
43734
43746
|
}
|
|
43735
43747
|
else if (env === 'webusb' || env === 'desktop-webusb') {
|
|
43736
|
-
yield this.
|
|
43748
|
+
yield this.ensureInitialized();
|
|
43737
43749
|
}
|
|
43738
43750
|
else {
|
|
43739
43751
|
yield this.transport.init(HttpLogger);
|
|
@@ -43816,6 +43828,7 @@ class TransportManager {
|
|
|
43816
43828
|
}
|
|
43817
43829
|
}
|
|
43818
43830
|
TransportManager.reactNativeInit = false;
|
|
43831
|
+
TransportManager.webUsbInit = false;
|
|
43819
43832
|
TransportManager.protocolV1MessageSchema = 'v1CurrentSchema';
|
|
43820
43833
|
TransportManager.plugin = null;
|
|
43821
43834
|
|
|
@@ -47263,6 +47276,28 @@ class PreInitialize extends BaseMethod {
|
|
|
47263
47276
|
}
|
|
47264
47277
|
|
|
47265
47278
|
const Log$e = getLogger(exports.LoggerNames.DevicePool);
|
|
47279
|
+
const isOwnedByActiveWebUsbRequest = (descriptor, requestQueue) => {
|
|
47280
|
+
if (!requestQueue)
|
|
47281
|
+
return false;
|
|
47282
|
+
const keys = [descriptor.path, descriptor.id].filter((key) => typeof key === 'string' && key.length > 0);
|
|
47283
|
+
return keys.some(key => requestQueue.getRequestTasksIdByConnectId(key).length > 0);
|
|
47284
|
+
};
|
|
47285
|
+
const toSearchDeviceFromDescriptor = (descriptor) => {
|
|
47286
|
+
const connectId = descriptor.path || descriptor.id || null;
|
|
47287
|
+
return {
|
|
47288
|
+
connectId,
|
|
47289
|
+
uuid: connectId !== null && connectId !== void 0 ? connectId : '',
|
|
47290
|
+
serialNo: connectId,
|
|
47291
|
+
deviceId: null,
|
|
47292
|
+
deviceType: hdShared.EDeviceType.Unknown,
|
|
47293
|
+
name: descriptor.name || connectId || '',
|
|
47294
|
+
commType: descriptor.commType,
|
|
47295
|
+
};
|
|
47296
|
+
};
|
|
47297
|
+
const toSearchDevice = (device) => {
|
|
47298
|
+
const message = device.toMessageObject();
|
|
47299
|
+
return message ? message : null;
|
|
47300
|
+
};
|
|
47266
47301
|
class SearchDevices extends BaseMethod {
|
|
47267
47302
|
init() {
|
|
47268
47303
|
this.useDevice = false;
|
|
@@ -47270,20 +47305,32 @@ class SearchDevices extends BaseMethod {
|
|
|
47270
47305
|
this.skipForceUpdateCheck = true;
|
|
47271
47306
|
}
|
|
47272
47307
|
run() {
|
|
47273
|
-
var _a, _b, _c, _d, _e;
|
|
47308
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
47274
47309
|
return __awaiter(this, void 0, void 0, function* () {
|
|
47275
|
-
yield TransportManager.configure();
|
|
47276
|
-
const deviceDiff = yield ((_a = this.connector) === null || _a === void 0 ? void 0 : _a.enumerate());
|
|
47277
|
-
const devicesDescriptor = (_b = deviceDiff === null || deviceDiff === void 0 ? void 0 : deviceDiff.descriptors) !== null && _b !== void 0 ? _b : [];
|
|
47278
47310
|
const env = DataManager.getSettings('env');
|
|
47311
|
+
const isWebUsb = env === 'webusb' || env === 'desktop-webusb';
|
|
47312
|
+
const requestQueue = (_a = this.context) === null || _a === void 0 ? void 0 : _a.requestQueue;
|
|
47313
|
+
const hasActiveWebUsbRequest = isWebUsb && ((_b = requestQueue === null || requestQueue === void 0 ? void 0 : requestQueue.getRequestTasksId().length) !== null && _b !== void 0 ? _b : 0) > 0;
|
|
47314
|
+
if (isWebUsb) {
|
|
47315
|
+
try {
|
|
47316
|
+
yield TransportManager.ensureInitialized();
|
|
47317
|
+
}
|
|
47318
|
+
catch (error) {
|
|
47319
|
+
Log$e.debug('WebUSB bring-up unavailable', error);
|
|
47320
|
+
}
|
|
47321
|
+
}
|
|
47322
|
+
if (!hasActiveWebUsbRequest)
|
|
47323
|
+
yield TransportManager.configure();
|
|
47324
|
+
const deviceDiff = yield ((_c = this.connector) === null || _c === void 0 ? void 0 : _c.enumerate());
|
|
47325
|
+
const devicesDescriptor = (_d = deviceDiff === null || deviceDiff === void 0 ? void 0 : deviceDiff.descriptors) !== null && _d !== void 0 ? _d : [];
|
|
47279
47326
|
if (DataManager.isBleConnect(env)) {
|
|
47280
47327
|
const devices = [];
|
|
47281
47328
|
const seenIds = new Set();
|
|
47282
47329
|
for (const device of devicesDescriptor) {
|
|
47283
|
-
const lowerId = (
|
|
47330
|
+
const lowerId = (_e = device.id) === null || _e === void 0 ? void 0 : _e.toLowerCase();
|
|
47284
47331
|
if (!seenIds.has(lowerId)) {
|
|
47285
47332
|
seenIds.add(lowerId);
|
|
47286
|
-
const rawBleName = (
|
|
47333
|
+
const rawBleName = (_g = (_f = device.name) !== null && _f !== void 0 ? _f : device.localName) !== null && _g !== void 0 ? _g : '';
|
|
47287
47334
|
const bleName = hdShared.canonicalizePro2BleAdvertisementName(rawBleName);
|
|
47288
47335
|
devices.push(Object.assign(Object.assign({}, device), { connectId: device.id, serialNo: null, uuid: '', deviceId: null, name: bleName || device.name, deviceType: getDeviceTypeByBleName(bleName) }));
|
|
47289
47336
|
}
|
|
@@ -47292,22 +47339,33 @@ class SearchDevices extends BaseMethod {
|
|
|
47292
47339
|
}
|
|
47293
47340
|
const deviceList = [];
|
|
47294
47341
|
for (const descriptor of devicesDescriptor) {
|
|
47295
|
-
|
|
47296
|
-
const
|
|
47297
|
-
|
|
47298
|
-
|
|
47299
|
-
refreshRuntimeState: true,
|
|
47300
|
-
});
|
|
47301
|
-
deviceList.push(...result.deviceList);
|
|
47342
|
+
if (hasActiveWebUsbRequest && isOwnedByActiveWebUsbRequest(descriptor, requestQueue)) {
|
|
47343
|
+
const cached = DevicePool.getDeviceByPath(descriptor.path);
|
|
47344
|
+
const message = (cached === null || cached === void 0 ? void 0 : cached.features) ? toSearchDevice(cached) : null;
|
|
47345
|
+
deviceList.push(message !== null && message !== void 0 ? message : toSearchDeviceFromDescriptor(descriptor));
|
|
47302
47346
|
}
|
|
47303
|
-
|
|
47304
|
-
|
|
47305
|
-
|
|
47306
|
-
|
|
47307
|
-
|
|
47347
|
+
else {
|
|
47348
|
+
try {
|
|
47349
|
+
const result = yield DevicePool.getDevices([descriptor], descriptor.path, {
|
|
47350
|
+
connectProtocol: undefined,
|
|
47351
|
+
forceProtocolDetection: true,
|
|
47352
|
+
refreshRuntimeState: true,
|
|
47353
|
+
});
|
|
47354
|
+
for (const device of result.deviceList) {
|
|
47355
|
+
const message = toSearchDevice(device);
|
|
47356
|
+
if (message)
|
|
47357
|
+
deviceList.push(message);
|
|
47358
|
+
}
|
|
47359
|
+
}
|
|
47360
|
+
catch (error) {
|
|
47361
|
+
const errorCode = error && typeof error === 'object' && 'errorCode' in error
|
|
47362
|
+
? error.errorCode
|
|
47363
|
+
: undefined;
|
|
47364
|
+
Log$e.debug('Skip unavailable device during search', Object.assign({ path: descriptor.path }, (errorCode !== undefined ? { errorCode } : {})));
|
|
47365
|
+
}
|
|
47308
47366
|
}
|
|
47309
47367
|
}
|
|
47310
|
-
return deviceList
|
|
47368
|
+
return deviceList;
|
|
47311
47369
|
});
|
|
47312
47370
|
}
|
|
47313
47371
|
}
|
|
@@ -65850,7 +65908,7 @@ const createUiProgressMessageFilter = (intervalMs = DEFAULT_UI_PROGRESS_INTERVAL
|
|
|
65850
65908
|
|
|
65851
65909
|
const Log = getLogger(exports.LoggerNames.Core);
|
|
65852
65910
|
const PRE_INITIALIZE_TTL_MS = 60 * 1000;
|
|
65853
|
-
const PRE_PENDING_CALL_TIMEOUT_MS =
|
|
65911
|
+
const PRE_PENDING_CALL_TIMEOUT_MS = 5 * 1000;
|
|
65854
65912
|
const PRO2_USB_SIGNING_COOLDOWN_MS = 1000;
|
|
65855
65913
|
const preWarmInflight = new Map();
|
|
65856
65914
|
const preWarmDoneAt = new Map();
|
|
@@ -65930,6 +65988,7 @@ const callAPI = (context, message) => __awaiter(void 0, void 0, void 0, function
|
|
|
65930
65988
|
}
|
|
65931
65989
|
};
|
|
65932
65990
|
(_a = method.setContext) === null || _a === void 0 ? void 0 : _a.call(method, context);
|
|
65991
|
+
method.context = context;
|
|
65933
65992
|
method.requestContext = createRequestContext(method.responseID, method.name, {
|
|
65934
65993
|
sdkInstanceId: context.sdkInstanceId,
|
|
65935
65994
|
connectId: method.connectId,
|
|
@@ -65947,7 +66006,11 @@ const callAPI = (context, message) => __awaiter(void 0, void 0, void 0, function
|
|
|
65947
66006
|
if (!method.useDevice) {
|
|
65948
66007
|
updateMethodRequestContext(method, { status: 'running' });
|
|
65949
66008
|
try {
|
|
65950
|
-
const
|
|
66009
|
+
const env = DataManager.getSettings('env');
|
|
66010
|
+
const response = method.name === 'searchDevices' &&
|
|
66011
|
+
(DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env))
|
|
66012
|
+
? yield context.methodSynchronize(() => method.run(), 'webusb-discovery')
|
|
66013
|
+
: yield method.run();
|
|
65951
66014
|
completeMethodRequestContext(method);
|
|
65952
66015
|
return createResponseMessage(method.responseID, true, response);
|
|
65953
66016
|
}
|
|
@@ -66018,20 +66081,28 @@ const waitForPendingPromise = (connectId, getPrePendingCallPromise, removePrePen
|
|
|
66018
66081
|
if (pendingPromise) {
|
|
66019
66082
|
Log.debug('pre pending call promise before call method, wait for it');
|
|
66020
66083
|
let timer;
|
|
66084
|
+
let timedOut = false;
|
|
66085
|
+
let completed = false;
|
|
66021
66086
|
try {
|
|
66022
66087
|
yield Promise.race([
|
|
66023
66088
|
pendingPromise,
|
|
66024
|
-
new Promise(
|
|
66089
|
+
new Promise(resolve => {
|
|
66025
66090
|
timer = setTimeout(() => {
|
|
66026
|
-
|
|
66091
|
+
timedOut = true;
|
|
66092
|
+
resolve();
|
|
66027
66093
|
}, PRE_PENDING_CALL_TIMEOUT_MS);
|
|
66028
66094
|
}),
|
|
66029
66095
|
]);
|
|
66030
|
-
|
|
66096
|
+
completed = !timedOut;
|
|
66031
66097
|
}
|
|
66032
66098
|
finally {
|
|
66033
66099
|
if (timer)
|
|
66034
66100
|
clearTimeout(timer);
|
|
66101
|
+
if (timedOut || completed)
|
|
66102
|
+
removePrePendingCallPromise === null || removePrePendingCallPromise === void 0 ? void 0 : removePrePendingCallPromise(connectId, pendingPromise);
|
|
66103
|
+
}
|
|
66104
|
+
if (timedOut) {
|
|
66105
|
+
Log.warn('pre pending call promise timed out before call method', { connectId });
|
|
66035
66106
|
}
|
|
66036
66107
|
Log.debug('pre pending call promise before call method done');
|
|
66037
66108
|
}
|
|
@@ -66079,7 +66150,22 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
66079
66150
|
context.registerCallbackTask(method.connectId, preWarmCallbackTask);
|
|
66080
66151
|
}
|
|
66081
66152
|
const pollingId = pollingManager.start(connectId);
|
|
66082
|
-
|
|
66153
|
+
const env = DataManager.getSettings('env');
|
|
66154
|
+
const connect = () => ensureConnected(context, method, connectId, pollingId, method.abortSignal);
|
|
66155
|
+
if (DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env)) {
|
|
66156
|
+
const connectPromise = context.methodSynchronize(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
66157
|
+
var _k;
|
|
66158
|
+
if ((_k = method.abortSignal) === null || _k === void 0 ? void 0 : _k.aborted) {
|
|
66159
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
|
|
66160
|
+
}
|
|
66161
|
+
return connect();
|
|
66162
|
+
}), 'webusb-discovery');
|
|
66163
|
+
connectPromise.catch(() => undefined);
|
|
66164
|
+
device = yield requestQueue.waitForTask(task, () => connectPromise);
|
|
66165
|
+
}
|
|
66166
|
+
else {
|
|
66167
|
+
device = yield connect();
|
|
66168
|
+
}
|
|
66083
66169
|
if ((_e = method.abortSignal) === null || _e === void 0 ? void 0 : _e.aborted) {
|
|
66084
66170
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
|
|
66085
66171
|
}
|
|
@@ -66144,12 +66230,12 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
66144
66230
|
return waitForPendingPromise((_a = method.connectId) !== null && _a !== void 0 ? _a : '', getPrePendingCallPromise, removePrePendingCallPromise);
|
|
66145
66231
|
});
|
|
66146
66232
|
const inner = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
66147
|
-
var
|
|
66233
|
+
var _l, _m;
|
|
66148
66234
|
method.assertProtocolSupported(device.getProtocol(), device.getCurrentFirmwareType());
|
|
66149
66235
|
protocolV2Operation = device.isProtocolV2();
|
|
66150
66236
|
const versionRange = device.getCurrentMethodVersionRange(type => method.getVersionRange()[type]);
|
|
66151
|
-
const currentFirmwareVersion = (
|
|
66152
|
-
const currentBleVersion = (
|
|
66237
|
+
const currentFirmwareVersion = (_l = device.getCurrentFirmwareVersionString()) !== null && _l !== void 0 ? _l : '0.0.0';
|
|
66238
|
+
const currentBleVersion = (_m = device.getCurrentBLEFirmwareVersionString()) !== null && _m !== void 0 ? _m : '0.0.0';
|
|
66153
66239
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
66154
66240
|
let newVersionStatus;
|
|
66155
66241
|
if (device.features && !device.isProtocolV2()) {
|
|
@@ -66227,7 +66313,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
66227
66313
|
}
|
|
66228
66314
|
},
|
|
66229
66315
|
prepare: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
66230
|
-
var
|
|
66316
|
+
var _o, _p, _q, _r, _s, _t;
|
|
66231
66317
|
if (method.deviceId && method.checkDeviceId && !deviceIdCheckedDuringUnlockPreflight) {
|
|
66232
66318
|
const isSameDeviceID = yield checkLiveDeviceId(device, method.deviceId);
|
|
66233
66319
|
if (!isSameDeviceID) {
|
|
@@ -66247,7 +66333,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
66247
66333
|
require: support.require,
|
|
66248
66334
|
});
|
|
66249
66335
|
}
|
|
66250
|
-
const passphraseStateSafety = yield device.checkPassphraseStateSafety((
|
|
66336
|
+
const passphraseStateSafety = yield device.checkPassphraseStateSafety((_o = method.payload) === null || _o === void 0 ? void 0 : _o.passphraseState, (_p = method.payload) === null || _p === void 0 ? void 0 : _p.useEmptyPassphrase, (_q = method.payload) === null || _q === void 0 ? void 0 : _q.skipPassphraseCheck, resolveDeriveCardano(method), (_r = method.protocolV2UnlockContext) === null || _r === void 0 ? void 0 : _r.preflightMainPinSelected);
|
|
66251
66337
|
checkPassphraseEnableState(method, device.features);
|
|
66252
66338
|
if (!passphraseStateSafety) {
|
|
66253
66339
|
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
@@ -66265,7 +66351,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
66265
66351
|
? e
|
|
66266
66352
|
: hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'open safety check failed.');
|
|
66267
66353
|
}
|
|
66268
|
-
(
|
|
66354
|
+
(_t = (_s = method.device) === null || _s === void 0 ? void 0 : _s.commands) === null || _t === void 0 ? void 0 : _t.checkDisposed();
|
|
66269
66355
|
}),
|
|
66270
66356
|
});
|
|
66271
66357
|
messageResponse = createResponseMessage(method.responseID, true, response);
|
|
@@ -66620,10 +66706,11 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
66620
66706
|
const POLL_INTERVAL_TIME = (method.payload && method.payload.pollIntervalTime) || 1000;
|
|
66621
66707
|
const TIME_OUT = (method.payload && method.payload.timeout) || 10000;
|
|
66622
66708
|
let timer = null;
|
|
66709
|
+
let lastInitializeError;
|
|
66623
66710
|
Log.debug(`EnsureConnected function start, MAX_RETRY_COUNT=${MAX_RETRY_COUNT}, POLL_INTERVAL_TIME=${POLL_INTERVAL_TIME} `);
|
|
66624
66711
|
const poll = (time = POLL_INTERVAL_TIME) => __awaiter(void 0, void 0, void 0, function* () {
|
|
66625
66712
|
return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
|
|
66626
|
-
var
|
|
66713
|
+
var _u;
|
|
66627
66714
|
const abort = () => {
|
|
66628
66715
|
if (abortSignal && abortSignal.aborted) {
|
|
66629
66716
|
if (timer) {
|
|
@@ -66652,8 +66739,10 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
66652
66739
|
Log.debug('EnsureConnected function try count: ', tryCount, ' poll interval time: ', time);
|
|
66653
66740
|
try {
|
|
66654
66741
|
yield initDeviceList(method);
|
|
66742
|
+
lastInitializeError = undefined;
|
|
66655
66743
|
}
|
|
66656
66744
|
catch (error) {
|
|
66745
|
+
lastInitializeError = error;
|
|
66657
66746
|
Log.debug('device list error: ', error);
|
|
66658
66747
|
if ([
|
|
66659
66748
|
hdShared.HardwareErrorCode.BridgeNotInstalled,
|
|
@@ -66666,6 +66755,7 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
66666
66755
|
}
|
|
66667
66756
|
if (error.errorCode === hdShared.HardwareErrorCode.TransportNotConfigured) {
|
|
66668
66757
|
yield TransportManager.configure();
|
|
66758
|
+
lastInitializeError = undefined;
|
|
66669
66759
|
}
|
|
66670
66760
|
}
|
|
66671
66761
|
if (abort()) {
|
|
@@ -66748,13 +66838,16 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
66748
66838
|
clearTimeout(timer);
|
|
66749
66839
|
}
|
|
66750
66840
|
Log.debug('EnsureConnected get to max try count, will return: ', tryCount);
|
|
66751
|
-
|
|
66841
|
+
const preserveWebUsbInitError = DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env);
|
|
66842
|
+
const needsPermissionPrompt = DataManager.isBrowserWebUsb(env) && !((_u = method.payload) === null || _u === void 0 ? void 0 : _u.skipWebDevicePrompt);
|
|
66843
|
+
const fallbackError = needsPermissionPrompt
|
|
66844
|
+
? hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission)
|
|
66845
|
+
: hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
|
|
66846
|
+
const errorToReject = preserveWebUsbInitError && lastInitializeError ? lastInitializeError : fallbackError;
|
|
66847
|
+
if (needsPermissionPrompt && errorToReject === fallbackError) {
|
|
66752
66848
|
postMessage(createUiMessage(UI_REQUEST.WEB_DEVICE_PROMPT_ACCESS_PERMISSION));
|
|
66753
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission));
|
|
66754
|
-
}
|
|
66755
|
-
else {
|
|
66756
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound));
|
|
66757
66849
|
}
|
|
66850
|
+
reject(errorToReject);
|
|
66758
66851
|
return;
|
|
66759
66852
|
}
|
|
66760
66853
|
if (abort()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.2-alpha.
|
|
3
|
+
"version": "1.2.2-alpha.114",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.2-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.2-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.2-alpha.114",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.2-alpha.114",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"buffer": "^6.0.3",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"@types/w3c-web-usb": "^1.0.10",
|
|
47
47
|
"@types/web-bluetooth": "^0.0.21"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "6490382eeeb6bda264b71c7e9bf96143840ee1cb"
|
|
50
50
|
}
|
package/src/api/SearchDevices.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canonicalizePro2BleAdvertisementName } from '@onekeyfe/hd-shared';
|
|
1
|
+
import { EDeviceType, canonicalizePro2BleAdvertisementName } from '@onekeyfe/hd-shared';
|
|
2
2
|
|
|
3
3
|
import { BaseMethod } from './BaseMethod';
|
|
4
4
|
import TransportManager from '../data-manager/TransportManager';
|
|
@@ -6,10 +6,46 @@ import { DataManager } from '../data-manager';
|
|
|
6
6
|
import { LoggerNames, getDeviceTypeByBleName, getLogger } from '../utils';
|
|
7
7
|
import { DevicePool } from '../device/DevicePool';
|
|
8
8
|
|
|
9
|
+
import type { SearchDevice } from '../types/device';
|
|
9
10
|
import type DeviceConnector from '../device/DeviceConnector';
|
|
11
|
+
import type { OneKeyDeviceInfo as DeviceDescriptor } from '@onekeyfe/hd-transport';
|
|
12
|
+
import type { Device } from '../device/Device';
|
|
10
13
|
|
|
11
14
|
const Log = getLogger(LoggerNames.DevicePool);
|
|
12
15
|
|
|
16
|
+
type RequestQueueLookup = {
|
|
17
|
+
getRequestTasksIdByConnectId: (connectId: string) => number[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const isOwnedByActiveWebUsbRequest = (
|
|
21
|
+
descriptor: DeviceDescriptor,
|
|
22
|
+
requestQueue?: RequestQueueLookup
|
|
23
|
+
) => {
|
|
24
|
+
if (!requestQueue) return false;
|
|
25
|
+
const keys = [descriptor.path, descriptor.id].filter(
|
|
26
|
+
(key): key is string => typeof key === 'string' && key.length > 0
|
|
27
|
+
);
|
|
28
|
+
return keys.some(key => requestQueue.getRequestTasksIdByConnectId(key).length > 0);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const toSearchDeviceFromDescriptor = (descriptor: DeviceDescriptor): SearchDevice => {
|
|
32
|
+
const connectId = descriptor.path || descriptor.id || null;
|
|
33
|
+
return {
|
|
34
|
+
connectId,
|
|
35
|
+
uuid: connectId ?? '',
|
|
36
|
+
serialNo: connectId,
|
|
37
|
+
deviceId: null,
|
|
38
|
+
deviceType: EDeviceType.Unknown,
|
|
39
|
+
name: descriptor.name || connectId || '',
|
|
40
|
+
commType: descriptor.commType,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const toSearchDevice = (device: Device): SearchDevice | null => {
|
|
45
|
+
const message = device.toMessageObject();
|
|
46
|
+
return message ? (message as SearchDevice) : null;
|
|
47
|
+
};
|
|
48
|
+
|
|
13
49
|
export default class SearchDevices extends BaseMethod {
|
|
14
50
|
connector?: DeviceConnector;
|
|
15
51
|
|
|
@@ -19,19 +55,31 @@ export default class SearchDevices extends BaseMethod {
|
|
|
19
55
|
this.skipForceUpdateCheck = true;
|
|
20
56
|
}
|
|
21
57
|
|
|
22
|
-
async run() {
|
|
23
|
-
|
|
58
|
+
async run(): Promise<SearchDevice[]> {
|
|
59
|
+
const env = DataManager.getSettings('env');
|
|
60
|
+
const isWebUsb = env === 'webusb' || env === 'desktop-webusb';
|
|
61
|
+
const requestQueue = this.context?.requestQueue;
|
|
62
|
+
const hasActiveWebUsbRequest = isWebUsb && (requestQueue?.getRequestTasksId().length ?? 0) > 0;
|
|
63
|
+
// Bring up WebUSB even when schema configuration is deferred while a
|
|
64
|
+
// business request owns the discovery lock. Failures here used to be
|
|
65
|
+
// swallowed by configure(); keep searchDevices resolving empty.
|
|
66
|
+
if (isWebUsb) {
|
|
67
|
+
try {
|
|
68
|
+
await TransportManager.ensureInitialized();
|
|
69
|
+
} catch (error) {
|
|
70
|
+
Log.debug('WebUSB bring-up unavailable', error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!hasActiveWebUsbRequest) await TransportManager.configure();
|
|
24
74
|
const deviceDiff = await this.connector?.enumerate();
|
|
25
75
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
26
76
|
|
|
27
|
-
const env = DataManager.getSettings('env');
|
|
28
|
-
|
|
29
77
|
/**
|
|
30
78
|
* No need to call features during Bluetooth scaning
|
|
31
79
|
* to avoid device pairing
|
|
32
80
|
*/
|
|
33
81
|
if (DataManager.isBleConnect(env)) {
|
|
34
|
-
const devices = [];
|
|
82
|
+
const devices: SearchDevice[] = [];
|
|
35
83
|
const seenIds = new Set<string>();
|
|
36
84
|
|
|
37
85
|
for (const device of devicesDescriptor) {
|
|
@@ -56,30 +104,41 @@ export default class SearchDevices extends BaseMethod {
|
|
|
56
104
|
return devices;
|
|
57
105
|
}
|
|
58
106
|
|
|
59
|
-
const deviceList = [];
|
|
107
|
+
const deviceList: SearchDevice[] = [];
|
|
60
108
|
for (const descriptor of devicesDescriptor) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
109
|
+
if (hasActiveWebUsbRequest && isOwnedByActiveWebUsbRequest(descriptor, requestQueue)) {
|
|
110
|
+
const cached = DevicePool.getDeviceByPath(descriptor.path);
|
|
111
|
+
const message = cached?.features ? toSearchDevice(cached) : null;
|
|
112
|
+
// Do not probe a path an in-flight request already owns. A cache miss
|
|
113
|
+
// (passphrase switch / initSession) is still a connected device.
|
|
114
|
+
deviceList.push(message ?? toSearchDeviceFromDescriptor(descriptor));
|
|
115
|
+
} else {
|
|
116
|
+
try {
|
|
117
|
+
// Discovery is best effort. Browsers may retain WebUSB grants for devices that
|
|
118
|
+
// are offline, busy, or not ready, so one descriptor must not abort the scan.
|
|
119
|
+
const result = await DevicePool.getDevices([descriptor], descriptor.path, {
|
|
120
|
+
// Discovery must actively identify the protocol instead of trusting a caller hint.
|
|
121
|
+
connectProtocol: undefined,
|
|
122
|
+
forceProtocolDetection: true,
|
|
123
|
+
refreshRuntimeState: true,
|
|
124
|
+
});
|
|
125
|
+
for (const device of result.deviceList) {
|
|
126
|
+
const message = toSearchDevice(device);
|
|
127
|
+
if (message) deviceList.push(message);
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
const errorCode =
|
|
131
|
+
error && typeof error === 'object' && 'errorCode' in error
|
|
132
|
+
? (error as { errorCode?: unknown }).errorCode
|
|
133
|
+
: undefined;
|
|
134
|
+
Log.debug('Skip unavailable device during search', {
|
|
135
|
+
path: descriptor.path,
|
|
136
|
+
...(errorCode !== undefined ? { errorCode } : {}),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
80
139
|
}
|
|
81
140
|
}
|
|
82
141
|
|
|
83
|
-
return deviceList
|
|
142
|
+
return deviceList;
|
|
84
143
|
}
|
|
85
144
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -84,7 +84,7 @@ import type { BaseMethod } from '../api/BaseMethod';
|
|
|
84
84
|
|
|
85
85
|
const Log = getLogger(LoggerNames.Core);
|
|
86
86
|
const PRE_INITIALIZE_TTL_MS = 60 * 1000;
|
|
87
|
-
const PRE_PENDING_CALL_TIMEOUT_MS =
|
|
87
|
+
const PRE_PENDING_CALL_TIMEOUT_MS = 5 * 1000;
|
|
88
88
|
const PRO2_USB_SIGNING_COOLDOWN_MS = 1000;
|
|
89
89
|
|
|
90
90
|
// Dedup/coalesce state for "pre-warm signal" methods (isPreWarmSignal),
|
|
@@ -183,6 +183,7 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
|
|
|
183
183
|
}
|
|
184
184
|
};
|
|
185
185
|
method.setContext?.(context);
|
|
186
|
+
method.context = context;
|
|
186
187
|
|
|
187
188
|
method.requestContext = createRequestContext(method.responseID, method.name, {
|
|
188
189
|
sdkInstanceId: context.sdkInstanceId,
|
|
@@ -203,7 +204,12 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
|
|
|
203
204
|
if (!method.useDevice) {
|
|
204
205
|
updateMethodRequestContext(method, { status: 'running' });
|
|
205
206
|
try {
|
|
206
|
-
const
|
|
207
|
+
const env = DataManager.getSettings('env');
|
|
208
|
+
const response =
|
|
209
|
+
method.name === 'searchDevices' &&
|
|
210
|
+
(DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env))
|
|
211
|
+
? await context.methodSynchronize(() => method.run(), 'webusb-discovery')
|
|
212
|
+
: await method.run();
|
|
207
213
|
completeMethodRequestContext(method);
|
|
208
214
|
return createResponseMessage(method.responseID, true, response);
|
|
209
215
|
} catch (error) {
|
|
@@ -315,25 +321,27 @@ const waitForPendingPromise = async (
|
|
|
315
321
|
if (pendingPromise) {
|
|
316
322
|
Log.debug('pre pending call promise before call method, wait for it');
|
|
317
323
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
324
|
+
let timedOut = false;
|
|
325
|
+
let completed = false;
|
|
318
326
|
try {
|
|
319
327
|
await Promise.race([
|
|
320
328
|
pendingPromise,
|
|
321
|
-
new Promise<void>(
|
|
329
|
+
new Promise<void>(resolve => {
|
|
322
330
|
timer = setTimeout(() => {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
HardwareErrorCode.DeviceBusy,
|
|
326
|
-
'Previous device cancellation is still draining'
|
|
327
|
-
)
|
|
328
|
-
);
|
|
331
|
+
timedOut = true;
|
|
332
|
+
resolve();
|
|
329
333
|
}, PRE_PENDING_CALL_TIMEOUT_MS);
|
|
330
334
|
}),
|
|
331
335
|
]);
|
|
332
|
-
|
|
333
|
-
// barrier on failure; a later call may proceed only after cleanup settles.
|
|
334
|
-
removePrePendingCallPromise?.(connectId, pendingPromise);
|
|
336
|
+
completed = !timedOut;
|
|
335
337
|
} finally {
|
|
336
338
|
if (timer) clearTimeout(timer);
|
|
339
|
+
// Keep a rejected cleanup barrier for the next caller's safety check;
|
|
340
|
+
// only a completed cleanup or a timeout may clear it.
|
|
341
|
+
if (timedOut || completed) removePrePendingCallPromise?.(connectId, pendingPromise);
|
|
342
|
+
}
|
|
343
|
+
if (timedOut) {
|
|
344
|
+
Log.warn('pre pending call promise timed out before call method', { connectId });
|
|
337
345
|
}
|
|
338
346
|
Log.debug('pre pending call promise before call method done');
|
|
339
347
|
}
|
|
@@ -411,7 +419,26 @@ const onCallDevice = async (
|
|
|
411
419
|
* Polling to ensure successful connection
|
|
412
420
|
*/
|
|
413
421
|
const pollingId = pollingManager.start(connectId);
|
|
414
|
-
|
|
422
|
+
const env = DataManager.getSettings('env');
|
|
423
|
+
const connect = () =>
|
|
424
|
+
ensureConnected(context, method, connectId, pollingId, method.abortSignal);
|
|
425
|
+
// Discovery may acquire USB endpoints. Finish it before initializing a public
|
|
426
|
+
// request; once registered, that request makes discovery use cached state only.
|
|
427
|
+
if (DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env)) {
|
|
428
|
+
// Synchronization can keep the connect action queued after the caller is
|
|
429
|
+
// cancelled. Observe that promise so a late device-not-found error does
|
|
430
|
+
// not become an unhandled rejection.
|
|
431
|
+
const connectPromise = context.methodSynchronize(async () => {
|
|
432
|
+
if (method.abortSignal?.aborted) {
|
|
433
|
+
throw ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled);
|
|
434
|
+
}
|
|
435
|
+
return connect();
|
|
436
|
+
}, 'webusb-discovery');
|
|
437
|
+
connectPromise.catch(() => undefined);
|
|
438
|
+
device = await requestQueue.waitForTask(task, () => connectPromise);
|
|
439
|
+
} else {
|
|
440
|
+
device = await connect();
|
|
441
|
+
}
|
|
415
442
|
if (method.abortSignal?.aborted) {
|
|
416
443
|
throw ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled);
|
|
417
444
|
}
|
|
@@ -1200,6 +1227,7 @@ const ensureConnected = async (
|
|
|
1200
1227
|
const POLL_INTERVAL_TIME = (method.payload && method.payload.pollIntervalTime) || 1000;
|
|
1201
1228
|
const TIME_OUT = (method.payload && method.payload.timeout) || 10000;
|
|
1202
1229
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
1230
|
+
let lastInitializeError: any;
|
|
1203
1231
|
Log.debug(
|
|
1204
1232
|
`EnsureConnected function start, MAX_RETRY_COUNT=${MAX_RETRY_COUNT}, POLL_INTERVAL_TIME=${POLL_INTERVAL_TIME} `
|
|
1205
1233
|
);
|
|
@@ -1240,7 +1268,9 @@ const ensureConnected = async (
|
|
|
1240
1268
|
Log.debug('EnsureConnected function try count: ', tryCount, ' poll interval time: ', time);
|
|
1241
1269
|
try {
|
|
1242
1270
|
await initDeviceList(method);
|
|
1271
|
+
lastInitializeError = undefined;
|
|
1243
1272
|
} catch (error) {
|
|
1273
|
+
lastInitializeError = error;
|
|
1244
1274
|
Log.debug('device list error: ', error);
|
|
1245
1275
|
if (
|
|
1246
1276
|
[
|
|
@@ -1255,6 +1285,7 @@ const ensureConnected = async (
|
|
|
1255
1285
|
}
|
|
1256
1286
|
if (error.errorCode === HardwareErrorCode.TransportNotConfigured) {
|
|
1257
1287
|
await TransportManager.configure();
|
|
1288
|
+
lastInitializeError = undefined;
|
|
1258
1289
|
}
|
|
1259
1290
|
}
|
|
1260
1291
|
|
|
@@ -1352,14 +1383,22 @@ const ensureConnected = async (
|
|
|
1352
1383
|
clearTimeout(timer);
|
|
1353
1384
|
}
|
|
1354
1385
|
Log.debug('EnsureConnected get to max try count, will return: ', tryCount);
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1386
|
+
const preserveWebUsbInitError =
|
|
1387
|
+
DataManager.isBrowserWebUsb(env) || DataManager.isDesktopWebUsb(env);
|
|
1388
|
+
const needsPermissionPrompt =
|
|
1389
|
+
DataManager.isBrowserWebUsb(env) && !method.payload?.skipWebDevicePrompt;
|
|
1390
|
+
const fallbackError = needsPermissionPrompt
|
|
1391
|
+
? ERRORS.TypedError(HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission)
|
|
1392
|
+
: ERRORS.TypedError(HardwareErrorCode.DeviceNotFound);
|
|
1393
|
+
const errorToReject =
|
|
1394
|
+
preserveWebUsbInitError && lastInitializeError ? lastInitializeError : fallbackError;
|
|
1395
|
+
// Only ask the host for a WebUSB grant when the failure is actually
|
|
1396
|
+
// "not found / needs permission". A preserved initialize error must
|
|
1397
|
+
// not fire that prompt with a different public code.
|
|
1398
|
+
if (needsPermissionPrompt && errorToReject === fallbackError) {
|
|
1358
1399
|
postMessage(createUiMessage(UI_REQUEST.WEB_DEVICE_PROMPT_ACCESS_PERMISSION));
|
|
1359
|
-
reject(ERRORS.TypedError(HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission));
|
|
1360
|
-
} else {
|
|
1361
|
-
reject(ERRORS.TypedError(HardwareErrorCode.DeviceNotFound));
|
|
1362
1400
|
}
|
|
1401
|
+
reject(errorToReject);
|
|
1363
1402
|
return;
|
|
1364
1403
|
}
|
|
1365
1404
|
|
|
@@ -33,6 +33,8 @@ export default class TransportManager {
|
|
|
33
33
|
|
|
34
34
|
static reactNativeInit = false;
|
|
35
35
|
|
|
36
|
+
static webUsbInit = false;
|
|
37
|
+
|
|
36
38
|
static protocolV1MessageSchema: ProtocolV1MessageSchema = 'v1CurrentSchema';
|
|
37
39
|
|
|
38
40
|
static plugin: LowlevelTransportSharedPlugin | null = null;
|
|
@@ -42,6 +44,17 @@ export default class TransportManager {
|
|
|
42
44
|
this.defaultMessages = DataManager.getProtobufMessages();
|
|
43
45
|
this.currentMessages = this.defaultMessages;
|
|
44
46
|
this.protocolV1MessageSchema = 'v1CurrentSchema';
|
|
47
|
+
this.webUsbInit = false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static async ensureInitialized() {
|
|
51
|
+
const env = DataManager.getSettings('env');
|
|
52
|
+
if (env !== 'webusb' && env !== 'desktop-webusb') return;
|
|
53
|
+
if (this.webUsbInit) return;
|
|
54
|
+
// The emitter registers USB disconnect events; this must happen even when
|
|
55
|
+
// schema configuration is intentionally deferred during discovery.
|
|
56
|
+
await this.transport.init(WebUsbLogger, DevicePool.emitter);
|
|
57
|
+
this.webUsbInit = true;
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
static async configure() {
|
|
@@ -69,9 +82,7 @@ export default class TransportManager {
|
|
|
69
82
|
} else if (env === 'desktop-web-ble') {
|
|
70
83
|
await this.transport.init(WebBleLogger, DevicePool.emitter);
|
|
71
84
|
} else if (env === 'webusb' || env === 'desktop-webusb') {
|
|
72
|
-
|
|
73
|
-
// DEVICE.DISCONNECT; without it WebUSB never reports device removal.
|
|
74
|
-
await this.transport.init(WebUsbLogger, DevicePool.emitter);
|
|
85
|
+
await this.ensureInitialized();
|
|
75
86
|
} else {
|
|
76
87
|
await this.transport.init(HttpLogger);
|
|
77
88
|
}
|