@onekeyfe/hd-core 1.2.0-alpha.130 → 1.2.0-alpha.132
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__/DeviceCommands.test.ts +7 -0
- package/__tests__/device-lifecycle-events.test.ts +34 -1
- package/__tests__/device-settings.test.ts +7 -8
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +73 -40
- package/package.json +4 -4
- package/src/api/device/DeviceSettings.ts +1 -14
- package/src/core/index.ts +55 -17
- package/src/device/DeviceCommands.ts +14 -1
|
@@ -800,7 +800,13 @@ describe('DeviceCommands cancellation', () => {
|
|
|
800
800
|
try {
|
|
801
801
|
const commands = createCommands();
|
|
802
802
|
commands.disposed = false;
|
|
803
|
+
commands.mainId = 'main-id';
|
|
803
804
|
commands.callPromise = new Promise(() => {});
|
|
805
|
+
const disconnect = jest.fn().mockResolvedValue(undefined);
|
|
806
|
+
commands.transport = {
|
|
807
|
+
name: 'ReactNativeBleTransport',
|
|
808
|
+
disconnect,
|
|
809
|
+
} as any;
|
|
804
810
|
const dispose = jest.fn().mockResolvedValue(undefined);
|
|
805
811
|
commands.dispose = dispose;
|
|
806
812
|
|
|
@@ -810,6 +816,7 @@ describe('DeviceCommands cancellation', () => {
|
|
|
810
816
|
|
|
811
817
|
await expect(cancellation).resolves.toBeUndefined();
|
|
812
818
|
expect(dispose).toHaveBeenCalledWith(true);
|
|
819
|
+
expect(disconnect).toHaveBeenCalledWith('main-id');
|
|
813
820
|
expect(commands.callPromise).toBeUndefined();
|
|
814
821
|
} finally {
|
|
815
822
|
jest.useRealTimers();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EDeviceType, ERRORS, HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
|
|
2
2
|
import { DeviceType, TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
|
|
3
3
|
|
|
4
|
-
import { initConnector, initCore } from '../src/core';
|
|
4
|
+
import { initConnector, initCore, isMissingDetectedProtocolV2Error } from '../src/core';
|
|
5
5
|
import { DataManager } from '../src/data-manager';
|
|
6
6
|
import TransportManager from '../src/data-manager/TransportManager';
|
|
7
7
|
import { Device } from '../src/device/Device';
|
|
@@ -82,6 +82,23 @@ describe('public device lifecycle events', () => {
|
|
|
82
82
|
expect(DevicePool.emitter.listenerCount(DEVICE.DISCONNECT)).toBe(1);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
test('isolates pending cancellation cleanup by connect id', () => {
|
|
86
|
+
core = initCore();
|
|
87
|
+
const context = (core as any).getCoreContext();
|
|
88
|
+
const firstCleanup = createDeferred<void>();
|
|
89
|
+
const replacementCleanup = createDeferred<void>();
|
|
90
|
+
|
|
91
|
+
context.setPrePendingCallPromise('device-a', firstCleanup.promise);
|
|
92
|
+
|
|
93
|
+
expect(context.getPrePendingCallPromise('device-a')).toBe(firstCleanup.promise);
|
|
94
|
+
expect(context.getPrePendingCallPromise('device-b')).toBeUndefined();
|
|
95
|
+
|
|
96
|
+
context.setPrePendingCallPromise('device-a', replacementCleanup.promise);
|
|
97
|
+
context.removePrePendingCallPromise('device-a', firstCleanup.promise);
|
|
98
|
+
|
|
99
|
+
expect(context.getPrePendingCallPromise('device-a')).toBe(replacementCleanup.promise);
|
|
100
|
+
});
|
|
101
|
+
|
|
85
102
|
test('keeps shared device lifecycle listeners across a device cache reset', () => {
|
|
86
103
|
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
87
104
|
core = initCore();
|
|
@@ -234,6 +251,22 @@ describe('public device lifecycle events', () => {
|
|
|
234
251
|
expect(device.getProtocol()).toBe('V2');
|
|
235
252
|
});
|
|
236
253
|
|
|
254
|
+
test.each([
|
|
255
|
+
['V2', true],
|
|
256
|
+
['V1', false],
|
|
257
|
+
] as const)(
|
|
258
|
+
'retries a missing detected protocol only for an explicit Protocol %s connection',
|
|
259
|
+
(connectProtocol, expected) => {
|
|
260
|
+
const method = { payload: { connectProtocol } } as never;
|
|
261
|
+
const error = {
|
|
262
|
+
errorCode: HardwareErrorCode.RuntimeError,
|
|
263
|
+
message: 'Device protocol has not been detected for ble-id',
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
expect(isMissingDetectedProtocolV2Error(method, error)).toBe(expected);
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
|
|
237
270
|
test('converts an internal transport disconnect into a public KnownDevice snapshot', () => {
|
|
238
271
|
jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
|
|
239
272
|
core = initCore();
|
|
@@ -361,8 +361,8 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
361
361
|
expect(getDeviceState).toHaveBeenCalledWith({ refreshSections: ['settings'] });
|
|
362
362
|
});
|
|
363
363
|
|
|
364
|
-
it('
|
|
365
|
-
const { device, getDeviceState } = createDevice({ protocol: 'V2' });
|
|
364
|
+
it('does not overwrite Pro2 passphrase state when refreshed state does not match', async () => {
|
|
365
|
+
const { device, getDeviceState, updateState } = createDevice({ protocol: 'V2' });
|
|
366
366
|
getDeviceState.mockResolvedValue({
|
|
367
367
|
status: { passphraseProtection: false },
|
|
368
368
|
});
|
|
@@ -376,14 +376,12 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
376
376
|
method.init();
|
|
377
377
|
(method as any).device = device;
|
|
378
378
|
|
|
379
|
-
await expect(method.run()).
|
|
380
|
-
|
|
381
|
-
message: 'Protocol V2 passphrase setting did not reach the requested value.',
|
|
382
|
-
});
|
|
379
|
+
await expect(method.run()).resolves.toEqual({ message: 'Success' });
|
|
380
|
+
expect(updateState).not.toHaveBeenCalled();
|
|
383
381
|
});
|
|
384
382
|
|
|
385
|
-
it('
|
|
386
|
-
const { device, getDeviceState } = createDevice({ protocol: 'V2' });
|
|
383
|
+
it('keeps the previous Pro2 passphrase state when refreshed state is unavailable after locking', async () => {
|
|
384
|
+
const { device, getDeviceState, updateState } = createDevice({ protocol: 'V2' });
|
|
387
385
|
getDeviceState
|
|
388
386
|
.mockResolvedValueOnce({
|
|
389
387
|
status: { unlocked: true, passphraseProtection: true },
|
|
@@ -402,6 +400,7 @@ describe('DeviceSettings protocol routing', () => {
|
|
|
402
400
|
(method as any).device = device;
|
|
403
401
|
|
|
404
402
|
await expect(method.run()).resolves.toEqual({ message: 'Success' });
|
|
403
|
+
expect(updateState).not.toHaveBeenCalled();
|
|
405
404
|
});
|
|
406
405
|
|
|
407
406
|
it('keeps Protocol V1 passphrase settings on ApplySettings', async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceSettings.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceSettings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0D5D,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,aAAa,CAAC;IACnE,qBAAqB;IAIrB,IAAI;IA0EJ,eAAe;;;;;;;IAWT,GAAG;
|
|
1
|
+
{"version":3,"file":"DeviceSettings.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceSettings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0D5D,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,aAAa,CAAC;IACnE,qBAAqB;IAIrB,IAAI;IA0EJ,eAAe;;;;;;;IAWT,GAAG;CA2HV"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -5,8 +5,10 @@ import DeviceConnector from '../device/DeviceConnector';
|
|
|
5
5
|
import type { ConnectSettings } from '../types';
|
|
6
6
|
import type { CoreMessage } from '../events';
|
|
7
7
|
import type { LowlevelTransportSharedPlugin } from '@onekeyfe/hd-transport';
|
|
8
|
+
import type { BaseMethod } from '../api/BaseMethod';
|
|
8
9
|
export type CoreContext = ReturnType<Core['getCoreContext']>;
|
|
9
10
|
export declare const callAPI: (context: CoreContext, message: CoreMessage) => Promise<any>;
|
|
11
|
+
export declare function isMissingDetectedProtocolV2Error(method: BaseMethod, error: unknown): boolean;
|
|
10
12
|
export declare const cancel: (context: CoreContext, connectId?: string) => void;
|
|
11
13
|
export declare const onDeviceButtonHandler: (__0_0: Device, __0_1: import("../events").DeviceButtonRequestPayload) => void;
|
|
12
14
|
export default class Core extends EventEmitter {
|
|
@@ -14,7 +16,7 @@ export default class Core extends EventEmitter {
|
|
|
14
16
|
readonly sdkInstanceId: string;
|
|
15
17
|
private requestQueue;
|
|
16
18
|
private disposePromise?;
|
|
17
|
-
private
|
|
19
|
+
private prePendingCallPromises;
|
|
18
20
|
private methodSynchronize;
|
|
19
21
|
constructor();
|
|
20
22
|
private getCoreContext;
|
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;AAoClC,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,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAoClC,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,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAmE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AA2qBF,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAQlF;AAsPD,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAqF9D,CAAC;AAmGF,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;IA6BhB,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceCommands.d.ts","sourceRoot":"","sources":["../../src/device/DeviceCommands.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,oBAAoB,EAG1B,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAU,KAAK,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAQlE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,MAAM,wBAAwB,GAAG;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;AACxC,KAAK,UAAU,GAAG,OAAO,CAAC,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC;AACrD,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,UAAU,IAAI;IACvD,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CACzB,CAAC;AACF,KAAK,oBAAoB,GAAG;KACzB,CAAC,IAAI,UAAU,GAAG,oBAAoB,CAAC,CAAC,CAAC;CAC3C,CAAC;AACF,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;AA8DtE,eAAO,MAAM,oBAAoB,WAAY,MAAM;;;;;;;;;;;;;;;;;;EA0ClD,CAAC;AAEF,eAAO,MAAM,0BAA0B,WAAY,MAAM;;;;;;;;;;;;;;;;;;EAgCxD,CAAC;AASF,qBAAa,cAAc;IACzB,UAAU,EAAE,MAAM,CAAC;IAEnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,MAAM,EAAE,MAAM,CAAC;IAEf,SAAS,EAAE,SAAS,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IAEf,QAAQ,EAAE,OAAO,CAAC;IAElB,WAAW,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;gBAElC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAUpC,OAAO,CAAC,cAAc,EAAE,OAAO;IAKrC,aAAa;IAOP,0BAA0B;;;;;;;;;;;;;;;;;;;IAkB1B,YAAY;;;;;;;;;;;;;;;;;;;IAkBZ,MAAM;
|
|
1
|
+
{"version":3,"file":"DeviceCommands.d.ts","sourceRoot":"","sources":["../../src/device/DeviceCommands.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1093,7 +1093,7 @@ declare class Core extends EventEmitter {
|
|
|
1093
1093
|
readonly sdkInstanceId: string;
|
|
1094
1094
|
private requestQueue;
|
|
1095
1095
|
private disposePromise?;
|
|
1096
|
-
private
|
|
1096
|
+
private prePendingCallPromises;
|
|
1097
1097
|
private methodSynchronize;
|
|
1098
1098
|
constructor();
|
|
1099
1099
|
private getCoreContext;
|
package/dist/index.js
CHANGED
|
@@ -43679,6 +43679,7 @@ class DeviceCommands {
|
|
|
43679
43679
|
}
|
|
43680
43680
|
const activeCall = this.callPromise;
|
|
43681
43681
|
let timer;
|
|
43682
|
+
let timedOut = false;
|
|
43682
43683
|
const cancellation = (() => __awaiter(this, void 0, void 0, function* () {
|
|
43683
43684
|
yield this.dispose(true);
|
|
43684
43685
|
yield (activeCall === null || activeCall === void 0 ? void 0 : activeCall.catch(() => undefined));
|
|
@@ -43687,13 +43688,23 @@ class DeviceCommands {
|
|
|
43687
43688
|
yield Promise.race([
|
|
43688
43689
|
cancellation,
|
|
43689
43690
|
new Promise(resolve => {
|
|
43690
|
-
timer = setTimeout(
|
|
43691
|
+
timer = setTimeout(() => {
|
|
43692
|
+
timedOut = true;
|
|
43693
|
+
resolve();
|
|
43694
|
+
}, 10 * 1000);
|
|
43691
43695
|
}),
|
|
43692
43696
|
]);
|
|
43693
43697
|
}
|
|
43694
43698
|
finally {
|
|
43695
43699
|
if (timer)
|
|
43696
43700
|
clearTimeout(timer);
|
|
43701
|
+
if (timedOut &&
|
|
43702
|
+
this.transport.name === 'ReactNativeBleTransport' &&
|
|
43703
|
+
this.transport.disconnect) {
|
|
43704
|
+
yield this.transport.disconnect(this.mainId).catch(error => {
|
|
43705
|
+
Log$h.debug('BLE cancellation timeout disconnect error (ignored)', error);
|
|
43706
|
+
});
|
|
43707
|
+
}
|
|
43697
43708
|
if (this.callPromise === activeCall) {
|
|
43698
43709
|
this.callPromise = undefined;
|
|
43699
43710
|
}
|
|
@@ -48515,14 +48526,7 @@ class DeviceSettings extends BaseMethod {
|
|
|
48515
48526
|
const res = yield this.device.commands.typedCall('DeviceSettingsPageShow', 'Success', {
|
|
48516
48527
|
page: hdTransport.DeviceSettingsPage.DevicePassphrase,
|
|
48517
48528
|
});
|
|
48518
|
-
|
|
48519
|
-
const lockedAfterDisabling = requestedPassphrase === false &&
|
|
48520
|
-
current.status.unlocked === true &&
|
|
48521
|
-
updated.status.unlocked === false;
|
|
48522
|
-
if (updated.status.passphraseProtection !== requestedPassphrase &&
|
|
48523
|
-
!lockedAfterDisabling) {
|
|
48524
|
-
throw hdShared.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 passphrase setting did not reach the requested value.');
|
|
48525
|
-
}
|
|
48529
|
+
yield refreshStatusAndSettings();
|
|
48526
48530
|
return res.message;
|
|
48527
48531
|
}
|
|
48528
48532
|
if (requestedAirgap !== undefined) {
|
|
@@ -65014,6 +65018,7 @@ const createUiProgressMessageFilter = (intervalMs = DEFAULT_UI_PROGRESS_INTERVAL
|
|
|
65014
65018
|
|
|
65015
65019
|
const Log = getLogger(exports.LoggerNames.Core);
|
|
65016
65020
|
const PRE_INITIALIZE_TTL_MS = 60 * 1000;
|
|
65021
|
+
const PRE_PENDING_CALL_TIMEOUT_MS = 15 * 1000;
|
|
65017
65022
|
const preWarmInflight = new Map();
|
|
65018
65023
|
const preWarmDoneAt = new Map();
|
|
65019
65024
|
function hasDeriveCardano(method) {
|
|
@@ -65169,23 +65174,40 @@ const handlePreWarmSignal = (context, message, method) => __awaiter(void 0, void
|
|
|
65169
65174
|
}
|
|
65170
65175
|
}
|
|
65171
65176
|
});
|
|
65172
|
-
const waitForPendingPromise = (getPrePendingCallPromise, removePrePendingCallPromise) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65173
|
-
const pendingPromise = getPrePendingCallPromise();
|
|
65177
|
+
const waitForPendingPromise = (connectId, getPrePendingCallPromise, removePrePendingCallPromise) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65178
|
+
const pendingPromise = getPrePendingCallPromise(connectId);
|
|
65174
65179
|
if (pendingPromise) {
|
|
65175
65180
|
Log.debug('pre pending call promise before call method, wait for it');
|
|
65181
|
+
let timer;
|
|
65182
|
+
let timedOut = false;
|
|
65176
65183
|
try {
|
|
65177
|
-
yield
|
|
65184
|
+
yield Promise.race([
|
|
65185
|
+
pendingPromise,
|
|
65186
|
+
new Promise(resolve => {
|
|
65187
|
+
timer = setTimeout(() => {
|
|
65188
|
+
timedOut = true;
|
|
65189
|
+
resolve();
|
|
65190
|
+
}, PRE_PENDING_CALL_TIMEOUT_MS);
|
|
65191
|
+
}),
|
|
65192
|
+
]);
|
|
65178
65193
|
}
|
|
65179
65194
|
catch (error) {
|
|
65180
65195
|
}
|
|
65181
|
-
|
|
65196
|
+
finally {
|
|
65197
|
+
if (timer)
|
|
65198
|
+
clearTimeout(timer);
|
|
65199
|
+
removePrePendingCallPromise === null || removePrePendingCallPromise === void 0 ? void 0 : removePrePendingCallPromise(connectId, pendingPromise);
|
|
65200
|
+
}
|
|
65201
|
+
if (timedOut) {
|
|
65202
|
+
Log.warn('pre pending call promise timed out before call method', { connectId });
|
|
65203
|
+
}
|
|
65182
65204
|
Log.debug('pre pending call promise before call method done');
|
|
65183
65205
|
}
|
|
65184
65206
|
});
|
|
65185
65207
|
const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65186
|
-
var _d, _e, _f, _g, _h;
|
|
65208
|
+
var _d, _e, _f, _g, _h, _j, _k;
|
|
65187
65209
|
let messageResponse;
|
|
65188
|
-
const { requestQueue, getPrePendingCallPromise,
|
|
65210
|
+
const { requestQueue, getPrePendingCallPromise, removePrePendingCallPromise } = context;
|
|
65189
65211
|
updateMethodRequestContext(method, { status: 'running' });
|
|
65190
65212
|
const normalizePassphraseState = (s) => s || '';
|
|
65191
65213
|
const connectStateChange = normalizePassphraseState(preConnectCache.passphraseState) !==
|
|
@@ -65200,7 +65222,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65200
65222
|
if (method.connectId) {
|
|
65201
65223
|
yield context.waitForCallbackTasks(method.connectId);
|
|
65202
65224
|
}
|
|
65203
|
-
yield waitForPendingPromise(getPrePendingCallPromise,
|
|
65225
|
+
yield waitForPendingPromise((_d = method.connectId) !== null && _d !== void 0 ? _d : '', getPrePendingCallPromise, removePrePendingCallPromise);
|
|
65204
65226
|
const task = requestQueue.createTask(method);
|
|
65205
65227
|
let preWarmCallbackTask;
|
|
65206
65228
|
if (method.isPreWarmSignal && method.connectId) {
|
|
@@ -65209,9 +65231,9 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65209
65231
|
}
|
|
65210
65232
|
let device;
|
|
65211
65233
|
try {
|
|
65212
|
-
const connectId = (
|
|
65234
|
+
const connectId = (_e = method.connectId) !== null && _e !== void 0 ? _e : '';
|
|
65213
65235
|
const pollingId = pollingManager.start(connectId);
|
|
65214
|
-
device = yield ensureConnected(context, method, connectId, pollingId, (
|
|
65236
|
+
device = yield ensureConnected(context, method, connectId, pollingId, (_f = task.abortController) === null || _f === void 0 ? void 0 : _f.signal);
|
|
65215
65237
|
}
|
|
65216
65238
|
catch (e) {
|
|
65217
65239
|
preWarmCallbackTask === null || preWarmCallbackTask === void 0 ? void 0 : preWarmCallbackTask.resolve();
|
|
@@ -65226,17 +65248,17 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65226
65248
|
requestQueue.releaseTask(method.responseID);
|
|
65227
65249
|
return createResponseMessage(method.responseID, false, { error: e });
|
|
65228
65250
|
}
|
|
65229
|
-
if ((
|
|
65251
|
+
if ((_g = method.payload) === null || _g === void 0 ? void 0 : _g.onlyConnectBleDevice) {
|
|
65230
65252
|
preWarmCallbackTask === null || preWarmCallbackTask === void 0 ? void 0 : preWarmCallbackTask.resolve();
|
|
65231
65253
|
Log.debug('Call API - only connect ble device: ', device === null || device === void 0 ? void 0 : device.mainId);
|
|
65232
65254
|
return createResponseMessage(method.responseID, true, null);
|
|
65233
65255
|
}
|
|
65234
65256
|
Log.debug('Call API - setDevice: ', device.mainId);
|
|
65235
|
-
(
|
|
65257
|
+
(_h = method.setDevice) === null || _h === void 0 ? void 0 : _h.call(method, device);
|
|
65236
65258
|
method.context = context;
|
|
65237
65259
|
updateMethodRequestContext(method, {
|
|
65238
65260
|
deviceInstanceId: device.instanceId,
|
|
65239
|
-
commandsInstanceId: (
|
|
65261
|
+
commandsInstanceId: (_j = device.commands) === null || _j === void 0 ? void 0 : _j.instanceId,
|
|
65240
65262
|
});
|
|
65241
65263
|
const activeRequests = getActiveRequestsByDeviceInstance(device.instanceId);
|
|
65242
65264
|
if (activeRequests.length > 0) {
|
|
@@ -65265,14 +65287,14 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65265
65287
|
if (method.connectId) {
|
|
65266
65288
|
yield context.waitForCallbackTasks(method.connectId, preWarmCallbackTask);
|
|
65267
65289
|
}
|
|
65268
|
-
yield waitForPendingPromise(getPrePendingCallPromise,
|
|
65290
|
+
yield waitForPendingPromise((_k = method.connectId) !== null && _k !== void 0 ? _k : '', getPrePendingCallPromise, removePrePendingCallPromise);
|
|
65269
65291
|
const inner = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
65270
|
-
var
|
|
65292
|
+
var _l, _m;
|
|
65271
65293
|
method.assertProtocolSupported(device.getProtocol(), device.getCurrentFirmwareType());
|
|
65272
65294
|
protocolV2Operation = device.isProtocolV2();
|
|
65273
65295
|
const versionRange = device.getCurrentMethodVersionRange(type => method.getVersionRange()[type]);
|
|
65274
|
-
const currentFirmwareVersion = (
|
|
65275
|
-
const currentBleVersion = (
|
|
65296
|
+
const currentFirmwareVersion = (_l = device.getCurrentFirmwareVersionString()) !== null && _l !== void 0 ? _l : '0.0.0';
|
|
65297
|
+
const currentBleVersion = (_m = device.getCurrentBLEFirmwareVersionString()) !== null && _m !== void 0 ? _m : '0.0.0';
|
|
65276
65298
|
const deviceFirmwareType = device.getCurrentFirmwareType();
|
|
65277
65299
|
let newVersionStatus;
|
|
65278
65300
|
if (device.features && !device.isProtocolV2()) {
|
|
@@ -65350,7 +65372,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65350
65372
|
}
|
|
65351
65373
|
},
|
|
65352
65374
|
prepare: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
65353
|
-
var
|
|
65375
|
+
var _o, _p, _q, _r, _s;
|
|
65354
65376
|
if (method.deviceId && method.checkDeviceId && !deviceIdCheckedDuringUnlockPreflight) {
|
|
65355
65377
|
const isSameDeviceID = yield checkLiveDeviceId(device, method.deviceId);
|
|
65356
65378
|
if (!isSameDeviceID) {
|
|
@@ -65370,7 +65392,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65370
65392
|
require: support.require,
|
|
65371
65393
|
});
|
|
65372
65394
|
}
|
|
65373
|
-
const passphraseStateSafety = yield device.checkPassphraseStateSafety((
|
|
65395
|
+
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, hasDeriveCardano(method));
|
|
65374
65396
|
checkPassphraseEnableState(method, device.features);
|
|
65375
65397
|
if (!passphraseStateSafety) {
|
|
65376
65398
|
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
@@ -65388,7 +65410,7 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
|
|
|
65388
65410
|
? e
|
|
65389
65411
|
: hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'open safety check failed.');
|
|
65390
65412
|
}
|
|
65391
|
-
(
|
|
65413
|
+
(_s = (_r = method.device) === null || _r === void 0 ? void 0 : _r.commands) === null || _s === void 0 ? void 0 : _s.checkDisposed();
|
|
65392
65414
|
}),
|
|
65393
65415
|
});
|
|
65394
65416
|
messageResponse = createResponseMessage(method.responseID, true, response);
|
|
@@ -65584,9 +65606,10 @@ function isRetryableBleProtocolV2ProbeError(method, error) {
|
|
|
65584
65606
|
message.includes('expected V2') &&
|
|
65585
65607
|
message.includes('did not respond to expected protocol'));
|
|
65586
65608
|
}
|
|
65587
|
-
function
|
|
65609
|
+
function isMissingDetectedProtocolV2Error(method, error) {
|
|
65588
65610
|
const typedError = error;
|
|
65589
|
-
return (
|
|
65611
|
+
return (method.payload.connectProtocol === 'V2' &&
|
|
65612
|
+
(typedError === null || typedError === void 0 ? void 0 : typedError.errorCode) === hdShared.HardwareErrorCode.RuntimeError &&
|
|
65590
65613
|
typeof typedError.message === 'string' &&
|
|
65591
65614
|
typedError.message.includes('Device protocol has not been detected'));
|
|
65592
65615
|
}
|
|
@@ -65624,7 +65647,7 @@ function connectDeviceForBle(method, device, retryCount = 0) {
|
|
|
65624
65647
|
}
|
|
65625
65648
|
}
|
|
65626
65649
|
catch (err) {
|
|
65627
|
-
const requiresColdReconnect =
|
|
65650
|
+
const requiresColdReconnect = isMissingDetectedProtocolV2Error(method, err);
|
|
65628
65651
|
if ((hdShared.ERROR_CODES_REQUIRE_DISCONNECT.includes(err.errorCode) || requiresColdReconnect) &&
|
|
65629
65652
|
device.mainId &&
|
|
65630
65653
|
device.deviceConnector) {
|
|
@@ -65656,7 +65679,7 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
65656
65679
|
Log.debug(`EnsureConnected function start, MAX_RETRY_COUNT=${MAX_RETRY_COUNT}, POLL_INTERVAL_TIME=${POLL_INTERVAL_TIME} `);
|
|
65657
65680
|
const poll = (time = POLL_INTERVAL_TIME) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65658
65681
|
return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
|
|
65659
|
-
var
|
|
65682
|
+
var _t;
|
|
65660
65683
|
const abort = () => {
|
|
65661
65684
|
if (abortSignal && abortSignal.aborted) {
|
|
65662
65685
|
if (timer) {
|
|
@@ -65771,7 +65794,7 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
65771
65794
|
clearTimeout(timer);
|
|
65772
65795
|
}
|
|
65773
65796
|
Log.debug('EnsureConnected get to max try count, will return: ', tryCount);
|
|
65774
|
-
if (DataManager.isBrowserWebUsb(env) && !((
|
|
65797
|
+
if (DataManager.isBrowserWebUsb(env) && !((_t = method.payload) === null || _t === void 0 ? void 0 : _t.skipWebDevicePrompt)) {
|
|
65775
65798
|
postMessage(createUiMessage(UI_REQUEST.WEB_DEVICE_PROMPT_ACCESS_PERMISSION));
|
|
65776
65799
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission));
|
|
65777
65800
|
}
|
|
@@ -65789,7 +65812,7 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
|
|
|
65789
65812
|
return poll();
|
|
65790
65813
|
});
|
|
65791
65814
|
const cancel = (context, connectId) => {
|
|
65792
|
-
var _a, _b;
|
|
65815
|
+
var _a, _b, _c;
|
|
65793
65816
|
const { requestQueue, setPrePendingCallPromise } = context;
|
|
65794
65817
|
if (connectId) {
|
|
65795
65818
|
try {
|
|
@@ -65803,7 +65826,7 @@ const cancel = (context, connectId) => {
|
|
|
65803
65826
|
if (task && ((_a = task.method) === null || _a === void 0 ? void 0 : _a.device)) {
|
|
65804
65827
|
if (!canceledDevices.includes(task.method.device)) {
|
|
65805
65828
|
const { device } = task.method;
|
|
65806
|
-
setPrePendingCallPromise(
|
|
65829
|
+
setPrePendingCallPromise((_b = task.method.connectId) !== null && _b !== void 0 ? _b : connectId, device.interruptionFromUser());
|
|
65807
65830
|
canceledDevices.push(device);
|
|
65808
65831
|
}
|
|
65809
65832
|
requestQueue.rejectRequest(requestId, hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled));
|
|
@@ -65823,7 +65846,7 @@ const cancel = (context, connectId) => {
|
|
|
65823
65846
|
for (const requestId of requestQueue.getRequestTasksId()) {
|
|
65824
65847
|
const task = requestQueue.getTask(requestId);
|
|
65825
65848
|
Log.debug('Cancel Api connect task: ', task);
|
|
65826
|
-
if (task && ((
|
|
65849
|
+
if (task && ((_c = task.method) === null || _c === void 0 ? void 0 : _c.device)) {
|
|
65827
65850
|
if (!canceledDevices.includes(task.method.device)) {
|
|
65828
65851
|
const { device } = task.method;
|
|
65829
65852
|
device === null || device === void 0 ? void 0 : device.interruptionFromUser();
|
|
@@ -66012,6 +66035,7 @@ class Core extends events.exports {
|
|
|
66012
66035
|
constructor() {
|
|
66013
66036
|
super();
|
|
66014
66037
|
this.requestQueue = new RequestQueue();
|
|
66038
|
+
this.prePendingCallPromises = new Map();
|
|
66015
66039
|
this.methodSynchronize = getSynchronize();
|
|
66016
66040
|
this.tracingContext = createSdkTracingContext();
|
|
66017
66041
|
this.sdkInstanceId = this.tracingContext.sdkInstanceId;
|
|
@@ -66023,9 +66047,18 @@ class Core extends events.exports {
|
|
|
66023
66047
|
tracingContext: this.tracingContext,
|
|
66024
66048
|
requestQueue: this.requestQueue,
|
|
66025
66049
|
methodSynchronize: this.methodSynchronize,
|
|
66026
|
-
getPrePendingCallPromise: () => this.
|
|
66027
|
-
setPrePendingCallPromise: (promise) => {
|
|
66028
|
-
|
|
66050
|
+
getPrePendingCallPromise: (connectId) => this.prePendingCallPromises.get(connectId),
|
|
66051
|
+
setPrePendingCallPromise: (connectId, promise) => {
|
|
66052
|
+
if (!promise) {
|
|
66053
|
+
this.prePendingCallPromises.delete(connectId);
|
|
66054
|
+
return;
|
|
66055
|
+
}
|
|
66056
|
+
this.prePendingCallPromises.set(connectId, promise);
|
|
66057
|
+
},
|
|
66058
|
+
removePrePendingCallPromise: (connectId, promise) => {
|
|
66059
|
+
if (this.prePendingCallPromises.get(connectId) === promise) {
|
|
66060
|
+
this.prePendingCallPromises.delete(connectId);
|
|
66061
|
+
}
|
|
66029
66062
|
},
|
|
66030
66063
|
registerCallbackTask: (connectId, callbackPromise) => {
|
|
66031
66064
|
this.requestQueue.registerPendingCallbackTask(connectId, callbackPromise);
|
|
@@ -66119,7 +66152,7 @@ class Core extends events.exports {
|
|
|
66119
66152
|
preWarmInflight.clear();
|
|
66120
66153
|
preWarmDoneAt.clear();
|
|
66121
66154
|
preConnectCache = { passphraseState: undefined };
|
|
66122
|
-
this.
|
|
66155
|
+
this.prePendingCallPromises.clear();
|
|
66123
66156
|
this.removeAllListeners();
|
|
66124
66157
|
cleanupSdkInstance(this.sdkInstanceId);
|
|
66125
66158
|
if (_core === this)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.132",
|
|
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.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.132",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.132",
|
|
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": "e02f784ed4bd26e3efee4592c0c286f0d740425e"
|
|
50
50
|
}
|
|
@@ -200,20 +200,7 @@ export default class DeviceSettings extends BaseMethod<ApplySettings> {
|
|
|
200
200
|
const res = await this.device.commands.typedCall('DeviceSettingsPageShow', 'Success', {
|
|
201
201
|
page: DeviceSettingsPage.DevicePassphrase,
|
|
202
202
|
});
|
|
203
|
-
|
|
204
|
-
const lockedAfterDisabling =
|
|
205
|
-
requestedPassphrase === false &&
|
|
206
|
-
current.status.unlocked === true &&
|
|
207
|
-
updated.status.unlocked === false;
|
|
208
|
-
if (
|
|
209
|
-
updated.status.passphraseProtection !== requestedPassphrase &&
|
|
210
|
-
!lockedAfterDisabling
|
|
211
|
-
) {
|
|
212
|
-
throw TypedError(
|
|
213
|
-
HardwareErrorCode.RuntimeError,
|
|
214
|
-
'Protocol V2 passphrase setting did not reach the requested value.'
|
|
215
|
-
);
|
|
216
|
-
}
|
|
203
|
+
await refreshStatusAndSettings();
|
|
217
204
|
return res.message;
|
|
218
205
|
}
|
|
219
206
|
if (requestedAirgap !== undefined) {
|
package/src/core/index.ts
CHANGED
|
@@ -83,6 +83,7 @@ import type { BaseMethod } from '../api/BaseMethod';
|
|
|
83
83
|
|
|
84
84
|
const Log = getLogger(LoggerNames.Core);
|
|
85
85
|
const PRE_INITIALIZE_TTL_MS = 60 * 1000;
|
|
86
|
+
const PRE_PENDING_CALL_TIMEOUT_MS = 15 * 1000;
|
|
86
87
|
|
|
87
88
|
// Dedup/coalesce state for "pre-warm signal" methods (isPreWarmSignal),
|
|
88
89
|
// keyed by getPreWarmKey(): coalesce in-flight, skip if warmed within TTL.
|
|
@@ -297,18 +298,34 @@ const handlePreWarmSignal = async (
|
|
|
297
298
|
};
|
|
298
299
|
|
|
299
300
|
const waitForPendingPromise = async (
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
connectId: string,
|
|
302
|
+
getPrePendingCallPromise: (connectId: string) => Promise<void> | undefined,
|
|
303
|
+
removePrePendingCallPromise?: (connectId: string, promise: Promise<void>) => void
|
|
302
304
|
) => {
|
|
303
|
-
const pendingPromise = getPrePendingCallPromise();
|
|
305
|
+
const pendingPromise = getPrePendingCallPromise(connectId);
|
|
304
306
|
if (pendingPromise) {
|
|
305
307
|
Log.debug('pre pending call promise before call method, wait for it');
|
|
308
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
309
|
+
let timedOut = false;
|
|
306
310
|
try {
|
|
307
|
-
await
|
|
311
|
+
await Promise.race([
|
|
312
|
+
pendingPromise,
|
|
313
|
+
new Promise<void>(resolve => {
|
|
314
|
+
timer = setTimeout(() => {
|
|
315
|
+
timedOut = true;
|
|
316
|
+
resolve();
|
|
317
|
+
}, PRE_PENDING_CALL_TIMEOUT_MS);
|
|
318
|
+
}),
|
|
319
|
+
]);
|
|
308
320
|
} catch (error) {
|
|
309
|
-
// Cancellation is best-effort
|
|
321
|
+
// Cancellation is best-effort; the transport teardown owns recovery.
|
|
322
|
+
} finally {
|
|
323
|
+
if (timer) clearTimeout(timer);
|
|
324
|
+
removePrePendingCallPromise?.(connectId, pendingPromise);
|
|
325
|
+
}
|
|
326
|
+
if (timedOut) {
|
|
327
|
+
Log.warn('pre pending call promise timed out before call method', { connectId });
|
|
310
328
|
}
|
|
311
|
-
removePrePendingCallPromise?.(pendingPromise);
|
|
312
329
|
Log.debug('pre pending call promise before call method done');
|
|
313
330
|
}
|
|
314
331
|
};
|
|
@@ -320,7 +337,7 @@ const onCallDevice = async (
|
|
|
320
337
|
): Promise<any> => {
|
|
321
338
|
let messageResponse: any;
|
|
322
339
|
|
|
323
|
-
const { requestQueue, getPrePendingCallPromise,
|
|
340
|
+
const { requestQueue, getPrePendingCallPromise, removePrePendingCallPromise } = context;
|
|
324
341
|
|
|
325
342
|
updateMethodRequestContext(method, { status: 'running' });
|
|
326
343
|
|
|
@@ -348,7 +365,11 @@ const onCallDevice = async (
|
|
|
348
365
|
await context.waitForCallbackTasks(method.connectId);
|
|
349
366
|
}
|
|
350
367
|
|
|
351
|
-
await waitForPendingPromise(
|
|
368
|
+
await waitForPendingPromise(
|
|
369
|
+
method.connectId ?? '',
|
|
370
|
+
getPrePendingCallPromise,
|
|
371
|
+
removePrePendingCallPromise
|
|
372
|
+
);
|
|
352
373
|
|
|
353
374
|
const task = requestQueue.createTask(method);
|
|
354
375
|
|
|
@@ -447,7 +468,11 @@ const onCallDevice = async (
|
|
|
447
468
|
await context.waitForCallbackTasks(method.connectId, preWarmCallbackTask);
|
|
448
469
|
}
|
|
449
470
|
|
|
450
|
-
await waitForPendingPromise(
|
|
471
|
+
await waitForPendingPromise(
|
|
472
|
+
method.connectId ?? '',
|
|
473
|
+
getPrePendingCallPromise,
|
|
474
|
+
removePrePendingCallPromise
|
|
475
|
+
);
|
|
451
476
|
|
|
452
477
|
const inner = async (): Promise<void> => {
|
|
453
478
|
// Protocol is established from an active device response during acquire/initialize.
|
|
@@ -899,9 +924,10 @@ function isRetryableBleProtocolV2ProbeError(method: BaseMethod, error: unknown)
|
|
|
899
924
|
);
|
|
900
925
|
}
|
|
901
926
|
|
|
902
|
-
function
|
|
927
|
+
export function isMissingDetectedProtocolV2Error(method: BaseMethod, error: unknown) {
|
|
903
928
|
const typedError = error as { errorCode?: unknown; message?: unknown };
|
|
904
929
|
return (
|
|
930
|
+
method.payload.connectProtocol === 'V2' &&
|
|
905
931
|
typedError?.errorCode === HardwareErrorCode.RuntimeError &&
|
|
906
932
|
typeof typedError.message === 'string' &&
|
|
907
933
|
typedError.message.includes('Device protocol has not been detected')
|
|
@@ -945,7 +971,7 @@ async function connectDeviceForBle(method: BaseMethod, device: Device, retryCoun
|
|
|
945
971
|
DevicePool.emitter.emit(DEVICE.CONNECT, device);
|
|
946
972
|
}
|
|
947
973
|
} catch (err) {
|
|
948
|
-
const requiresColdReconnect =
|
|
974
|
+
const requiresColdReconnect = isMissingDetectedProtocolV2Error(method, err);
|
|
949
975
|
// Device.run()'s REQUIRE_DISCONNECT handling never sees acquire/initialize
|
|
950
976
|
// failures, so with keep-alive a wedged link would be reused by every retry
|
|
951
977
|
// (field case: Initialize timing out at 25s per attempt, forever). Drop it
|
|
@@ -1181,7 +1207,10 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
1181
1207
|
if (task && task.method?.device) {
|
|
1182
1208
|
if (!canceledDevices.includes(task.method.device)) {
|
|
1183
1209
|
const { device } = task.method;
|
|
1184
|
-
setPrePendingCallPromise(
|
|
1210
|
+
setPrePendingCallPromise(
|
|
1211
|
+
task.method.connectId ?? connectId,
|
|
1212
|
+
device.interruptionFromUser()
|
|
1213
|
+
);
|
|
1185
1214
|
canceledDevices.push(device);
|
|
1186
1215
|
}
|
|
1187
1216
|
requestQueue.rejectRequest(
|
|
@@ -1535,7 +1564,7 @@ export default class Core extends EventEmitter {
|
|
|
1535
1564
|
private disposePromise?: Promise<void>;
|
|
1536
1565
|
|
|
1537
1566
|
// background task
|
|
1538
|
-
private
|
|
1567
|
+
private prePendingCallPromises = new Map<string, Promise<void>>();
|
|
1539
1568
|
|
|
1540
1569
|
private methodSynchronize = getSynchronize();
|
|
1541
1570
|
|
|
@@ -1552,9 +1581,18 @@ export default class Core extends EventEmitter {
|
|
|
1552
1581
|
tracingContext: this.tracingContext,
|
|
1553
1582
|
requestQueue: this.requestQueue,
|
|
1554
1583
|
methodSynchronize: this.methodSynchronize,
|
|
1555
|
-
getPrePendingCallPromise: () => this.
|
|
1556
|
-
setPrePendingCallPromise: (
|
|
1557
|
-
|
|
1584
|
+
getPrePendingCallPromise: (connectId: string) => this.prePendingCallPromises.get(connectId),
|
|
1585
|
+
setPrePendingCallPromise: (connectId: string, promise?: Promise<void>) => {
|
|
1586
|
+
if (!promise) {
|
|
1587
|
+
this.prePendingCallPromises.delete(connectId);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
this.prePendingCallPromises.set(connectId, promise);
|
|
1591
|
+
},
|
|
1592
|
+
removePrePendingCallPromise: (connectId: string, promise: Promise<void>) => {
|
|
1593
|
+
if (this.prePendingCallPromises.get(connectId) === promise) {
|
|
1594
|
+
this.prePendingCallPromises.delete(connectId);
|
|
1595
|
+
}
|
|
1558
1596
|
},
|
|
1559
1597
|
// callback 任务管理
|
|
1560
1598
|
registerCallbackTask: (connectId: string, callbackPromise: Deferred<any>) => {
|
|
@@ -1669,7 +1707,7 @@ export default class Core extends EventEmitter {
|
|
|
1669
1707
|
preWarmInflight.clear();
|
|
1670
1708
|
preWarmDoneAt.clear();
|
|
1671
1709
|
preConnectCache = { passphraseState: undefined };
|
|
1672
|
-
this.
|
|
1710
|
+
this.prePendingCallPromises.clear();
|
|
1673
1711
|
this.removeAllListeners();
|
|
1674
1712
|
cleanupSdkInstance(this.sdkInstanceId);
|
|
1675
1713
|
if (_core === this) _core = undefined;
|
|
@@ -264,6 +264,7 @@ export class DeviceCommands {
|
|
|
264
264
|
}
|
|
265
265
|
const activeCall = this.callPromise;
|
|
266
266
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
267
|
+
let timedOut = false;
|
|
267
268
|
const cancellation = (async () => {
|
|
268
269
|
await this.dispose(true);
|
|
269
270
|
await activeCall?.catch(() => undefined);
|
|
@@ -273,11 +274,23 @@ export class DeviceCommands {
|
|
|
273
274
|
await Promise.race([
|
|
274
275
|
cancellation,
|
|
275
276
|
new Promise<void>(resolve => {
|
|
276
|
-
timer = setTimeout(
|
|
277
|
+
timer = setTimeout(() => {
|
|
278
|
+
timedOut = true;
|
|
279
|
+
resolve();
|
|
280
|
+
}, 10 * 1000);
|
|
277
281
|
}),
|
|
278
282
|
]);
|
|
279
283
|
} finally {
|
|
280
284
|
if (timer) clearTimeout(timer);
|
|
285
|
+
if (
|
|
286
|
+
timedOut &&
|
|
287
|
+
this.transport.name === 'ReactNativeBleTransport' &&
|
|
288
|
+
this.transport.disconnect
|
|
289
|
+
) {
|
|
290
|
+
await this.transport.disconnect(this.mainId).catch(error => {
|
|
291
|
+
Log.debug('BLE cancellation timeout disconnect error (ignored)', error);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
281
294
|
if (this.callPromise === activeCall) {
|
|
282
295
|
this.callPromise = undefined;
|
|
283
296
|
}
|