@onekeyfe/hd-core 1.1.19-alpha.0 → 1.1.19-alpha.1
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/dist/api/BaseMethod.d.ts +5 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +4 -4
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +5 -2
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +6 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/index.d.ts +51 -6
- package/dist/index.js +348 -63
- package/dist/types/device.d.ts +3 -0
- package/dist/types/device.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/tracing.d.ts +34 -0
- package/dist/utils/tracing.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +38 -1
- package/src/api/FirmwareUpdateV3.ts +2 -0
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +46 -15
- package/src/api/evm/EVMSignTypedData.ts +8 -2
- package/src/api/firmware/uploadFirmware.ts +51 -15
- package/src/core/index.ts +108 -7
- package/src/data/messages/messages.json +11 -1
- package/src/device/Device.ts +24 -3
- package/src/device/DeviceCommands.ts +42 -8
- package/src/types/device.ts +5 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/tracing.ts +251 -0
|
@@ -2,29 +2,27 @@ import semver from 'semver';
|
|
|
2
2
|
import { blake2s } from '@noble/hashes/blake2s';
|
|
3
3
|
import JSZip from 'jszip';
|
|
4
4
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
LoggerNames,
|
|
8
8
|
getDeviceBootloaderVersion,
|
|
9
9
|
getDeviceType,
|
|
10
|
-
LoggerNames,
|
|
11
10
|
getLogger,
|
|
11
|
+
wait,
|
|
12
12
|
} from '../../utils';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
CoreMessage,
|
|
16
|
-
createUiMessage,
|
|
17
|
-
UI_REQUEST,
|
|
18
|
-
IFirmwareUpdateProgressType,
|
|
19
|
-
} from '../../events';
|
|
20
|
-
import { PROTO } from '../../constants';
|
|
21
|
-
import type { Device } from '../../device/Device';
|
|
22
|
-
import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
|
|
23
|
-
import { DeviceModelToTypes, KnownDevice } from '../../types';
|
|
13
|
+
import { DEVICE, UI_REQUEST, createUiMessage } from '../../events';
|
|
14
|
+
import { DeviceModelToTypes } from '../../types';
|
|
24
15
|
import { bytesToHex } from '../helpers/hexUtils';
|
|
25
16
|
import { DataManager } from '../../data-manager';
|
|
26
17
|
import { DevicePool } from '../../device/DevicePool';
|
|
27
18
|
|
|
19
|
+
import type { KnownDevice } from '../../types';
|
|
20
|
+
import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
|
|
21
|
+
import type { PROTO } from '../../constants';
|
|
22
|
+
import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
|
|
23
|
+
import type { Success } from '@onekeyfe/hd-transport';
|
|
24
|
+
import type { Device } from '../../device/Device';
|
|
25
|
+
|
|
28
26
|
const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
|
|
29
27
|
const SESSION_ERROR = 'session not found';
|
|
30
28
|
const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
|
|
@@ -111,7 +109,45 @@ export const uploadFirmware = async (
|
|
|
111
109
|
if (DeviceModelToTypes.model_mini.includes(deviceType)) {
|
|
112
110
|
postConfirmationMessage(device);
|
|
113
111
|
postProgressTip(device, 'ConfirmOnDevice', postMessage);
|
|
114
|
-
const
|
|
112
|
+
const isFirmware = updateType === 'firmware';
|
|
113
|
+
|
|
114
|
+
const deviceBootloaderVersion = getDeviceBootloaderVersion(device.features).join('.');
|
|
115
|
+
const supportUpgradeFileHeader = semver.gt(deviceBootloaderVersion, '2.1.0');
|
|
116
|
+
|
|
117
|
+
Log.debug(
|
|
118
|
+
'supportUpgradeFileHeader:',
|
|
119
|
+
supportUpgradeFileHeader,
|
|
120
|
+
'deviceBootloaderVersion:',
|
|
121
|
+
deviceBootloaderVersion
|
|
122
|
+
);
|
|
123
|
+
if (isFirmware && supportUpgradeFileHeader) {
|
|
124
|
+
// Extract and validate firmware header (first 1KB)
|
|
125
|
+
const HEADER_SIZE = 1024;
|
|
126
|
+
if (payload.byteLength < HEADER_SIZE) {
|
|
127
|
+
throw ERRORS.TypedError(
|
|
128
|
+
HardwareErrorCode.RuntimeError,
|
|
129
|
+
`firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Log.debug('Uploading firmware header:', { size: HEADER_SIZE, totalSize: payload.byteLength });
|
|
134
|
+
postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
|
|
135
|
+
|
|
136
|
+
const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
|
|
137
|
+
const headerRes = (await typedCall('UpgradeFileHeader', 'Success', {
|
|
138
|
+
data: bytesToHex(header),
|
|
139
|
+
})) as TypedResponseMessage<'Success'>;
|
|
140
|
+
|
|
141
|
+
const isUnexpectedMessage = headerRes.message?.message?.includes('Failure_UnexpectedMessage');
|
|
142
|
+
if (headerRes.type !== 'Success' && !isUnexpectedMessage) {
|
|
143
|
+
Log.error('Firmware header upload failed:', headerRes);
|
|
144
|
+
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'failed to upload firmware header');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
Log.debug('Firmware header uploaded successfully, isUnexpectedMessage:', isUnexpectedMessage);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const eraseCommand = isFirmware ? 'FirmwareErase' : 'FirmwareErase_ex';
|
|
115
151
|
const eraseRes = await typedCall(eraseCommand as unknown as any, 'Success', {});
|
|
116
152
|
if (eraseRes.type !== 'Success') {
|
|
117
153
|
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'erase firmware error');
|
package/src/core/index.ts
CHANGED
|
@@ -29,6 +29,16 @@ import {
|
|
|
29
29
|
getDefectiveDeviceInfo,
|
|
30
30
|
} from '../utils/findDefectiveBatchDevice';
|
|
31
31
|
import { supportNewPassphrase } from '../utils/deviceFeaturesUtils';
|
|
32
|
+
import {
|
|
33
|
+
completeRequestContext,
|
|
34
|
+
createRequestContext,
|
|
35
|
+
createSdkTracingContext,
|
|
36
|
+
formatRequestContext,
|
|
37
|
+
getActiveRequestsByDeviceInstance,
|
|
38
|
+
SdkTracingContext,
|
|
39
|
+
updateRequestContext,
|
|
40
|
+
cleanupSdkInstance,
|
|
41
|
+
} from '../utils/tracing';
|
|
32
42
|
import { Device, DeviceEvents, InitOptions, RunOptions } from '../device/Device';
|
|
33
43
|
import { DeviceList } from '../device/DeviceList';
|
|
34
44
|
import { DevicePool } from '../device/DevicePool';
|
|
@@ -97,6 +107,30 @@ let preConnectCache: {
|
|
|
97
107
|
passphraseState: undefined,
|
|
98
108
|
};
|
|
99
109
|
|
|
110
|
+
const toError = (error: unknown): Error | undefined => {
|
|
111
|
+
if (error instanceof Error) return error;
|
|
112
|
+
if (error == null) return undefined;
|
|
113
|
+
if (typeof error === 'string') return new Error(error);
|
|
114
|
+
try {
|
|
115
|
+
return new Error(JSON.stringify(error));
|
|
116
|
+
} catch {
|
|
117
|
+
return new Error(String(error));
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const updateMethodRequestContext = (method: BaseMethod, updates: any) => {
|
|
122
|
+
if (method.requestContext) {
|
|
123
|
+
updateRequestContext(method.requestContext.responseID, updates);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const completeMethodRequestContext = (method: BaseMethod, error?: unknown) => {
|
|
128
|
+
if (!method.requestContext) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
completeRequestContext(method.requestContext.responseID, toError(error));
|
|
132
|
+
};
|
|
133
|
+
|
|
100
134
|
export const callAPI = async (context: CoreContext, message: CoreMessage) => {
|
|
101
135
|
if (!message.id || !message.payload || message.type !== IFRAME.CALL) {
|
|
102
136
|
return Promise.reject(ERRORS.TypedError('on call: message.id or message.payload is missing'));
|
|
@@ -108,6 +142,15 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
|
|
|
108
142
|
method = findMethod(message as IFrameCallMessage);
|
|
109
143
|
method.connector = _connector;
|
|
110
144
|
method.postMessage = postMessage;
|
|
145
|
+
method.setContext?.(context);
|
|
146
|
+
|
|
147
|
+
method.requestContext = createRequestContext(method.responseID, method.name, {
|
|
148
|
+
sdkInstanceId: context.sdkInstanceId,
|
|
149
|
+
connectId: method.connectId,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
Log.debug(`[${context.sdkInstanceId}] callAPI: ${formatRequestContext(method.requestContext)}`);
|
|
153
|
+
|
|
111
154
|
method.init();
|
|
112
155
|
} catch (error) {
|
|
113
156
|
return Promise.reject(error);
|
|
@@ -116,10 +159,13 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
|
|
|
116
159
|
DevicePool.emitter.on(DEVICE.CONNECT, onDeviceConnectHandler);
|
|
117
160
|
|
|
118
161
|
if (!method.useDevice) {
|
|
162
|
+
updateMethodRequestContext(method, { status: 'running' });
|
|
119
163
|
try {
|
|
120
164
|
const response = await method.run();
|
|
165
|
+
completeMethodRequestContext(method);
|
|
121
166
|
return createResponseMessage(method.responseID, true, response);
|
|
122
167
|
} catch (error) {
|
|
168
|
+
completeMethodRequestContext(method, error);
|
|
123
169
|
return createResponseMessage(method.responseID, false, { error });
|
|
124
170
|
}
|
|
125
171
|
}
|
|
@@ -191,6 +237,8 @@ const onCallDevice = async (
|
|
|
191
237
|
|
|
192
238
|
const { requestQueue, getPrePendingCallPromise, setPrePendingCallPromise } = context;
|
|
193
239
|
|
|
240
|
+
updateMethodRequestContext(method, { status: 'running' });
|
|
241
|
+
|
|
194
242
|
const connectStateChange = preConnectCache.passphraseState !== method.payload.passphraseState;
|
|
195
243
|
|
|
196
244
|
preConnectCache = {
|
|
@@ -225,6 +273,8 @@ const onCallDevice = async (
|
|
|
225
273
|
} catch (e) {
|
|
226
274
|
console.log('ensureConnected error: ', e);
|
|
227
275
|
|
|
276
|
+
completeMethodRequestContext(method, e);
|
|
277
|
+
|
|
228
278
|
if (e.name === 'AbortError' || e.message === 'Request aborted') {
|
|
229
279
|
requestQueue.releaseTask(method.responseID);
|
|
230
280
|
return createResponseMessage(method.responseID, false, {
|
|
@@ -239,6 +289,19 @@ const onCallDevice = async (
|
|
|
239
289
|
method.setDevice?.(device);
|
|
240
290
|
method.context = context;
|
|
241
291
|
|
|
292
|
+
updateMethodRequestContext(method, {
|
|
293
|
+
deviceInstanceId: device.instanceId,
|
|
294
|
+
commandsInstanceId: device.commands?.instanceId,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const activeRequests = getActiveRequestsByDeviceInstance(device.instanceId);
|
|
298
|
+
if (activeRequests.length > 0) {
|
|
299
|
+
Log.warn(
|
|
300
|
+
`[${method.instanceId}] Device ${device.instanceId} has ${activeRequests.length} active requests:`,
|
|
301
|
+
activeRequests.map(formatRequestContext)
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
242
305
|
device.on(DEVICE.PIN, onDevicePinHandler);
|
|
243
306
|
device.on(DEVICE.BUTTON, onDeviceButtonHandler);
|
|
244
307
|
device.on(
|
|
@@ -452,10 +515,12 @@ const onCallDevice = async (
|
|
|
452
515
|
Log.debug('Call API - Inner Method Run: ');
|
|
453
516
|
messageResponse = createResponseMessage(method.responseID, true, response);
|
|
454
517
|
requestQueue.resolveRequest(method.responseID, messageResponse);
|
|
518
|
+
completeMethodRequestContext(method);
|
|
455
519
|
} catch (error) {
|
|
456
|
-
Log.debug(
|
|
520
|
+
Log.debug(`Call API - Inner Method Run Error`, error);
|
|
457
521
|
messageResponse = createResponseMessage(method.responseID, false, { error });
|
|
458
522
|
requestQueue.resolveRequest(method.responseID, messageResponse);
|
|
523
|
+
completeMethodRequestContext(method, error);
|
|
459
524
|
}
|
|
460
525
|
};
|
|
461
526
|
Log.debug('Call API - Device Run: ', device.mainId);
|
|
@@ -471,6 +536,7 @@ const onCallDevice = async (
|
|
|
471
536
|
return await task.callPromise.promise;
|
|
472
537
|
} catch (e) {
|
|
473
538
|
Log.debug('Device Run Error: ', e);
|
|
539
|
+
completeMethodRequestContext(method, e);
|
|
474
540
|
return createResponseMessage(method.responseID, false, { error: e });
|
|
475
541
|
}
|
|
476
542
|
} catch (error) {
|
|
@@ -480,6 +546,7 @@ const onCallDevice = async (
|
|
|
480
546
|
ERRORS.TypedError(HardwareErrorCode.CallMethodError, error.message)
|
|
481
547
|
);
|
|
482
548
|
Log.debug('Call API - Run Error: ', error);
|
|
549
|
+
completeMethodRequestContext(method, error);
|
|
483
550
|
} finally {
|
|
484
551
|
const response = messageResponse;
|
|
485
552
|
|
|
@@ -507,7 +574,20 @@ const onCallDevice = async (
|
|
|
507
574
|
|
|
508
575
|
cleanup();
|
|
509
576
|
|
|
510
|
-
|
|
577
|
+
if (device) {
|
|
578
|
+
const stillActive = getActiveRequestsByDeviceInstance(device.instanceId);
|
|
579
|
+
if (stillActive.length > 1) {
|
|
580
|
+
Log.warn(
|
|
581
|
+
`[${method.instanceId}] Removing listeners while ${stillActive.length} requests are active!`,
|
|
582
|
+
{
|
|
583
|
+
deviceInstanceId: device.instanceId,
|
|
584
|
+
activeRequests: stillActive.map(formatRequestContext),
|
|
585
|
+
pinListeners: device.listenerCount(DEVICE.PIN),
|
|
586
|
+
}
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
removeDeviceListener(device);
|
|
590
|
+
}
|
|
511
591
|
}
|
|
512
592
|
};
|
|
513
593
|
|
|
@@ -587,7 +667,10 @@ function initDeviceForBle(method: BaseMethod) {
|
|
|
587
667
|
if (deviceCacheMap.has(method.connectId)) {
|
|
588
668
|
device = deviceCacheMap.get(method.connectId) as Device;
|
|
589
669
|
} else {
|
|
590
|
-
device = Device.fromDescriptor(
|
|
670
|
+
device = Device.fromDescriptor(
|
|
671
|
+
{ id: method.connectId } as OneKeyDeviceInfo,
|
|
672
|
+
method.sdkInstanceId
|
|
673
|
+
);
|
|
591
674
|
deviceCacheMap.set(method.connectId, device);
|
|
592
675
|
}
|
|
593
676
|
device.deviceConnector = _connector;
|
|
@@ -642,7 +725,7 @@ const ensureConnected = async (
|
|
|
642
725
|
if (timer) {
|
|
643
726
|
clearTimeout(timer);
|
|
644
727
|
}
|
|
645
|
-
reject(ERRORS.TypedError(HardwareErrorCode.
|
|
728
|
+
reject(ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled));
|
|
646
729
|
return true;
|
|
647
730
|
}
|
|
648
731
|
return false;
|
|
@@ -806,7 +889,7 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
806
889
|
}
|
|
807
890
|
requestQueue.rejectRequest(
|
|
808
891
|
requestId,
|
|
809
|
-
ERRORS.TypedError(HardwareErrorCode.
|
|
892
|
+
ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled)
|
|
810
893
|
);
|
|
811
894
|
}
|
|
812
895
|
}
|
|
@@ -831,7 +914,7 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
831
914
|
|
|
832
915
|
requestQueue.rejectRequest(
|
|
833
916
|
requestId,
|
|
834
|
-
ERRORS.TypedError(HardwareErrorCode.
|
|
917
|
+
ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled)
|
|
835
918
|
);
|
|
836
919
|
}
|
|
837
920
|
}
|
|
@@ -844,7 +927,10 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
844
927
|
});
|
|
845
928
|
|
|
846
929
|
requestQueue.getRequestTasksId().forEach(requestId => {
|
|
847
|
-
requestQueue.rejectRequest(
|
|
930
|
+
requestQueue.rejectRequest(
|
|
931
|
+
requestId,
|
|
932
|
+
ERRORS.TypedError(HardwareErrorCode.CallQueueActionCancelled)
|
|
933
|
+
);
|
|
848
934
|
});
|
|
849
935
|
}
|
|
850
936
|
}
|
|
@@ -1023,6 +1109,10 @@ const removeUiPromise = (promise: Deferred<any>) => {
|
|
|
1023
1109
|
};
|
|
1024
1110
|
|
|
1025
1111
|
export default class Core extends EventEmitter {
|
|
1112
|
+
private tracingContext: SdkTracingContext;
|
|
1113
|
+
|
|
1114
|
+
public readonly sdkInstanceId: string;
|
|
1115
|
+
|
|
1026
1116
|
private requestQueue = new RequestQueue();
|
|
1027
1117
|
|
|
1028
1118
|
// background task
|
|
@@ -1030,8 +1120,17 @@ export default class Core extends EventEmitter {
|
|
|
1030
1120
|
|
|
1031
1121
|
private methodSynchronize = getSynchronize();
|
|
1032
1122
|
|
|
1123
|
+
constructor() {
|
|
1124
|
+
super();
|
|
1125
|
+
this.tracingContext = createSdkTracingContext();
|
|
1126
|
+
this.sdkInstanceId = this.tracingContext.sdkInstanceId;
|
|
1127
|
+
Log.debug(`[Core] Created SDK instance: ${this.sdkInstanceId}`);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1033
1130
|
private getCoreContext() {
|
|
1034
1131
|
return {
|
|
1132
|
+
sdkInstanceId: this.sdkInstanceId,
|
|
1133
|
+
tracingContext: this.tracingContext,
|
|
1035
1134
|
requestQueue: this.requestQueue,
|
|
1036
1135
|
methodSynchronize: this.methodSynchronize,
|
|
1037
1136
|
getPrePendingCallPromise: () => this.prePendingCallPromise,
|
|
@@ -1109,6 +1208,8 @@ export default class Core extends EventEmitter {
|
|
|
1109
1208
|
dispose() {
|
|
1110
1209
|
_deviceList = undefined;
|
|
1111
1210
|
_connector = undefined;
|
|
1211
|
+
Log.debug(`[Core] Disposing SDK instance: ${this.sdkInstanceId}`);
|
|
1212
|
+
cleanupSdkInstance(this.sdkInstanceId);
|
|
1112
1213
|
}
|
|
1113
1214
|
}
|
|
1114
1215
|
|
|
@@ -1997,6 +1997,15 @@
|
|
|
1997
1997
|
}
|
|
1998
1998
|
}
|
|
1999
1999
|
},
|
|
2000
|
+
"UpgradeFileHeader": {
|
|
2001
|
+
"fields": {
|
|
2002
|
+
"data": {
|
|
2003
|
+
"rule": "required",
|
|
2004
|
+
"type": "bytes",
|
|
2005
|
+
"id": 1
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
},
|
|
2000
2009
|
"CardanoDerivationType": {
|
|
2001
2010
|
"values": {
|
|
2002
2011
|
"LEDGER": 0,
|
|
@@ -12397,7 +12406,8 @@
|
|
|
12397
12406
|
"MessageType_GetPassphraseState": 10028,
|
|
12398
12407
|
"MessageType_PassphraseState": 10029,
|
|
12399
12408
|
"MessageType_UnLockDevice": 10030,
|
|
12400
|
-
"MessageType_UnLockDeviceResponse": 10031
|
|
12409
|
+
"MessageType_UnLockDeviceResponse": 10031,
|
|
12410
|
+
"MessageType_UpgradeFileHeader": 10050
|
|
12401
12411
|
}
|
|
12402
12412
|
},
|
|
12403
12413
|
"google": {
|
package/src/device/Device.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
fixFeaturesFirmwareVersion,
|
|
25
25
|
getPassphraseStateWithRefreshDeviceInfo,
|
|
26
26
|
} from '../utils/deviceFeaturesUtils';
|
|
27
|
+
import { generateInstanceId } from '../utils/tracing';
|
|
27
28
|
|
|
28
29
|
import type DeviceConnector from './DeviceConnector';
|
|
29
30
|
// eslint-disable-next-line import/no-cycle
|
|
@@ -99,6 +100,15 @@ export class Device extends EventEmitter {
|
|
|
99
100
|
*/
|
|
100
101
|
originalDescriptor: DeviceDescriptor;
|
|
101
102
|
|
|
103
|
+
sdkInstanceId?: string;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 设备实例唯一标识
|
|
107
|
+
*/
|
|
108
|
+
instanceId: string;
|
|
109
|
+
|
|
110
|
+
createdAt: number;
|
|
111
|
+
|
|
102
112
|
/**
|
|
103
113
|
* 设备主 ID
|
|
104
114
|
* 蓝牙连接时是设备的 UUID
|
|
@@ -158,14 +168,22 @@ export class Device extends EventEmitter {
|
|
|
158
168
|
|
|
159
169
|
pendingCallbackPromise?: Deferred<void>;
|
|
160
170
|
|
|
161
|
-
constructor(descriptor: DeviceDescriptor) {
|
|
171
|
+
constructor(descriptor: DeviceDescriptor, sdkInstanceId?: string) {
|
|
162
172
|
super();
|
|
163
173
|
this.originalDescriptor = descriptor;
|
|
174
|
+
this.sdkInstanceId = sdkInstanceId;
|
|
175
|
+
this.instanceId = generateInstanceId('Device', this.sdkInstanceId);
|
|
176
|
+
this.createdAt = Date.now();
|
|
177
|
+
Log.debug(
|
|
178
|
+
`[Device] Created: ${this.instanceId}${
|
|
179
|
+
this.sdkInstanceId ? ` for SDK: ${this.sdkInstanceId}` : ''
|
|
180
|
+
}`
|
|
181
|
+
);
|
|
164
182
|
}
|
|
165
183
|
|
|
166
|
-
static fromDescriptor(originalDescriptor: DeviceDescriptor) {
|
|
184
|
+
static fromDescriptor(originalDescriptor: DeviceDescriptor, sdkInstanceId?: string) {
|
|
167
185
|
const descriptor = { ...originalDescriptor };
|
|
168
|
-
return new Device(descriptor);
|
|
186
|
+
return new Device(descriptor, sdkInstanceId);
|
|
169
187
|
}
|
|
170
188
|
|
|
171
189
|
// simplified object to pass via postMessage
|
|
@@ -183,6 +201,9 @@ export class Device extends EventEmitter {
|
|
|
183
201
|
connectId: DataManager.isBleConnect(env) ? this.mainId || null : getDeviceUUID(this.features),
|
|
184
202
|
/** Hardware ID, will not change at any time */
|
|
185
203
|
uuid: getDeviceUUID(this.features),
|
|
204
|
+
sdkInstanceId: this.sdkInstanceId,
|
|
205
|
+
instanceId: this.instanceId,
|
|
206
|
+
createdAt: this.createdAt,
|
|
186
207
|
deviceType,
|
|
187
208
|
/** ID for current seeds, will clear after replace a new seed at device */
|
|
188
209
|
deviceId: this.features.device_id || null,
|
|
@@ -6,6 +6,11 @@ import { patchFeatures, getLogger, LoggerNames, getDeviceType } from '../utils';
|
|
|
6
6
|
import type { Device } from './Device';
|
|
7
7
|
import { DEVICE, type PassphraseRequestPayload } from '../events';
|
|
8
8
|
import { DeviceModelToTypes } from '../types';
|
|
9
|
+
import {
|
|
10
|
+
formatRequestContext,
|
|
11
|
+
generateInstanceId,
|
|
12
|
+
getActiveRequestsByDeviceInstance,
|
|
13
|
+
} from '../utils/tracing';
|
|
9
14
|
|
|
10
15
|
export type PassphrasePromptResponse = {
|
|
11
16
|
passphrase?: string;
|
|
@@ -114,12 +119,17 @@ export const cancelDeviceWithInitialize = (device: Device) => {
|
|
|
114
119
|
};
|
|
115
120
|
|
|
116
121
|
const Log = getLogger(LoggerNames.DeviceCommands);
|
|
122
|
+
const LogCore = getLogger(LoggerNames.Core);
|
|
117
123
|
|
|
118
124
|
/**
|
|
119
125
|
* The life cycle begins with the acquisition of the device and ends with the disposal device commands
|
|
120
126
|
* acquire device -> create DeviceCommands -> release device -> dispose DeviceCommands
|
|
121
127
|
*/
|
|
122
128
|
export class DeviceCommands {
|
|
129
|
+
instanceId: string;
|
|
130
|
+
|
|
131
|
+
currentResponseID?: number;
|
|
132
|
+
|
|
123
133
|
device: Device;
|
|
124
134
|
|
|
125
135
|
transport: Transport;
|
|
@@ -135,6 +145,9 @@ export class DeviceCommands {
|
|
|
135
145
|
this.mainId = mainId;
|
|
136
146
|
this.transport = TransportManager.getTransport();
|
|
137
147
|
this.disposed = false;
|
|
148
|
+
this.instanceId = generateInstanceId('DeviceCommands', device.sdkInstanceId);
|
|
149
|
+
|
|
150
|
+
Log.debug(`[DeviceCommands] Created: ${this.instanceId}, device: ${this.device.instanceId}`);
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
async dispose(_cancelRequest: boolean) {
|
|
@@ -217,10 +230,10 @@ export class DeviceCommands {
|
|
|
217
230
|
const promise = this.transport.call(this.mainId, type, msg) as any;
|
|
218
231
|
this.callPromise = promise;
|
|
219
232
|
const res = await promise;
|
|
220
|
-
|
|
233
|
+
LogCore.debug('[DeviceCommands] [call] Received', res.type);
|
|
221
234
|
return res;
|
|
222
235
|
} catch (error) {
|
|
223
|
-
|
|
236
|
+
LogCore.debug('[DeviceCommands] [call] Received error', error);
|
|
224
237
|
if (error.errorCode === HardwareErrorCode.BleDeviceBondError) {
|
|
225
238
|
return {
|
|
226
239
|
type: 'BleDeviceBondError',
|
|
@@ -500,7 +513,7 @@ export class DeviceCommands {
|
|
|
500
513
|
cancelDeviceInPrompt(this.device, false)
|
|
501
514
|
.then(onCancel => {
|
|
502
515
|
const error = ERRORS.TypedError(
|
|
503
|
-
HardwareErrorCode.
|
|
516
|
+
HardwareErrorCode.CallQueueActionCancelled,
|
|
504
517
|
`${DEVICE.PIN} canceled`
|
|
505
518
|
);
|
|
506
519
|
// onCancel not void
|
|
@@ -515,7 +528,15 @@ export class DeviceCommands {
|
|
|
515
528
|
reject(error);
|
|
516
529
|
});
|
|
517
530
|
|
|
518
|
-
|
|
531
|
+
const listenerCount = this.device.listenerCount(DEVICE.PIN);
|
|
532
|
+
|
|
533
|
+
Log.debug(`[${this.instanceId}] _promptPin called`, {
|
|
534
|
+
responseID: this.currentResponseID,
|
|
535
|
+
deviceInstanceId: this.device.instanceId,
|
|
536
|
+
listenerCount,
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
if (listenerCount > 0) {
|
|
519
540
|
this.device.setCancelableAction(cancelAndReject);
|
|
520
541
|
this.device.emit(DEVICE.PIN, this.device, type, (err, pin) => {
|
|
521
542
|
this.device.clearCancelableAction();
|
|
@@ -526,11 +547,22 @@ export class DeviceCommands {
|
|
|
526
547
|
}
|
|
527
548
|
});
|
|
528
549
|
} else {
|
|
529
|
-
|
|
550
|
+
const activeRequests = getActiveRequestsByDeviceInstance(this.device.instanceId);
|
|
551
|
+
const errorInfo = {
|
|
552
|
+
commandsInstanceId: this.instanceId,
|
|
553
|
+
deviceInstanceId: this.device.instanceId,
|
|
554
|
+
currentResponseID: this.currentResponseID,
|
|
555
|
+
listenerCount,
|
|
556
|
+
activeRequests: activeRequests.map(formatRequestContext),
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
LogCore.error('[DeviceCommands] [call] PIN callback not configured, cancelling request', {
|
|
560
|
+
...errorInfo,
|
|
561
|
+
});
|
|
530
562
|
reject(
|
|
531
563
|
ERRORS.TypedError(
|
|
532
564
|
HardwareErrorCode.RuntimeError,
|
|
533
|
-
|
|
565
|
+
`_promptPin: PIN callback not configured: ${JSON.stringify(errorInfo)}`
|
|
534
566
|
)
|
|
535
567
|
);
|
|
536
568
|
}
|
|
@@ -543,7 +575,7 @@ export class DeviceCommands {
|
|
|
543
575
|
cancelDeviceInPrompt(this.device, false)
|
|
544
576
|
.then(onCancel => {
|
|
545
577
|
const error = ERRORS.TypedError(
|
|
546
|
-
HardwareErrorCode.
|
|
578
|
+
HardwareErrorCode.CallQueueActionCancelled,
|
|
547
579
|
`${DEVICE.PASSPHRASE} canceled`
|
|
548
580
|
);
|
|
549
581
|
// onCancel not void
|
|
@@ -574,7 +606,9 @@ export class DeviceCommands {
|
|
|
574
606
|
}
|
|
575
607
|
);
|
|
576
608
|
} else {
|
|
577
|
-
|
|
609
|
+
LogCore.error(
|
|
610
|
+
'[DeviceCommands] [call] Passphrase callback not configured, cancelling request'
|
|
611
|
+
);
|
|
578
612
|
reject(
|
|
579
613
|
ERRORS.TypedError(
|
|
580
614
|
HardwareErrorCode.RuntimeError,
|
package/src/types/device.ts
CHANGED
|
@@ -35,6 +35,11 @@ export type KnownDevice = {
|
|
|
35
35
|
unavailableCapabilities: UnavailableCapabilities;
|
|
36
36
|
bleFirmwareVersion: IVersionArray | null;
|
|
37
37
|
firmwareVersion: IVersionArray | null;
|
|
38
|
+
|
|
39
|
+
// debug sdk
|
|
40
|
+
instanceId?: string;
|
|
41
|
+
sdkInstanceId?: string;
|
|
42
|
+
createdAt?: number;
|
|
38
43
|
};
|
|
39
44
|
|
|
40
45
|
export type SearchDevice = {
|
package/src/utils/index.ts
CHANGED