@onekeyfe/hd-core 1.2.8-alpha.128 → 1.2.8-alpha.129
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__/device-lifecycle-events.test.ts +96 -0
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +11 -0
- package/__tests__/protocol-v2-resources.test.ts +14 -0
- package/__tests__/protocol-v2.test.ts +306 -14
- package/__tests__/protocolV2FileWrite.test.ts +434 -7
- package/dist/api/FileWrite.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +0 -1
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +5 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -0
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +1 -0
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +616 -382
- package/dist/protocols/protocol-v2/resources.d.ts +1 -0
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/FileWrite.ts +7 -1
- package/src/api/FirmwareUpdateV4.ts +56 -30
- package/src/api/firmware/FirmwareArtifactSource.ts +12 -3
- package/src/api/helpers/protocolV2FileWrite.ts +375 -111
- package/src/api/protocol-v2/DeviceUploadNft.ts +6 -1
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +15 -1
- package/src/device/Device.ts +18 -2
- package/src/events/ui-request.ts +1 -0
- package/src/protocols/protocol-v2/resources.ts +6 -1
package/dist/index.js
CHANGED
|
@@ -235,15 +235,24 @@ const readFirmwareByteSourceFully = (source) => __awaiter(void 0, void 0, void 0
|
|
|
235
235
|
const readVerifiedFirmwareArtifact = ({ artifact, reader, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
236
236
|
assertFirmwareArtifactReference(artifact);
|
|
237
237
|
const source = yield ReaderFirmwareByteSource.open(artifact, reader);
|
|
238
|
+
const hasher = sha256.sha256.create();
|
|
238
239
|
try {
|
|
239
|
-
const
|
|
240
|
-
|
|
240
|
+
const bytes = new Uint8Array(source.size);
|
|
241
|
+
let offset = 0;
|
|
242
|
+
while (offset < source.size) {
|
|
243
|
+
const length = Math.min(MAX_FIRMWARE_ARTIFACT_READ_BYTES, source.size - offset);
|
|
244
|
+
bytes.set(new Uint8Array(yield source.readAt(offset, length)), offset);
|
|
245
|
+
hasher.update(bytes.subarray(offset, offset + length));
|
|
246
|
+
offset += length;
|
|
247
|
+
}
|
|
248
|
+
const actualSha256 = utils.bytesToHex(hasher.digest());
|
|
241
249
|
if (actualSha256 !== artifact.sha256.toLowerCase()) {
|
|
242
250
|
return artifactError('FirmwareArtifactReceiptMismatch', 'Firmware artifact bytes do not match the approved SHA-256 receipt');
|
|
243
251
|
}
|
|
244
|
-
return
|
|
252
|
+
return bytes.buffer;
|
|
245
253
|
}
|
|
246
254
|
finally {
|
|
255
|
+
hasher.destroy();
|
|
247
256
|
yield source.close().catch(() => undefined);
|
|
248
257
|
}
|
|
249
258
|
});
|
|
@@ -43071,6 +43080,7 @@ const findLatestRelease = (releases) => {
|
|
|
43071
43080
|
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH = 'vol0:/loaders/bootloader/boot_resource.okpkg';
|
|
43072
43081
|
const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_STAGING_PATH = `${PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH}.staging`;
|
|
43073
43082
|
const PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_SIZE = 0x5f90;
|
|
43083
|
+
const PROTOCOL_V2_RESOURCE_PACKAGE_COMPARE_SIZE = 0x280;
|
|
43074
43084
|
const PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_VERSION = 1;
|
|
43075
43085
|
const PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_OFFSET = 0x6c;
|
|
43076
43086
|
const PROTOCOL_V2_RESOURCE_PACKAGE_FLEXIBLE_SIZE = 64;
|
|
@@ -43154,7 +43164,7 @@ function readResourceDevicePath(bytes) {
|
|
|
43154
43164
|
return path;
|
|
43155
43165
|
}
|
|
43156
43166
|
function parseProtocolV2ResourcePackageHeader(bytes, packageSize) {
|
|
43157
|
-
if (bytes.byteLength <
|
|
43167
|
+
if (bytes.byteLength < PROTOCOL_V2_RESOURCE_PACKAGE_COMPARE_SIZE) {
|
|
43158
43168
|
throw new Error('Pro2 RESOURCE package is shorter than its header');
|
|
43159
43169
|
}
|
|
43160
43170
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
@@ -43184,6 +43194,9 @@ function parseProtocolV2ResourcePackageHeader(bytes, packageSize) {
|
|
|
43184
43194
|
}
|
|
43185
43195
|
function parseProtocolV2ResourcePackage(binary) {
|
|
43186
43196
|
const bytes = binary instanceof Uint8Array ? binary : new Uint8Array(binary);
|
|
43197
|
+
if (bytes.byteLength < PROTOCOL_V2_RESOURCE_PACKAGE_HEADER_SIZE) {
|
|
43198
|
+
throw new Error('Pro2 RESOURCE package is shorter than its header');
|
|
43199
|
+
}
|
|
43187
43200
|
return parseProtocolV2ResourcePackageHeader(bytes, bytes.byteLength);
|
|
43188
43201
|
}
|
|
43189
43202
|
|
|
@@ -45546,6 +45559,7 @@ class Device extends events.exports {
|
|
|
45546
45559
|
super();
|
|
45547
45560
|
this.deviceConnector = null;
|
|
45548
45561
|
this.deviceAcquired = false;
|
|
45562
|
+
this.releasedBleConnection = false;
|
|
45549
45563
|
this.connectionAttempt = 0;
|
|
45550
45564
|
this.interruptedAttempt = null;
|
|
45551
45565
|
this.stateStore = new DeviceStateStore();
|
|
@@ -45650,6 +45664,7 @@ class Device extends events.exports {
|
|
|
45650
45664
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45651
45665
|
const attempt = this.connectionAttempt;
|
|
45652
45666
|
this.throwIfInterruptedByUser();
|
|
45667
|
+
this.releasedBleConnection = false;
|
|
45653
45668
|
const env = DataManager.getSettings('env');
|
|
45654
45669
|
const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
|
|
45655
45670
|
const previousProtocol = this.originalDescriptor.protocolType;
|
|
@@ -45729,6 +45744,7 @@ class Device extends events.exports {
|
|
|
45729
45744
|
const env = DataManager.getSettings('env');
|
|
45730
45745
|
if ((this.isUsedHere() && !this.keepSession && this.mainId) ||
|
|
45731
45746
|
(this.mainId && DataManager.isBleConnect(env))) {
|
|
45747
|
+
this.releasedBleConnection = false;
|
|
45732
45748
|
if (this.pendingCallbackPromise) {
|
|
45733
45749
|
try {
|
|
45734
45750
|
Log$i.debug('Waiting for callback tasks to complete before releasing device (in release method)');
|
|
@@ -45750,7 +45766,12 @@ class Device extends events.exports {
|
|
|
45750
45766
|
}
|
|
45751
45767
|
}
|
|
45752
45768
|
try {
|
|
45753
|
-
|
|
45769
|
+
const deviceType = this.getCurrentDeviceType();
|
|
45770
|
+
const keepBleConnection = (env === 'react-native' || env === 'desktop-web-ble') &&
|
|
45771
|
+
this.isProtocolV2() &&
|
|
45772
|
+
(deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo);
|
|
45773
|
+
yield ((_a = this.deviceConnector) === null || _a === void 0 ? void 0 : _a.release(this.mainId, false, this.keepSession || keepBleConnection));
|
|
45774
|
+
this.releasedBleConnection = keepBleConnection;
|
|
45754
45775
|
}
|
|
45755
45776
|
catch (err) {
|
|
45756
45777
|
Log$i.error('[Device] release error: ', err);
|
|
@@ -46359,6 +46380,7 @@ class Device extends events.exports {
|
|
|
46359
46380
|
}
|
|
46360
46381
|
markTransportDisconnected() {
|
|
46361
46382
|
this.deviceAcquired = false;
|
|
46383
|
+
this.releasedBleConnection = false;
|
|
46362
46384
|
this.invalidateProtocolV2RuntimeState();
|
|
46363
46385
|
}
|
|
46364
46386
|
invalidateAfterWipe() {
|
|
@@ -46583,7 +46605,7 @@ class Device extends events.exports {
|
|
|
46583
46605
|
Log$i.debug('Protocol V2 fallback cancel error', cancelError);
|
|
46584
46606
|
}));
|
|
46585
46607
|
}
|
|
46586
|
-
else if (!acquired) {
|
|
46608
|
+
else if (!acquired && !this.releasedBleConnection) {
|
|
46587
46609
|
if (mainId && (deviceConnector === null || deviceConnector === void 0 ? void 0 : deviceConnector.disconnect)) {
|
|
46588
46610
|
Log$i.debug('interruptionFromUser: disconnecting device without acquire, mainId:', mainId);
|
|
46589
46611
|
yield deviceConnector.disconnect(mainId);
|
|
@@ -52533,11 +52555,276 @@ const INSTALLABLE_FIRMWARE_TARGET_IDS = new Set([
|
|
|
52533
52555
|
]);
|
|
52534
52556
|
new Map(Object.entries(ProtocolV2FirmwareTargetType).flatMap(([key, value]) => INSTALLABLE_FIRMWARE_TARGET_IDS.has(value) ? [[key, value]] : []));
|
|
52535
52557
|
|
|
52558
|
+
const isProtocolV2UiEnabled = (method) => method.protocolV2UiMode !== 'none';
|
|
52559
|
+
const getDisplayState = (value) => {
|
|
52560
|
+
const visited = new Set();
|
|
52561
|
+
let seen = false;
|
|
52562
|
+
let enabled = false;
|
|
52563
|
+
const visit = (current) => {
|
|
52564
|
+
if (current == null || typeof current !== 'object')
|
|
52565
|
+
return;
|
|
52566
|
+
if (visited.has(current))
|
|
52567
|
+
return;
|
|
52568
|
+
visited.add(current);
|
|
52569
|
+
if (Array.isArray(current)) {
|
|
52570
|
+
current.forEach(visit);
|
|
52571
|
+
return;
|
|
52572
|
+
}
|
|
52573
|
+
Object.entries(current).forEach(([key, item]) => {
|
|
52574
|
+
if ((key === 'show_display' || key === 'showOnOneKey') && typeof item === 'boolean') {
|
|
52575
|
+
seen = true;
|
|
52576
|
+
enabled || (enabled = item);
|
|
52577
|
+
return;
|
|
52578
|
+
}
|
|
52579
|
+
visit(item);
|
|
52580
|
+
});
|
|
52581
|
+
};
|
|
52582
|
+
visit(value);
|
|
52583
|
+
return { seen, enabled };
|
|
52584
|
+
};
|
|
52585
|
+
const createMethodInteraction = (reason, operation) => ({
|
|
52586
|
+
request: 'button',
|
|
52587
|
+
source: 'method-lifecycle',
|
|
52588
|
+
reason,
|
|
52589
|
+
completion: 'operation-completed',
|
|
52590
|
+
deviceOnly: true,
|
|
52591
|
+
operation,
|
|
52592
|
+
});
|
|
52593
|
+
const hasCipherConfirmation = (value) => {
|
|
52594
|
+
if (Array.isArray(value))
|
|
52595
|
+
return value.some(hasCipherConfirmation);
|
|
52596
|
+
if (value == null || typeof value !== 'object')
|
|
52597
|
+
return false;
|
|
52598
|
+
const params = value;
|
|
52599
|
+
return params.encrypt === true ? params.ask_on_encrypt === true : params.ask_on_decrypt === true;
|
|
52600
|
+
};
|
|
52601
|
+
const resolveProtocolV2UiInteraction = (method) => {
|
|
52602
|
+
if (method.protocolV2UiInteraction)
|
|
52603
|
+
return method.protocolV2UiInteraction;
|
|
52604
|
+
const operation = method.name;
|
|
52605
|
+
if (!operation)
|
|
52606
|
+
return undefined;
|
|
52607
|
+
const isAddress = /getAddress(?:ByLoop)?$/i.test(operation);
|
|
52608
|
+
const isPublicKey = /getPublicKey$/i.test(operation);
|
|
52609
|
+
if (isAddress || isPublicKey) {
|
|
52610
|
+
const paramsDisplay = getDisplayState(method.params);
|
|
52611
|
+
const payloadDisplay = getDisplayState(method.payload);
|
|
52612
|
+
const display = paramsDisplay.seen ? paramsDisplay : payloadDisplay;
|
|
52613
|
+
const shouldDisplay = display.seen ? display.enabled : isAddress;
|
|
52614
|
+
if (!shouldDisplay)
|
|
52615
|
+
return undefined;
|
|
52616
|
+
return createMethodInteraction(isAddress ? 'address-confirmation' : 'public-key-confirmation', operation);
|
|
52617
|
+
}
|
|
52618
|
+
if (/sign/i.test(operation) || /verifyMessage$/i.test(operation) || operation === 'lnurlAuth') {
|
|
52619
|
+
return createMethodInteraction('signing-confirmation', operation);
|
|
52620
|
+
}
|
|
52621
|
+
if (operation === 'nostrEncryptMessage' || operation === 'nostrDecryptMessage') {
|
|
52622
|
+
const display = getDisplayState(method.params);
|
|
52623
|
+
if (!display.enabled)
|
|
52624
|
+
return undefined;
|
|
52625
|
+
return createMethodInteraction('signing-confirmation', operation);
|
|
52626
|
+
}
|
|
52627
|
+
if (operation === 'cipherKeyValue' && hasCipherConfirmation(method.params)) {
|
|
52628
|
+
return createMethodInteraction('signing-confirmation', operation);
|
|
52629
|
+
}
|
|
52630
|
+
return undefined;
|
|
52631
|
+
};
|
|
52632
|
+
class ProtocolV2UiInteractionCoordinator {
|
|
52633
|
+
constructor(device, postMessage) {
|
|
52634
|
+
this.opened = false;
|
|
52635
|
+
this.closed = false;
|
|
52636
|
+
this.device = device;
|
|
52637
|
+
this.postMessage = postMessage;
|
|
52638
|
+
}
|
|
52639
|
+
enterMethodInteraction(interaction) {
|
|
52640
|
+
var _a, _b, _c, _d;
|
|
52641
|
+
this.methodInteraction = interaction;
|
|
52642
|
+
if (!interaction)
|
|
52643
|
+
return;
|
|
52644
|
+
const { request } = interaction, metadata = __rest(interaction, ["request"]);
|
|
52645
|
+
const interactionMeta = (_b = (_a = this.device).createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, request === 'pin' ? 'pin' : 'button', 'start');
|
|
52646
|
+
this.emit(request === 'pin' ? UI_REQUEST.REQUEST_PIN : UI_REQUEST.REQUEST_BUTTON, Object.assign(Object.assign({ device: this.device.toMessageObject() }, metadata), (interactionMeta ? { interaction: interactionMeta } : {})), `method:${request}:${interaction.reason}:${(_c = interaction.page) !== null && _c !== void 0 ? _c : ''}:${(_d = interaction.operation) !== null && _d !== void 0 ? _d : ''}`);
|
|
52647
|
+
}
|
|
52648
|
+
enterUnlockInteraction(method) {
|
|
52649
|
+
var _a, _b;
|
|
52650
|
+
const interaction = (_b = (_a = this.device).createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, 'pin', 'start');
|
|
52651
|
+
this.emit(UI_REQUEST.REQUEST_PIN, Object.assign({ device: this.device.toMessageObject(), source: 'unlock-coordinator', reason: 'device-locked', deviceOnly: true, method }, (interaction ? { interaction } : {})), `unlock:${method !== null && method !== void 0 ? method : ''}`);
|
|
52652
|
+
return interaction;
|
|
52653
|
+
}
|
|
52654
|
+
resumeMethodInteraction() {
|
|
52655
|
+
this.enterMethodInteraction(this.methodInteraction);
|
|
52656
|
+
}
|
|
52657
|
+
close(options = {}) {
|
|
52658
|
+
var _a, _b, _c, _d;
|
|
52659
|
+
if ((!options.protocolV2Operation && !this.device.isProtocolV2()) ||
|
|
52660
|
+
(!options.ensureOperationClose &&
|
|
52661
|
+
!this.opened &&
|
|
52662
|
+
!((_b = (_a = this.device).hasOpenProtocolV2UiInteraction) === null || _b === void 0 ? void 0 : _b.call(_a))) ||
|
|
52663
|
+
this.closed)
|
|
52664
|
+
return false;
|
|
52665
|
+
this.closed = true;
|
|
52666
|
+
const interaction = (_d = (_c = this.device).finishProtocolV2UiInteraction) === null || _d === void 0 ? void 0 : _d.call(_c, 'succeeded', {
|
|
52667
|
+
ensureMetadata: options.ensureOperationClose,
|
|
52668
|
+
});
|
|
52669
|
+
const device = this.device.toMessageObject();
|
|
52670
|
+
this.postMessage(interaction
|
|
52671
|
+
? createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW, Object.assign(Object.assign({}, interaction), (device ? { device } : {})))
|
|
52672
|
+
: createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW));
|
|
52673
|
+
return true;
|
|
52674
|
+
}
|
|
52675
|
+
emit(type, payload, phase) {
|
|
52676
|
+
if (!this.device.isProtocolV2() || this.closed || this.currentPhase === phase)
|
|
52677
|
+
return;
|
|
52678
|
+
this.currentPhase = phase;
|
|
52679
|
+
this.opened = true;
|
|
52680
|
+
const message = type === UI_REQUEST.REQUEST_BUTTON
|
|
52681
|
+
? createUiMessage(UI_REQUEST.REQUEST_BUTTON, payload)
|
|
52682
|
+
: createUiMessage(UI_REQUEST.REQUEST_PIN, payload);
|
|
52683
|
+
this.postMessage(message);
|
|
52684
|
+
}
|
|
52685
|
+
}
|
|
52686
|
+
|
|
52536
52687
|
const Log$7 = getLogger(exports.LoggerNames.Core);
|
|
52688
|
+
const createProtocolV2UnlockContext = () => ({
|
|
52689
|
+
preflightCompleted: false,
|
|
52690
|
+
preflightStatusRefreshed: false,
|
|
52691
|
+
preflightMainPinSelected: false,
|
|
52692
|
+
});
|
|
52693
|
+
const resolvePreUnlockPinType = (method) => {
|
|
52694
|
+
var _a, _b;
|
|
52695
|
+
if (method.protocolV2PreUnlockPinType !== undefined) {
|
|
52696
|
+
return method.protocolV2PreUnlockPinType;
|
|
52697
|
+
}
|
|
52698
|
+
const targetsKnownHiddenWallet = method.useDevicePassphraseState &&
|
|
52699
|
+
((_a = method.payload) === null || _a === void 0 ? void 0 : _a.useEmptyPassphrase) !== true &&
|
|
52700
|
+
typeof ((_b = method.payload) === null || _b === void 0 ? void 0 : _b.passphraseState) === 'string' &&
|
|
52701
|
+
method.payload.passphraseState.length > 0;
|
|
52702
|
+
return targetsKnownHiddenWallet ? hdTransport.DeviceSessionPinType.Any : hdTransport.DeviceSessionPinType.Main;
|
|
52703
|
+
};
|
|
52704
|
+
function runMethodWithUnlockPolicy(method, device, options = {}) {
|
|
52705
|
+
var _a, _b, _c;
|
|
52706
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52707
|
+
const { context = createProtocolV2UnlockContext(), uiCoordinator, afterStatusBeforeUnlock, prepare, run: configuredRun, } = options;
|
|
52708
|
+
const run = configuredRun !== null && configuredRun !== void 0 ? configuredRun : (() => method.run());
|
|
52709
|
+
method.protocolV2UnlockContext = context;
|
|
52710
|
+
const shouldEmitUi = isProtocolV2UiEnabled(method);
|
|
52711
|
+
const shouldCoordinateUi = shouldEmitUi && uiCoordinator !== undefined;
|
|
52712
|
+
const requiresPreUnlock = device.isProtocolV2() &&
|
|
52713
|
+
(method.useDevicePassphraseState || method.unlockPolicy === 'unlock-before-run') &&
|
|
52714
|
+
((_a = device.state) === null || _a === void 0 ? void 0 : _a.status.initialized) !== false &&
|
|
52715
|
+
!((_b = device.isBootloader) === null || _b === void 0 ? void 0 : _b.call(device)) &&
|
|
52716
|
+
!((_c = device.isRomloader) === null || _c === void 0 ? void 0 : _c.call(device));
|
|
52717
|
+
if (requiresPreUnlock && !context.preflightCompleted) {
|
|
52718
|
+
const status = yield refreshProtocolV2DeviceStatus(device);
|
|
52719
|
+
if (typeof (status === null || status === void 0 ? void 0 : status.unlocked) !== 'boolean') {
|
|
52720
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 DeviceStatus did not report an explicit unlock state.');
|
|
52721
|
+
}
|
|
52722
|
+
yield (afterStatusBeforeUnlock === null || afterStatusBeforeUnlock === void 0 ? void 0 : afterStatusBeforeUnlock());
|
|
52723
|
+
if (!status.unlocked) {
|
|
52724
|
+
const preUnlockPinType = resolvePreUnlockPinType(method);
|
|
52725
|
+
const unlockInteraction = shouldCoordinateUi
|
|
52726
|
+
? uiCoordinator.enterUnlockInteraction(method.name)
|
|
52727
|
+
: undefined;
|
|
52728
|
+
const unlockedStatus = yield device.unlockDevice(preUnlockPinType, shouldCoordinateUi
|
|
52729
|
+
? { emitUiEvent: false, interaction: unlockInteraction }
|
|
52730
|
+
: {
|
|
52731
|
+
source: 'unlock-coordinator',
|
|
52732
|
+
reason: 'device-locked',
|
|
52733
|
+
deviceOnly: true,
|
|
52734
|
+
method: method.name,
|
|
52735
|
+
});
|
|
52736
|
+
if ((unlockedStatus === null || unlockedStatus === void 0 ? void 0 : unlockedStatus.unlocked) !== true) {
|
|
52737
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 device remained locked after the unlock flow.');
|
|
52738
|
+
}
|
|
52739
|
+
context.preflightMainPinSelected = preUnlockPinType === hdTransport.DeviceSessionPinType.Main;
|
|
52740
|
+
Log$7.debug('Protocol V2 pre-unlock completed', { method: method.name });
|
|
52741
|
+
}
|
|
52742
|
+
context.preflightStatusRefreshed = true;
|
|
52743
|
+
context.preflightCompleted = true;
|
|
52744
|
+
}
|
|
52745
|
+
yield (prepare === null || prepare === void 0 ? void 0 : prepare());
|
|
52746
|
+
if (shouldCoordinateUi) {
|
|
52747
|
+
uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
|
|
52748
|
+
}
|
|
52749
|
+
return run();
|
|
52750
|
+
});
|
|
52751
|
+
}
|
|
52752
|
+
|
|
52753
|
+
const Log$6 = getLogger(exports.LoggerNames.Core);
|
|
52537
52754
|
const MIN_FILE_CHUNK_SIZE = 64;
|
|
52538
52755
|
const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
|
|
52539
52756
|
const FILE_TRANSFER_LOG_INTERVAL_MS = 10000;
|
|
52540
52757
|
const SESSION_ERROR$1 = 'session not found';
|
|
52758
|
+
const ASSET_FILE_WRITE_MIN_APPLICATION_VERSION = '1.0.3';
|
|
52759
|
+
const ASSET_FILE_WRITE_RESPONSE_TIMEOUT = 10000;
|
|
52760
|
+
function createProtocolV2AssetFileWriteRecovery(method) {
|
|
52761
|
+
var _a, _b, _c, _d;
|
|
52762
|
+
const { device } = method;
|
|
52763
|
+
const expectedSerialNo = (_b = (_a = device.state) === null || _a === void 0 ? void 0 : _a.identity) === null || _b === void 0 ? void 0 : _b.serialNo;
|
|
52764
|
+
const expectedDeviceType = (_d = (_c = device.state) === null || _c === void 0 ? void 0 : _c.identity) === null || _d === void 0 ? void 0 : _d.deviceType;
|
|
52765
|
+
return () => __awaiter(this, void 0, void 0, function* () {
|
|
52766
|
+
var _e, _f, _g, _h, _j, _k, _l, _m;
|
|
52767
|
+
if ((_e = method.abortSignal) === null || _e === void 0 ? void 0 : _e.aborted) {
|
|
52768
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
|
|
52769
|
+
}
|
|
52770
|
+
if (!expectedSerialNo) {
|
|
52771
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
52772
|
+
}
|
|
52773
|
+
yield device.acquire('V2', { throwOnRunPromiseError: true });
|
|
52774
|
+
if ((_f = method.abortSignal) === null || _f === void 0 ? void 0 : _f.aborted) {
|
|
52775
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
|
|
52776
|
+
}
|
|
52777
|
+
yield device.initialize();
|
|
52778
|
+
if (!device.isProtocolV2() ||
|
|
52779
|
+
((_g = device.state) === null || _g === void 0 ? void 0 : _g.identity.serialNo) !== expectedSerialNo ||
|
|
52780
|
+
((_h = device.state) === null || _h === void 0 ? void 0 : _h.identity.deviceType) !== expectedDeviceType ||
|
|
52781
|
+
!['normal', 'notInitialized'].includes((_k = (_j = device.state) === null || _j === void 0 ? void 0 : _j.status.mode) !== null && _k !== void 0 ? _k : '')) {
|
|
52782
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
52783
|
+
}
|
|
52784
|
+
if ((_l = method.abortSignal) === null || _l === void 0 ? void 0 : _l.aborted) {
|
|
52785
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
|
|
52786
|
+
}
|
|
52787
|
+
yield runMethodWithUnlockPolicy({
|
|
52788
|
+
name: method.name,
|
|
52789
|
+
unlockPolicy: method.unlockPolicy,
|
|
52790
|
+
useDevicePassphraseState: method.useDevicePassphraseState,
|
|
52791
|
+
protocolV2PreUnlockPinType: method.protocolV2PreUnlockPinType,
|
|
52792
|
+
protocolV2UiMode: method.protocolV2UiMode,
|
|
52793
|
+
payload: method.payload,
|
|
52794
|
+
params: undefined,
|
|
52795
|
+
run: () => Promise.resolve(undefined),
|
|
52796
|
+
}, device, { uiCoordinator: new ProtocolV2UiInteractionCoordinator(device, method.postMessage) });
|
|
52797
|
+
if ((_m = method.abortSignal) === null || _m === void 0 ? void 0 : _m.aborted) {
|
|
52798
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
|
|
52799
|
+
}
|
|
52800
|
+
DevicePool.emitter.emit(DEVICE.CONNECT, device);
|
|
52801
|
+
return device.commands;
|
|
52802
|
+
});
|
|
52803
|
+
}
|
|
52804
|
+
function shouldPipelineAssetFileWrite(options) {
|
|
52805
|
+
var _a, _b, _c, _d;
|
|
52806
|
+
const env = DataManager.getSettings('env');
|
|
52807
|
+
if (env !== 'react-native' && env !== 'desktop-web-ble')
|
|
52808
|
+
return false;
|
|
52809
|
+
if (options.overwrite !== true ||
|
|
52810
|
+
options.append ||
|
|
52811
|
+
((_a = options.offset) !== null && _a !== void 0 ? _a : 0) !== 0 ||
|
|
52812
|
+
((_b = options.paceMs) !== null && _b !== void 0 ? _b : 0) > 0 ||
|
|
52813
|
+
options.writeWithResponse === true ||
|
|
52814
|
+
!/^vol1:\/(?:wallpapers\/wallpaper\.okpkg|nft\/nft-[0-9a-f]{8}-[1-9][0-9]*\.okpkg|portfolio\/portfolio\.okpkg\.pending)$/.test(options.path)) {
|
|
52815
|
+
return false;
|
|
52816
|
+
}
|
|
52817
|
+
const { device } = options.commands;
|
|
52818
|
+
const deviceType = device === null || device === void 0 ? void 0 : device.getCurrentDeviceType();
|
|
52819
|
+
const firmwareVersion = (_c = device === null || device === void 0 ? void 0 : device.state) === null || _c === void 0 ? void 0 : _c.versions.firmware;
|
|
52820
|
+
const mode = (_d = device === null || device === void 0 ? void 0 : device.state) === null || _d === void 0 ? void 0 : _d.status.mode;
|
|
52821
|
+
return Boolean((device === null || device === void 0 ? void 0 : device.isProtocolV2()) &&
|
|
52822
|
+
(deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) &&
|
|
52823
|
+
(mode === 'normal' || mode === 'notInitialized') &&
|
|
52824
|
+
firmwareVersion &&
|
|
52825
|
+
semver__default["default"].valid(firmwareVersion) &&
|
|
52826
|
+
semver__default["default"].gte(firmwareVersion, ASSET_FILE_WRITE_MIN_APPLICATION_VERSION));
|
|
52827
|
+
}
|
|
52541
52828
|
function formatFileTransferRate(bytesPerSecond) {
|
|
52542
52829
|
return (Math.max(bytesPerSecond, 0) / 1024).toFixed(2);
|
|
52543
52830
|
}
|
|
@@ -52550,11 +52837,11 @@ function getFileTransferTransport() {
|
|
|
52550
52837
|
const env = DataManager.getSettings('env');
|
|
52551
52838
|
return env && DataManager.isBleConnect(env) ? 'BLE' : String(env !== null && env !== void 0 ? env : 'unknown');
|
|
52552
52839
|
}
|
|
52553
|
-
function logFileTransferMetrics({ transport, status, path, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, hostWriteElapsedMs, responseWaitElapsedMs, measuredAttempts, }) {
|
|
52840
|
+
function logFileTransferMetrics({ transport, status, path, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, hostWriteElapsedMs, responseWaitElapsedMs, measuredAttempts, fileWriteWindow, chunkSize, retryCount, }) {
|
|
52554
52841
|
const segmentedMetrics = measuredAttempts > 0
|
|
52555
52842
|
? ` hostWriteTotal=${(hostWriteElapsedMs / 1000).toFixed(2)}s responseWaitTotal=${(responseWaitElapsedMs / 1000).toFixed(2)}s measuredAttempts=${measuredAttempts}`
|
|
52556
52843
|
: '';
|
|
52557
|
-
Log$
|
|
52844
|
+
Log$6.log(`[FileWrite] metrics transport=${transport} status=${status} path=${path} bytes=${transferredBytes}/${totalBytes} elapsed=${(elapsedMs / 1000).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s${segmentedMetrics} window=${fileWriteWindow} chunk=${chunkSize} retry=${retryCount} averageSpeed=${formatFileTransferRate(getAverageFileTransferRate(transferredBytes, elapsedMs))} KiB/s`);
|
|
52558
52845
|
}
|
|
52559
52846
|
function isProtocolV2ResponseTimeout(error) {
|
|
52560
52847
|
var _a, _b;
|
|
@@ -52617,7 +52904,7 @@ function getConfirmedProgress(processed, total, written, length) {
|
|
|
52617
52904
|
return 100;
|
|
52618
52905
|
}
|
|
52619
52906
|
function writeProtocolV2File(options) {
|
|
52620
|
-
var _a, _b, _c, _d, _e, _f
|
|
52907
|
+
var _a, _b, _c, _d, _e, _f;
|
|
52621
52908
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52622
52909
|
(_a = options.throwIfAborted) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
52623
52910
|
const data = yield dataToUint8Array(options.data);
|
|
@@ -52630,15 +52917,21 @@ function writeProtocolV2File(options) {
|
|
|
52630
52917
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `FilesystemFileWrite totalSize ${totalSize} is smaller than offset + data length ${startOffset + dataLength}`);
|
|
52631
52918
|
}
|
|
52632
52919
|
const defaultChunkSizeLimit = getProtocolV2FileChunkLimit(options.bleChunkSizeLimit);
|
|
52920
|
+
const pipelineAsset = totalSize === dataLength && shouldPipelineAssetFileWrite(options);
|
|
52633
52921
|
const configuredChunkSizeLimit = Number(options.chunkSizeLimit);
|
|
52634
52922
|
const chunkSizeLimit = Number.isFinite(configuredChunkSizeLimit) && configuredChunkSizeLimit > 0
|
|
52635
52923
|
? Math.floor(configuredChunkSizeLimit)
|
|
52636
52924
|
: defaultChunkSizeLimit;
|
|
52637
|
-
const chunkSize = normalizeChunkSize((_b = options.chunkSize) !== null && _b !== void 0 ? _b : options.chunkLen, chunkSizeLimit);
|
|
52925
|
+
const chunkSize = normalizeChunkSize((_b = options.chunkSize) !== null && _b !== void 0 ? _b : options.chunkLen, pipelineAsset ? Math.min(chunkSizeLimit, hdTransport.PROTOCOL_V2_BLE_FILE_CHUNK_SIZE) : chunkSizeLimit);
|
|
52926
|
+
const fileWriteWindow = pipelineAsset && dataLength > chunkSize ? hdTransport.PROTOCOL_V2_FILE_WRITE_PIPELINE_WINDOW : 1;
|
|
52638
52927
|
let written = 0;
|
|
52639
52928
|
let chunks = 0;
|
|
52640
52929
|
let lastMessage;
|
|
52641
|
-
|
|
52930
|
+
let { commands } = options;
|
|
52931
|
+
let retryCount = 0;
|
|
52932
|
+
const maxChunkRetries = Math.max(Math.floor((_c = options.maxChunkRetries) !== null && _c !== void 0 ? _c : 0), 0);
|
|
52933
|
+
const canRecoverPipeline = pipelineAsset && dataLength > chunkSize && options.recoverConnection;
|
|
52934
|
+
let startTime = Date.now();
|
|
52642
52935
|
let rateWindowStartedAt = startTime;
|
|
52643
52936
|
let rateWindowStartedBytes = 0;
|
|
52644
52937
|
let rateBytesPerSecond;
|
|
@@ -52648,26 +52941,151 @@ function writeProtocolV2File(options) {
|
|
|
52648
52941
|
let hostWriteElapsedMs = 0;
|
|
52649
52942
|
let responseWaitElapsedMs = 0;
|
|
52650
52943
|
let measuredAttempts = 0;
|
|
52944
|
+
const createRequest = (position) => {
|
|
52945
|
+
var _a, _b, _c, _d, _e;
|
|
52946
|
+
const chunk = data.slice(position, Math.min(position + chunkSize, dataLength));
|
|
52947
|
+
const offset = startOffset + position;
|
|
52948
|
+
const progress = (_c = (_a = options.uiPercentage) !== null && _a !== void 0 ? _a : (_b = options.getUiPercentage) === null || _b === void 0 ? void 0 : _b.call(options, {
|
|
52949
|
+
offset,
|
|
52950
|
+
chunkLength: chunk.byteLength,
|
|
52951
|
+
totalSize,
|
|
52952
|
+
})) !== null && _c !== void 0 ? _c : getDeviceTransferProgress(offset, offset + chunk.byteLength, totalSize);
|
|
52953
|
+
return {
|
|
52954
|
+
file: { path: options.path, offset, total_size: totalSize, data: chunk },
|
|
52955
|
+
overwrite: position === 0 ? (_d = options.overwrite) !== null && _d !== void 0 ? _d : false : false,
|
|
52956
|
+
append: (_e = options.append) !== null && _e !== void 0 ? _e : false,
|
|
52957
|
+
ui_percentage: progress,
|
|
52958
|
+
};
|
|
52959
|
+
};
|
|
52960
|
+
const confirmChunk = (response, offset, chunkLength) => {
|
|
52961
|
+
var _a, _b, _c, _d;
|
|
52962
|
+
const responseType = response.type;
|
|
52963
|
+
if (responseType && responseType !== 'FilesystemFile') {
|
|
52964
|
+
const responseError = (_a = response.message) === null || _a === void 0 ? void 0 : _a.error;
|
|
52965
|
+
if (typeof responseError === 'string' && responseError.includes(SESSION_ERROR$1)) {
|
|
52966
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, SESSION_ERROR$1);
|
|
52967
|
+
}
|
|
52968
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `FilesystemFileWrite received unexpected response ${responseType}`);
|
|
52969
|
+
}
|
|
52970
|
+
(_b = options.throwIfAborted) === null || _b === void 0 ? void 0 : _b.call(options);
|
|
52971
|
+
lastMessage = response.message;
|
|
52972
|
+
const rawProcessedByte = (_c = response.message) === null || _c === void 0 ? void 0 : _c.processed_byte;
|
|
52973
|
+
const processedByte = Number(rawProcessedByte);
|
|
52974
|
+
if (rawProcessedByte !== undefined &&
|
|
52975
|
+
(!Number.isFinite(processedByte) ||
|
|
52976
|
+
processedByte <= offset ||
|
|
52977
|
+
processedByte > offset + chunkLength)) {
|
|
52978
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `FilesystemFileWrite invalid processed_byte ${processedByte}`);
|
|
52979
|
+
}
|
|
52980
|
+
written = rawProcessedByte === undefined ? written + chunkLength : processedByte - startOffset;
|
|
52981
|
+
chunks += 1;
|
|
52982
|
+
const now = Date.now();
|
|
52983
|
+
lastConfirmedAt = now;
|
|
52984
|
+
const elapsedMs = now - startTime;
|
|
52985
|
+
const transferredBytes = Math.min(written, dataLength);
|
|
52986
|
+
const rateWindowElapsedMs = now - rateWindowStartedAt;
|
|
52987
|
+
if (rateWindowElapsedMs >= FILE_TRANSFER_RATE_WINDOW_MS) {
|
|
52988
|
+
const rateWindowBytes = Math.max(transferredBytes - rateWindowStartedBytes, 0);
|
|
52989
|
+
rateBytesPerSecond = Math.round((rateWindowBytes / rateWindowElapsedMs) * 1000);
|
|
52990
|
+
rateWindowStartedAt = now;
|
|
52991
|
+
rateWindowStartedBytes = transferredBytes;
|
|
52992
|
+
}
|
|
52993
|
+
else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
|
|
52994
|
+
rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
|
|
52995
|
+
}
|
|
52996
|
+
(_d = options.onProgress) === null || _d === void 0 ? void 0 : _d.call(options, Object.assign({ progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength), transferredBytes, totalBytes: dataLength, rateBytesPerSecond,
|
|
52997
|
+
elapsedMs }, (retryCount > 0 ? { retryCount } : {})));
|
|
52998
|
+
const logWindowElapsedMs = now - logWindowStartedAt;
|
|
52999
|
+
if (logWindowElapsedMs >= FILE_TRANSFER_LOG_INTERVAL_MS && transferredBytes < dataLength) {
|
|
53000
|
+
const logWindowBytes = Math.max(transferredBytes - logWindowStartedBytes, 0);
|
|
53001
|
+
logFileTransferMetrics({
|
|
53002
|
+
transport,
|
|
53003
|
+
status: 'progress',
|
|
53004
|
+
path: options.path,
|
|
53005
|
+
transferredBytes,
|
|
53006
|
+
totalBytes: dataLength,
|
|
53007
|
+
elapsedMs,
|
|
53008
|
+
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
53009
|
+
hostWriteElapsedMs,
|
|
53010
|
+
responseWaitElapsedMs,
|
|
53011
|
+
measuredAttempts,
|
|
53012
|
+
fileWriteWindow,
|
|
53013
|
+
chunkSize,
|
|
53014
|
+
retryCount,
|
|
53015
|
+
});
|
|
53016
|
+
logWindowStartedAt = now;
|
|
53017
|
+
logWindowStartedBytes = transferredBytes;
|
|
53018
|
+
}
|
|
53019
|
+
};
|
|
52651
53020
|
const transport = getFileTransferTransport();
|
|
52652
|
-
Log$
|
|
52653
|
-
|
|
53021
|
+
Log$6.log(`[FileWrite] started transport=${transport} path=${options.path} bytes=${dataLength} offset=${startOffset} chunk=${chunkSize}`);
|
|
53022
|
+
const writeAttempt = () => __awaiter(this, void 0, void 0, function* () {
|
|
53023
|
+
var _g, _h, _j, _k, _l, _m, _o, _p;
|
|
53024
|
+
(_g = options.throwIfAborted) === null || _g === void 0 ? void 0 : _g.call(options);
|
|
53025
|
+
const attemptRetryCount = retryCount;
|
|
53026
|
+
if (fileWriteWindow === hdTransport.PROTOCOL_V2_FILE_WRITE_PIPELINE_WINDOW) {
|
|
53027
|
+
Log$6.debug('[FileWrite] BLE asset pipeline', {
|
|
53028
|
+
path: options.path,
|
|
53029
|
+
window: fileWriteWindow,
|
|
53030
|
+
chunkSize,
|
|
53031
|
+
retryCount,
|
|
53032
|
+
applicationVersion: (_j = (_h = commands.device) === null || _h === void 0 ? void 0 : _h.state) === null || _j === void 0 ? void 0 : _j.versions.firmware,
|
|
53033
|
+
});
|
|
53034
|
+
let sendOffset = chunkSize;
|
|
53035
|
+
let interrupted = false;
|
|
53036
|
+
let interruption;
|
|
53037
|
+
const response = yield commands.typedCall('FilesystemFileWrite', 'FilesystemFile', createRequest(0), {
|
|
53038
|
+
timeoutMs: (_k = options.timeoutMs) !== null && _k !== void 0 ? _k : ASSET_FILE_WRITE_RESPONSE_TIMEOUT,
|
|
53039
|
+
writeWithResponse: false,
|
|
53040
|
+
fileWritePipeline: {
|
|
53041
|
+
next: () => {
|
|
53042
|
+
var _a;
|
|
53043
|
+
if (interrupted || attemptRetryCount !== retryCount || sendOffset >= dataLength)
|
|
53044
|
+
return Promise.resolve(undefined);
|
|
53045
|
+
try {
|
|
53046
|
+
(_a = options.throwIfAborted) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
53047
|
+
const request = createRequest(sendOffset);
|
|
53048
|
+
sendOffset += request.file.data.byteLength;
|
|
53049
|
+
return Promise.resolve(request);
|
|
53050
|
+
}
|
|
53051
|
+
catch (error) {
|
|
53052
|
+
interrupted = true;
|
|
53053
|
+
interruption = error;
|
|
53054
|
+
return Promise.resolve(undefined);
|
|
53055
|
+
}
|
|
53056
|
+
},
|
|
53057
|
+
onResponse: confirmed => {
|
|
53058
|
+
if (interrupted || attemptRetryCount !== retryCount)
|
|
53059
|
+
return;
|
|
53060
|
+
try {
|
|
53061
|
+
const offset = startOffset + written;
|
|
53062
|
+
const length = Math.min(chunkSize, dataLength - written);
|
|
53063
|
+
if (Number(confirmed.message.processed_byte) !== offset + length) {
|
|
53064
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'FilesystemFileWrite pipeline did not confirm the complete chunk');
|
|
53065
|
+
}
|
|
53066
|
+
confirmChunk(confirmed, offset, length);
|
|
53067
|
+
}
|
|
53068
|
+
catch (error) {
|
|
53069
|
+
interrupted = true;
|
|
53070
|
+
interruption = error;
|
|
53071
|
+
}
|
|
53072
|
+
},
|
|
53073
|
+
},
|
|
53074
|
+
});
|
|
53075
|
+
(_l = options.throwIfAborted) === null || _l === void 0 ? void 0 : _l.call(options);
|
|
53076
|
+
if (interrupted)
|
|
53077
|
+
throw interruption;
|
|
53078
|
+
if (response.type !== 'FilesystemFile' ||
|
|
53079
|
+
Number(response.message.processed_byte) !== startOffset + dataLength ||
|
|
53080
|
+
written !== dataLength) {
|
|
53081
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'FilesystemFileWrite pipeline ended before the complete file was confirmed');
|
|
53082
|
+
}
|
|
53083
|
+
}
|
|
52654
53084
|
while (written < dataLength) {
|
|
52655
|
-
(
|
|
52656
|
-
const
|
|
52657
|
-
const offset
|
|
52658
|
-
|
|
52659
|
-
offset,
|
|
52660
|
-
chunkLength: chunk.byteLength,
|
|
52661
|
-
totalSize,
|
|
52662
|
-
})) !== null && _f !== void 0 ? _f : getDeviceTransferProgress(offset, offset + chunk.byteLength, totalSize);
|
|
52663
|
-
const request = {
|
|
52664
|
-
file: { path: options.path, offset, total_size: totalSize, data: chunk },
|
|
52665
|
-
overwrite: chunks === 0 ? (_g = options.overwrite) !== null && _g !== void 0 ? _g : false : false,
|
|
52666
|
-
append: (_h = options.append) !== null && _h !== void 0 ? _h : false,
|
|
52667
|
-
ui_percentage: progress,
|
|
52668
|
-
};
|
|
52669
|
-
const maxChunkRetries = Math.max(Math.floor((_j = options.maxChunkRetries) !== null && _j !== void 0 ? _j : 0), 0);
|
|
52670
|
-
let retryCount = 0;
|
|
53085
|
+
(_m = options.throwIfAborted) === null || _m === void 0 ? void 0 : _m.call(options);
|
|
53086
|
+
const request = createRequest(written);
|
|
53087
|
+
const { offset, data: chunk } = request.file;
|
|
53088
|
+
let chunkRetryCount = 0;
|
|
52671
53089
|
let response;
|
|
52672
53090
|
let isWritePending = true;
|
|
52673
53091
|
while (isWritePending) {
|
|
@@ -52676,7 +53094,7 @@ function writeProtocolV2File(options) {
|
|
|
52676
53094
|
try {
|
|
52677
53095
|
const callOptions = options.writeWithResponse === undefined
|
|
52678
53096
|
? {
|
|
52679
|
-
timeoutMs: options.timeoutMs,
|
|
53097
|
+
timeoutMs: (_o = options.timeoutMs) !== null && _o !== void 0 ? _o : (canRecoverPipeline ? ASSET_FILE_WRITE_RESPONSE_TIMEOUT : undefined),
|
|
52680
53098
|
onWriteCompleted: ({ elapsedMs }) => {
|
|
52681
53099
|
currentHostWriteElapsedMs = elapsedMs;
|
|
52682
53100
|
responseWaitStartedAt = Date.now();
|
|
@@ -52686,14 +53104,16 @@ function writeProtocolV2File(options) {
|
|
|
52686
53104
|
currentHostWriteElapsedMs = elapsedMs;
|
|
52687
53105
|
responseWaitStartedAt = Date.now();
|
|
52688
53106
|
} });
|
|
52689
|
-
response = yield
|
|
53107
|
+
response = yield commands.typedCall('FilesystemFileWrite', 'FilesystemFile', request, callOptions);
|
|
52690
53108
|
isWritePending = false;
|
|
52691
53109
|
}
|
|
52692
53110
|
catch (error) {
|
|
52693
|
-
if (
|
|
53111
|
+
if (canRecoverPipeline ||
|
|
53112
|
+
chunkRetryCount >= maxChunkRetries ||
|
|
53113
|
+
!isProtocolV2ResponseTimeout(error))
|
|
52694
53114
|
throw error;
|
|
52695
|
-
|
|
52696
|
-
(
|
|
53115
|
+
chunkRetryCount += 1;
|
|
53116
|
+
(_p = options.throwIfAborted) === null || _p === void 0 ? void 0 : _p.call(options);
|
|
52697
53117
|
}
|
|
52698
53118
|
finally {
|
|
52699
53119
|
if (currentHostWriteElapsedMs !== undefined && responseWaitStartedAt !== undefined) {
|
|
@@ -52706,92 +53126,71 @@ function writeProtocolV2File(options) {
|
|
|
52706
53126
|
if (!response) {
|
|
52707
53127
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'FilesystemFileWrite completed without a response');
|
|
52708
53128
|
}
|
|
52709
|
-
|
|
52710
|
-
if (
|
|
52711
|
-
|
|
52712
|
-
|
|
52713
|
-
|
|
52714
|
-
}
|
|
52715
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `FilesystemFileWrite received unexpected response ${responseType}`);
|
|
52716
|
-
}
|
|
52717
|
-
(_m = options.throwIfAborted) === null || _m === void 0 ? void 0 : _m.call(options);
|
|
52718
|
-
lastMessage = response.message;
|
|
52719
|
-
const rawProcessedByte = (_o = response.message) === null || _o === void 0 ? void 0 : _o.processed_byte;
|
|
52720
|
-
const processedByte = Number(rawProcessedByte);
|
|
52721
|
-
if (rawProcessedByte !== undefined &&
|
|
52722
|
-
(!Number.isFinite(processedByte) ||
|
|
52723
|
-
processedByte <= offset ||
|
|
52724
|
-
processedByte > offset + chunk.byteLength)) {
|
|
52725
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `FilesystemFileWrite invalid processed_byte ${processedByte}`);
|
|
53129
|
+
confirmChunk(response, offset, chunk.byteLength);
|
|
53130
|
+
if (options.paceMs && options.paceMs > 0) {
|
|
53131
|
+
yield new Promise(resolve => {
|
|
53132
|
+
setTimeout(resolve, options.paceMs);
|
|
53133
|
+
});
|
|
52726
53134
|
}
|
|
52727
|
-
|
|
52728
|
-
|
|
52729
|
-
|
|
53135
|
+
}
|
|
53136
|
+
});
|
|
53137
|
+
while (true) {
|
|
53138
|
+
try {
|
|
53139
|
+
yield writeAttempt();
|
|
53140
|
+
break;
|
|
53141
|
+
}
|
|
53142
|
+
catch (error) {
|
|
52730
53143
|
const now = Date.now();
|
|
52731
|
-
|
|
52732
|
-
const
|
|
52733
|
-
const
|
|
52734
|
-
|
|
52735
|
-
|
|
52736
|
-
|
|
52737
|
-
|
|
52738
|
-
|
|
52739
|
-
rateWindowStartedBytes = transferredBytes;
|
|
52740
|
-
}
|
|
52741
|
-
else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
|
|
52742
|
-
rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
|
|
52743
|
-
}
|
|
52744
|
-
(_p = options.onProgress) === null || _p === void 0 ? void 0 : _p.call(options, {
|
|
52745
|
-
progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
|
|
52746
|
-
transferredBytes,
|
|
53144
|
+
const elapsedMs = Math.max(now - startTime, 0);
|
|
53145
|
+
const logWindowElapsedMs = Math.max(now - logWindowStartedAt, 0);
|
|
53146
|
+
const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
|
|
53147
|
+
logFileTransferMetrics({
|
|
53148
|
+
transport,
|
|
53149
|
+
status: 'failed',
|
|
53150
|
+
path: options.path,
|
|
53151
|
+
transferredBytes: written,
|
|
52747
53152
|
totalBytes: dataLength,
|
|
52748
|
-
rateBytesPerSecond,
|
|
52749
53153
|
elapsedMs,
|
|
53154
|
+
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
53155
|
+
hostWriteElapsedMs,
|
|
53156
|
+
responseWaitElapsedMs,
|
|
53157
|
+
measuredAttempts,
|
|
53158
|
+
fileWriteWindow,
|
|
53159
|
+
chunkSize,
|
|
53160
|
+
retryCount,
|
|
52750
53161
|
});
|
|
52751
|
-
|
|
52752
|
-
|
|
52753
|
-
|
|
52754
|
-
|
|
52755
|
-
transport,
|
|
52756
|
-
status: 'progress',
|
|
52757
|
-
path: options.path,
|
|
52758
|
-
transferredBytes,
|
|
52759
|
-
totalBytes: dataLength,
|
|
52760
|
-
elapsedMs,
|
|
52761
|
-
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
52762
|
-
hostWriteElapsedMs,
|
|
52763
|
-
responseWaitElapsedMs,
|
|
52764
|
-
measuredAttempts,
|
|
52765
|
-
});
|
|
52766
|
-
logWindowStartedAt = now;
|
|
52767
|
-
logWindowStartedBytes = transferredBytes;
|
|
52768
|
-
}
|
|
52769
|
-
if (options.paceMs && options.paceMs > 0) {
|
|
52770
|
-
yield new Promise(resolve => {
|
|
52771
|
-
setTimeout(resolve, options.paceMs);
|
|
52772
|
-
});
|
|
53162
|
+
if (!canRecoverPipeline ||
|
|
53163
|
+
retryCount >= maxChunkRetries ||
|
|
53164
|
+
!isProtocolV2ResponseTimeout(error)) {
|
|
53165
|
+
throw error;
|
|
52773
53166
|
}
|
|
53167
|
+
(_d = options.throwIfAborted) === null || _d === void 0 ? void 0 : _d.call(options);
|
|
53168
|
+
retryCount += 1;
|
|
53169
|
+
Log$6.log(`[FileWrite] retry=${retryCount}/${maxChunkRetries} restarting window=${fileWriteWindow} after reconnect path=${options.path}`);
|
|
53170
|
+
(_e = options.onProgress) === null || _e === void 0 ? void 0 : _e.call(options, {
|
|
53171
|
+
progress: 0,
|
|
53172
|
+
transferredBytes: 0,
|
|
53173
|
+
totalBytes: dataLength,
|
|
53174
|
+
elapsedMs: 0,
|
|
53175
|
+
retryCount,
|
|
53176
|
+
});
|
|
53177
|
+
commands = yield canRecoverPipeline();
|
|
53178
|
+
(_f = options.throwIfAborted) === null || _f === void 0 ? void 0 : _f.call(options);
|
|
53179
|
+
written = 0;
|
|
53180
|
+
chunks = 0;
|
|
53181
|
+
lastMessage = undefined;
|
|
53182
|
+
startTime = Date.now();
|
|
53183
|
+
lastConfirmedAt = startTime;
|
|
53184
|
+
rateWindowStartedAt = startTime;
|
|
53185
|
+
rateWindowStartedBytes = 0;
|
|
53186
|
+
rateBytesPerSecond = undefined;
|
|
53187
|
+
logWindowStartedAt = startTime;
|
|
53188
|
+
logWindowStartedBytes = 0;
|
|
53189
|
+
hostWriteElapsedMs = 0;
|
|
53190
|
+
responseWaitElapsedMs = 0;
|
|
53191
|
+
measuredAttempts = 0;
|
|
52774
53192
|
}
|
|
52775
53193
|
}
|
|
52776
|
-
catch (error) {
|
|
52777
|
-
const now = Date.now();
|
|
52778
|
-
const elapsedMs = Math.max(now - startTime, 0);
|
|
52779
|
-
const logWindowElapsedMs = Math.max(now - logWindowStartedAt, 0);
|
|
52780
|
-
const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
|
|
52781
|
-
logFileTransferMetrics({
|
|
52782
|
-
transport,
|
|
52783
|
-
status: 'failed',
|
|
52784
|
-
path: options.path,
|
|
52785
|
-
transferredBytes: written,
|
|
52786
|
-
totalBytes: dataLength,
|
|
52787
|
-
elapsedMs,
|
|
52788
|
-
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
52789
|
-
hostWriteElapsedMs,
|
|
52790
|
-
responseWaitElapsedMs,
|
|
52791
|
-
measuredAttempts,
|
|
52792
|
-
});
|
|
52793
|
-
throw error;
|
|
52794
|
-
}
|
|
52795
53194
|
const elapsedMs = Math.max(lastConfirmedAt - startTime, 0);
|
|
52796
53195
|
const logWindowElapsedMs = Math.max(lastConfirmedAt - logWindowStartedAt, 0);
|
|
52797
53196
|
const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
|
|
@@ -52806,12 +53205,16 @@ function writeProtocolV2File(options) {
|
|
|
52806
53205
|
hostWriteElapsedMs,
|
|
52807
53206
|
responseWaitElapsedMs,
|
|
52808
53207
|
measuredAttempts,
|
|
53208
|
+
fileWriteWindow,
|
|
53209
|
+
chunkSize,
|
|
53210
|
+
retryCount,
|
|
52809
53211
|
});
|
|
52810
53212
|
return Object.assign(Object.assign({}, lastMessage), { path: options.path, offset: startOffset, total_size: totalSize, processed_byte: startOffset + written, chunks });
|
|
52811
53213
|
});
|
|
52812
53214
|
}
|
|
52813
53215
|
|
|
52814
|
-
const Log$
|
|
53216
|
+
const Log$5 = getLogger(exports.LoggerNames.Method);
|
|
53217
|
+
const TransferLog = getLogger(exports.LoggerNames.Core);
|
|
52815
53218
|
const SESSION_ERROR = 'session not found';
|
|
52816
53219
|
const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
|
|
52817
53220
|
const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
|
|
@@ -52836,6 +53239,7 @@ const PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT = 3;
|
|
|
52836
53239
|
const PROTOCOL_V2_RESOURCE_HEADER_RECOVERY_LIMIT = 2;
|
|
52837
53240
|
const PROTOCOL_V2_BLE_FILE_WRITE_WINDOW_MIN_BOOTLOADER_VERSION = '1.0.3';
|
|
52838
53241
|
const PROTOCOL_V2_TRANSFER_PROGRESS_HEARTBEAT_MS = 1000;
|
|
53242
|
+
const PROTOCOL_V2_TRANSFER_LOG_INTERVAL_MS = 10000;
|
|
52839
53243
|
const PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE = 'FirmwareInstallStatusConflict';
|
|
52840
53244
|
const PROTOCOL_V2_INSTALL_FAILED_CODE = 'FirmwareInstallFailed';
|
|
52841
53245
|
const PROTOCOL_V2_INSTALL_TIMEOUT_CODE = 'FirmwareInstallTimeout';
|
|
@@ -53143,7 +53547,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53143
53547
|
this.protocolV2InstallTerminalSuccessObserved = false;
|
|
53144
53548
|
this.protocolV2LastTransferProgressAt = 0;
|
|
53145
53549
|
this.protocolV2LastTransferredBytes = 0;
|
|
53146
|
-
this.protocolV2FileWriteWindowDisabled = false;
|
|
53147
53550
|
}
|
|
53148
53551
|
getSupportedProtocols() {
|
|
53149
53552
|
return ['V2'];
|
|
@@ -53316,7 +53719,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53316
53719
|
}
|
|
53317
53720
|
run() {
|
|
53318
53721
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53319
|
-
Log$
|
|
53722
|
+
Log$5.debug('FirmwareUpdateV4 strategy: Protocol V2');
|
|
53320
53723
|
return this.runProtocolV2();
|
|
53321
53724
|
});
|
|
53322
53725
|
}
|
|
@@ -53749,7 +54152,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
53749
54152
|
if (!observedVersion) {
|
|
53750
54153
|
const hasCompleteTargetEvidence = targetId !== undefined && this.protocolV2CompletedTargetIds.has(targetId);
|
|
53751
54154
|
if (hasCompleteTargetEvidence) {
|
|
53752
|
-
Log$
|
|
54155
|
+
Log$5.warn(`Protocol V2 target ${target} has no observable final version; install completion is authoritative`);
|
|
53753
54156
|
}
|
|
53754
54157
|
else {
|
|
53755
54158
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareVerificationFailed, `Protocol V2 target ${target} has no observable final version after status fallback`);
|
|
@@ -54061,8 +54464,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54061
54464
|
const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
|
|
54062
54465
|
const chunks = [];
|
|
54063
54466
|
let offset = 0;
|
|
54064
|
-
while (offset <
|
|
54065
|
-
const readLen = Math.min(chunkSize,
|
|
54467
|
+
while (offset < PROTOCOL_V2_RESOURCE_PACKAGE_COMPARE_SIZE) {
|
|
54468
|
+
const readLen = Math.min(chunkSize, PROTOCOL_V2_RESOURCE_PACKAGE_COMPARE_SIZE - offset);
|
|
54066
54469
|
const res = yield typedCall('FilesystemFileRead', 'FilesystemFile', {
|
|
54067
54470
|
file: {
|
|
54068
54471
|
path: filePath,
|
|
@@ -54073,7 +54476,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54073
54476
|
ui_percentage: undefined,
|
|
54074
54477
|
});
|
|
54075
54478
|
const data = toProtocolV2Bytes((_d = res.message) === null || _d === void 0 ? void 0 : _d.data);
|
|
54076
|
-
if (data.byteLength === 0)
|
|
54479
|
+
if (data.byteLength === 0 || data.byteLength > readLen)
|
|
54077
54480
|
return null;
|
|
54078
54481
|
chunks.push(data);
|
|
54079
54482
|
offset += data.byteLength;
|
|
@@ -54119,7 +54522,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54119
54522
|
catch (error) {
|
|
54120
54523
|
if (isProtocolV2ResourceHeaderLinkError(error))
|
|
54121
54524
|
throw error;
|
|
54122
|
-
Log$
|
|
54525
|
+
Log$5.log(`[FirmwareUpdateV4] RESC bundle ${bundle.name} header check failed: `, error);
|
|
54123
54526
|
return false;
|
|
54124
54527
|
}
|
|
54125
54528
|
});
|
|
@@ -54133,11 +54536,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54133
54536
|
catch (error) {
|
|
54134
54537
|
this.throwIfAborted();
|
|
54135
54538
|
if (recovery.remaining <= 0) {
|
|
54136
|
-
Log$
|
|
54539
|
+
Log$5.log(`[FirmwareUpdateV4] RESC bundle ${bundle.name} header check lost the link; reconnect budget used up: `, getProtocolV2UnknownErrorText(error));
|
|
54137
54540
|
return false;
|
|
54138
54541
|
}
|
|
54139
54542
|
recovery.remaining -= 1;
|
|
54140
|
-
Log$
|
|
54543
|
+
Log$5.log(`[FirmwareUpdateV4] RESC bundle ${bundle.name} header check lost the link; reconnecting: `, getProtocolV2UnknownErrorText(error));
|
|
54141
54544
|
}
|
|
54142
54545
|
yield this.recoverProtocolV2FileTransfer();
|
|
54143
54546
|
this.throwIfAborted();
|
|
@@ -54165,11 +54568,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54165
54568
|
return ((_a = this.device.features) === null || _a === void 0 ? void 0 : _a.mode) === 'romloader';
|
|
54166
54569
|
}
|
|
54167
54570
|
rebootProtocolV2ToBootloader() {
|
|
54571
|
+
var _a;
|
|
54168
54572
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54169
54573
|
try {
|
|
54170
54574
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.AutoRebootToBootloader);
|
|
54171
54575
|
yield this.protocolV2Reboot(hdTransport.DeviceRebootType.Bootloader);
|
|
54172
54576
|
yield hdShared.wait(1000);
|
|
54577
|
+
if (this.isBleReconnect()) {
|
|
54578
|
+
yield ((_a = this.device.deviceConnector) === null || _a === void 0 ? void 0 : _a.disconnect(this.device.originalDescriptor.id));
|
|
54579
|
+
}
|
|
54173
54580
|
yield this.waitForProtocolV2BootloaderMode();
|
|
54174
54581
|
this.protocolV2ExecutionInLoader = true;
|
|
54175
54582
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
@@ -54179,7 +54586,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54179
54586
|
if (error instanceof hdShared.HardwareError) {
|
|
54180
54587
|
throw error;
|
|
54181
54588
|
}
|
|
54182
|
-
Log$
|
|
54589
|
+
Log$5.log('Protocol V2 auto go to bootloader mode failed: ', error);
|
|
54183
54590
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure);
|
|
54184
54591
|
}
|
|
54185
54592
|
});
|
|
@@ -54187,12 +54594,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54187
54594
|
enterProtocolV2BootloaderMode() {
|
|
54188
54595
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54189
54596
|
if (this.isProtocolV2RomloaderMode()) {
|
|
54190
|
-
Log$
|
|
54597
|
+
Log$5.debug('Protocol V2 device is in romloader mode; start firmware update directly');
|
|
54191
54598
|
this.protocolV2ExecutionInLoader = true;
|
|
54192
54599
|
return false;
|
|
54193
54600
|
}
|
|
54194
54601
|
if (this.isProtocolV2BootloaderMode()) {
|
|
54195
|
-
Log$
|
|
54602
|
+
Log$5.debug('Protocol V2 device is already in bootloader mode, skip reboot');
|
|
54196
54603
|
this.protocolV2ExecutionInLoader = true;
|
|
54197
54604
|
this.postTipMessage(exports.FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
54198
54605
|
return false;
|
|
@@ -54208,12 +54615,17 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54208
54615
|
while (Date.now() - startTime < timeout) {
|
|
54209
54616
|
try {
|
|
54210
54617
|
if (shouldReconnect) {
|
|
54211
|
-
|
|
54618
|
+
if (this.isBleReconnect()) {
|
|
54619
|
+
yield this.reconnectProtocolV2Device({ skipProtocolProbe: true });
|
|
54620
|
+
}
|
|
54621
|
+
else {
|
|
54622
|
+
yield this.reconnectProtocolV2Device();
|
|
54623
|
+
}
|
|
54212
54624
|
shouldReconnect = false;
|
|
54213
54625
|
}
|
|
54214
54626
|
const deviceInfo = yield requestProtocolV2DeviceInfo({
|
|
54215
54627
|
commands: this.device.getCommands(),
|
|
54216
|
-
timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
|
|
54628
|
+
timeoutMs: Math.min(this.getProtocolV2DeviceInfoTimeout(), PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT),
|
|
54217
54629
|
});
|
|
54218
54630
|
this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
|
|
54219
54631
|
const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT);
|
|
@@ -54228,7 +54640,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54228
54640
|
}
|
|
54229
54641
|
shouldReconnect = true;
|
|
54230
54642
|
lastError = error;
|
|
54231
|
-
Log$
|
|
54643
|
+
Log$5.log('Protocol V2 bootloader mode not ready, polling reconnect: ', error);
|
|
54232
54644
|
}
|
|
54233
54645
|
yield hdShared.wait(retryInterval);
|
|
54234
54646
|
}
|
|
@@ -54325,7 +54737,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54325
54737
|
const headerRecovery = { remaining: PROTOCOL_V2_RESOURCE_HEADER_RECOVERY_LIMIT };
|
|
54326
54738
|
for (const resource of resourceSources) {
|
|
54327
54739
|
if (yield this.isProtocolV2ResourceBundleUpToDateWithRecovery(resource, headerRecovery)) {
|
|
54328
|
-
Log$
|
|
54740
|
+
Log$5.log(`[FirmwareUpdateV4] skip RESC bundle ${resource.name}; already up to date`);
|
|
54329
54741
|
}
|
|
54330
54742
|
else {
|
|
54331
54743
|
resourcesToSync.push(resource);
|
|
@@ -54377,7 +54789,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54377
54789
|
rateBytesPerSecond,
|
|
54378
54790
|
elapsedMs,
|
|
54379
54791
|
});
|
|
54380
|
-
Log$
|
|
54792
|
+
Log$5.debug('[FirmwareUpdateV4] Protocol V2 transfer completed', {
|
|
54381
54793
|
files: resourcesToSync.length + installSources.length,
|
|
54382
54794
|
totalBytes: totalSize,
|
|
54383
54795
|
elapsedMs,
|
|
@@ -54397,7 +54809,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54397
54809
|
yield this.protocolV2StartFirmwareUpdate({ targets });
|
|
54398
54810
|
yield hdShared.wait(PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY);
|
|
54399
54811
|
yield this.waitForProtocolV2FirmwareUpdateComplete(targets, true);
|
|
54400
|
-
Log$
|
|
54812
|
+
Log$5.debug('[FirmwareUpdateV4] Protocol V2 install completed', {
|
|
54401
54813
|
targets: targets.length,
|
|
54402
54814
|
elapsedMs: getProtocolV2ElapsedMs(installStartedAt),
|
|
54403
54815
|
});
|
|
@@ -54436,10 +54848,37 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54436
54848
|
this.throwIfAborted();
|
|
54437
54849
|
const attemptStartedAt = Date.now();
|
|
54438
54850
|
let windowed = false;
|
|
54851
|
+
let chunkSize = 0;
|
|
54852
|
+
let confirmedBytes = 0;
|
|
54853
|
+
let lastMetricsAt = attemptStartedAt;
|
|
54854
|
+
const logTransfer = (status) => {
|
|
54855
|
+
const elapsedMs = getProtocolV2ElapsedMs(attemptStartedAt);
|
|
54856
|
+
TransferLog.log('[FirmwareUpdateV4] FileWrite metrics', {
|
|
54857
|
+
status,
|
|
54858
|
+
path: filePath,
|
|
54859
|
+
fileWriteWindow: windowed ? hdTransport.PROTOCOL_V2_FILE_WRITE_PIPELINE_WINDOW : 1,
|
|
54860
|
+
chunkSize,
|
|
54861
|
+
attempt,
|
|
54862
|
+
retryCount: attempt - 1,
|
|
54863
|
+
transferredBytes: confirmedBytes,
|
|
54864
|
+
totalBytes: source.size,
|
|
54865
|
+
elapsedMs,
|
|
54866
|
+
rateBytesPerSecond: getProtocolV2TransferRate(confirmedBytes, elapsedMs),
|
|
54867
|
+
});
|
|
54868
|
+
};
|
|
54869
|
+
const reportAttemptChunk = (chunkEnd) => {
|
|
54870
|
+
confirmedBytes = chunkEnd;
|
|
54871
|
+
reportConfirmedChunk(chunkEnd);
|
|
54872
|
+
const now = Date.now();
|
|
54873
|
+
if (now - lastMetricsAt >= PROTOCOL_V2_TRANSFER_LOG_INTERVAL_MS && chunkEnd < source.size) {
|
|
54874
|
+
logTransfer('progress');
|
|
54875
|
+
lastMetricsAt = now;
|
|
54876
|
+
}
|
|
54877
|
+
};
|
|
54439
54878
|
try {
|
|
54440
|
-
windowed =
|
|
54441
|
-
|
|
54442
|
-
|
|
54879
|
+
windowed = this.shouldUseProtocolV2BleFileWriteWindow();
|
|
54880
|
+
chunkSize = this.getProtocolV2FirmwareChunkSize('write', filePath, windowed);
|
|
54881
|
+
logTransfer('started');
|
|
54443
54882
|
if (windowed) {
|
|
54444
54883
|
yield this.writeProtocolV2SourceWindowed({
|
|
54445
54884
|
source,
|
|
@@ -54447,7 +54886,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54447
54886
|
chunkSize,
|
|
54448
54887
|
processedSize,
|
|
54449
54888
|
totalSize,
|
|
54450
|
-
onChunkConfirmed:
|
|
54889
|
+
onChunkConfirmed: reportAttemptChunk,
|
|
54451
54890
|
});
|
|
54452
54891
|
}
|
|
54453
54892
|
else {
|
|
@@ -54464,24 +54903,19 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54464
54903
|
if (!Number.isFinite(nextOffset) || nextOffset !== chunkEnd) {
|
|
54465
54904
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, `invalid processed_byte ${rawProcessedByte} for offset ${sourceOffset}`);
|
|
54466
54905
|
}
|
|
54467
|
-
|
|
54906
|
+
reportAttemptChunk(chunkEnd);
|
|
54468
54907
|
return length;
|
|
54469
54908
|
}),
|
|
54470
54909
|
});
|
|
54471
54910
|
}
|
|
54472
|
-
|
|
54473
|
-
path: filePath,
|
|
54474
|
-
bytes: source.size,
|
|
54475
|
-
elapsedMs: getProtocolV2ElapsedMs(attemptStartedAt),
|
|
54476
|
-
attempt,
|
|
54477
|
-
fileWriteWindow: windowed ? hdTransport.PROTOCOL_V2_FILE_WRITE_PIPELINE_WINDOW : 1,
|
|
54478
|
-
});
|
|
54911
|
+
logTransfer('completed');
|
|
54479
54912
|
return processedSize + source.size;
|
|
54480
54913
|
}
|
|
54481
54914
|
catch (error) {
|
|
54482
54915
|
this.throwIfAborted();
|
|
54483
54916
|
lastError = error;
|
|
54484
|
-
|
|
54917
|
+
logTransfer('failed');
|
|
54918
|
+
TransferLog.debug('[FirmwareUpdateV4] Protocol V2 file transfer attempt failed', {
|
|
54485
54919
|
path: filePath,
|
|
54486
54920
|
attempt,
|
|
54487
54921
|
fileWriteWindow: windowed ? hdTransport.PROTOCOL_V2_FILE_WRITE_PIPELINE_WINDOW : 1,
|
|
@@ -54523,7 +54957,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54523
54957
|
}
|
|
54524
54958
|
assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths, liveTargetIds) {
|
|
54525
54959
|
const resolvedExpectedPaths = expectedPaths !== null && expectedPaths !== void 0 ? expectedPaths : new Map();
|
|
54526
|
-
Log$
|
|
54960
|
+
Log$5.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`);
|
|
54527
54961
|
const failedTarget = statusTargets.find(target => {
|
|
54528
54962
|
var _a;
|
|
54529
54963
|
const targetId = (_a = normalizeProtocolV2TargetId(target.target_id)) !== null && _a !== void 0 ? _a : -1;
|
|
@@ -54538,7 +54972,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54538
54972
|
payloadVersion: failedTarget.payload_version,
|
|
54539
54973
|
path: failedTarget.path,
|
|
54540
54974
|
});
|
|
54541
|
-
Log$
|
|
54975
|
+
Log$5.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
|
|
54542
54976
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, 'Protocol V2 firmware install failed', {
|
|
54543
54977
|
firmwareUpdateCode: PROTOCOL_V2_INSTALL_FAILED_CODE,
|
|
54544
54978
|
});
|
|
@@ -54552,7 +54986,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54552
54986
|
!liveTargetIds.has(targetId));
|
|
54553
54987
|
});
|
|
54554
54988
|
if (staleFailedTargets.length > 0) {
|
|
54555
|
-
Log$
|
|
54989
|
+
Log$5.log(`[FirmwareUpdateV4] ignoring stale failed firmware status until those targets start: ${JSON.stringify(staleFailedTargets.map(target => ({
|
|
54556
54990
|
targetId: target.target_id,
|
|
54557
54991
|
status: target.status,
|
|
54558
54992
|
path: target.path,
|
|
@@ -54571,7 +55005,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54571
55005
|
if (targetId === undefined ||
|
|
54572
55006
|
seenTargetIds.has(targetId) ||
|
|
54573
55007
|
pathConflictsWithCurrentInstall) {
|
|
54574
|
-
Log$
|
|
55008
|
+
Log$5.error(`[FirmwareUpdateV4] install status conflicts with target=${target.target_id}`);
|
|
54575
55009
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, 'Protocol V2 firmware install status conflict', {
|
|
54576
55010
|
firmwareUpdateCode: PROTOCOL_V2_INSTALL_STATUS_CONFLICT_CODE,
|
|
54577
55011
|
});
|
|
@@ -54879,7 +55313,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54879
55313
|
if (isNormalMode &&
|
|
54880
55314
|
(installEvidenceObserved ||
|
|
54881
55315
|
this.hasProtocolV2InstallVersionChanged(expectedTargetIds, currentDeviceInfo))) {
|
|
54882
|
-
Log$
|
|
55316
|
+
Log$5.log('[FirmwareUpdateV4] empty firmware status after confirmed App reboot; update complete');
|
|
54883
55317
|
this.recordProtocolV2AuthoritativeInstallCompletion(expectedTargetIds);
|
|
54884
55318
|
this.postProgressMessage(100, 'installingFirmware');
|
|
54885
55319
|
return;
|
|
@@ -54913,7 +55347,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54913
55347
|
if (isNormalMode &&
|
|
54914
55348
|
(installEvidenceObserved ||
|
|
54915
55349
|
this.hasProtocolV2InstallVersionChanged(expectedTargetIds, deviceInfo))) {
|
|
54916
|
-
Log$
|
|
55350
|
+
Log$5.log('[FirmwareUpdateV4] firmware status endpoint unavailable after confirmed App reboot');
|
|
54917
55351
|
this.recordProtocolV2AuthoritativeInstallCompletion(expectedTargetIds);
|
|
54918
55352
|
this.postProgressMessage(100, 'installingFirmware');
|
|
54919
55353
|
return;
|
|
@@ -54931,7 +55365,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54931
55365
|
deviceInfo = undefined;
|
|
54932
55366
|
bleInstallLinkReady = false;
|
|
54933
55367
|
lastError = error;
|
|
54934
|
-
Log$
|
|
55368
|
+
Log$5.log('[FirmwareUpdateV4] DeviceFirmwareUpdateStatusGet unavailable during install: ', error);
|
|
54935
55369
|
}
|
|
54936
55370
|
}
|
|
54937
55371
|
}
|
|
@@ -54951,13 +55385,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54951
55385
|
shouldReconnect = true;
|
|
54952
55386
|
deviceInfo = undefined;
|
|
54953
55387
|
bleInstallLinkReady = false;
|
|
54954
|
-
Log$
|
|
55388
|
+
Log$5.log('Protocol V2 firmware install device readiness probe failed: ', error);
|
|
54955
55389
|
}
|
|
54956
55390
|
if (isFinalStatusCheck)
|
|
54957
55391
|
break;
|
|
54958
55392
|
yield hdShared.wait(1000);
|
|
54959
55393
|
}
|
|
54960
|
-
Log$
|
|
55394
|
+
Log$5.error(`[FirmwareUpdateV4] install timed out after ${PROTOCOL_V2_INSTALL_TIMEOUT / 1000}s: ${this.normalizeErrorMessage(lastError)}`);
|
|
54961
55395
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, 'Protocol V2 firmware install timed out', {
|
|
54962
55396
|
firmwareUpdateCode: PROTOCOL_V2_INSTALL_TIMEOUT_CODE,
|
|
54963
55397
|
});
|
|
@@ -54969,12 +55403,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
54969
55403
|
const deviceInfo = yield this.verifyProtocolV2ReconnectIdentity();
|
|
54970
55404
|
try {
|
|
54971
55405
|
if (yield this.probeProtocolV2NormalMode(deviceInfo)) {
|
|
54972
|
-
Log$
|
|
55406
|
+
Log$5.log('[FirmwareUpdateV4] device already returned to App mode; skip Normal reboot');
|
|
54973
55407
|
return;
|
|
54974
55408
|
}
|
|
54975
55409
|
}
|
|
54976
55410
|
catch (error) {
|
|
54977
|
-
Log$
|
|
55411
|
+
Log$5.log('[FirmwareUpdateV4] unable to confirm App mode before Normal reboot: ', error);
|
|
54978
55412
|
}
|
|
54979
55413
|
yield this.protocolV2Reboot(hdTransport.DeviceRebootType.Normal);
|
|
54980
55414
|
this.protocolV2ExecutionInLoader = false;
|
|
@@ -55002,7 +55436,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55002
55436
|
const firmwareVersion = getDeviceFirmwareVersion(features).join('.');
|
|
55003
55437
|
this.protocolV2LatestFinalFeatures = features;
|
|
55004
55438
|
if (firmwareVersion === '0.0.0') {
|
|
55005
|
-
Log$
|
|
55439
|
+
Log$5.warn('Protocol V2 firmware update finished but app firmware version is still 0.0.0. This is allowed for Pro2 debug BLE-only update flows.');
|
|
55006
55440
|
}
|
|
55007
55441
|
return {
|
|
55008
55442
|
bootloaderVersion,
|
|
@@ -55053,7 +55487,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55053
55487
|
}
|
|
55054
55488
|
shouldReconnect = true;
|
|
55055
55489
|
lastError = error;
|
|
55056
|
-
Log$
|
|
55490
|
+
Log$5.log('Protocol V2 normal mode not ready, polling Ping: ', error);
|
|
55057
55491
|
}
|
|
55058
55492
|
yield hdShared.wait(1000);
|
|
55059
55493
|
}
|
|
@@ -55117,7 +55551,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55117
55551
|
if (!reconnectDevice) {
|
|
55118
55552
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
|
|
55119
55553
|
}
|
|
55120
|
-
Log$
|
|
55554
|
+
Log$5.debug('Protocol V2 firmware reconnect using matched device:', reconnectDevice.getConnectId());
|
|
55121
55555
|
this.device.updateFromCache(reconnectDevice);
|
|
55122
55556
|
yield this.ensureProtocolV2DeviceAcquired();
|
|
55123
55557
|
this.device.commands.disposed = false;
|
|
@@ -55178,7 +55612,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55178
55612
|
}
|
|
55179
55613
|
const bootloaderVersion = getDeviceBootloaderVersion(this.device.features).join('.');
|
|
55180
55614
|
const enabled = supportsProtocolV2BleFileWriteWindow(bootloaderVersion, minBootloaderVersion);
|
|
55181
|
-
|
|
55615
|
+
TransferLog.debug('[FirmwareUpdateV4] BLE FileWrite window', {
|
|
55182
55616
|
enabled,
|
|
55183
55617
|
bootloaderVersion,
|
|
55184
55618
|
bootloaderBuildId: (_b = (_a = this.device.features) === null || _a === void 0 ? void 0 : _a.verify) === null || _b === void 0 ? void 0 : _b.bootloaderBuildId,
|
|
@@ -55228,17 +55662,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55228
55662
|
onChunkConfirmed(Number(confirmed.message.processed_byte));
|
|
55229
55663
|
},
|
|
55230
55664
|
},
|
|
55231
|
-
})
|
|
55232
|
-
.catch((error) => {
|
|
55233
|
-
this.protocolV2FileWriteWindowDisabled = true;
|
|
55234
|
-
throw error;
|
|
55235
55665
|
});
|
|
55236
55666
|
this.throwIfAborted();
|
|
55237
55667
|
if (sourceError)
|
|
55238
55668
|
throw sourceError;
|
|
55239
55669
|
const rawProcessedByte = response.message.processed_byte;
|
|
55240
55670
|
if (Number(rawProcessedByte) !== source.size) {
|
|
55241
|
-
this.protocolV2FileWriteWindowDisabled = true;
|
|
55242
55671
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.EmmcFileWriteFirmwareError, `invalid processed_byte ${rawProcessedByte} for file size ${source.size}`);
|
|
55243
55672
|
}
|
|
55244
55673
|
});
|
|
@@ -55294,17 +55723,17 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55294
55723
|
return;
|
|
55295
55724
|
this.protocolV2InstallTerminalSuccessObserved = true;
|
|
55296
55725
|
this.device.clearCancelableAction();
|
|
55297
|
-
Log$
|
|
55726
|
+
Log$5.log('[FirmwareUpdateV4] firmware install completed by device response');
|
|
55298
55727
|
},
|
|
55299
55728
|
});
|
|
55300
|
-
Log$
|
|
55729
|
+
Log$5.log('[FirmwareUpdateV4] firmware install request written; continue with status polling');
|
|
55301
55730
|
}
|
|
55302
55731
|
catch (error) {
|
|
55303
55732
|
this.throwIfAborted();
|
|
55304
55733
|
if (!isProtocolV2DeviceDisconnectedError(error)) {
|
|
55305
55734
|
throw error;
|
|
55306
55735
|
}
|
|
55307
|
-
Log$
|
|
55736
|
+
Log$5.log('[FirmwareUpdateV4] transport released while writing install request; continue status polling');
|
|
55308
55737
|
this.protocolV2InstallNeedsReconnect = true;
|
|
55309
55738
|
this.protocolV2InstallDisconnectObserved = !isProtocolV2InstallResponseTimeout(error);
|
|
55310
55739
|
}
|
|
@@ -55339,7 +55768,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
55339
55768
|
}
|
|
55340
55769
|
}
|
|
55341
55770
|
|
|
55342
|
-
const Log$
|
|
55771
|
+
const Log$4 = getLogger(exports.LoggerNames.Method);
|
|
55343
55772
|
class PromptWebDeviceAccess extends BaseMethod {
|
|
55344
55773
|
init() {
|
|
55345
55774
|
this.useDevice = false;
|
|
@@ -55394,7 +55823,7 @@ class PromptWebDeviceAccess extends BaseMethod {
|
|
|
55394
55823
|
return { device: null };
|
|
55395
55824
|
}
|
|
55396
55825
|
catch (error) {
|
|
55397
|
-
Log$
|
|
55826
|
+
Log$4.debug(error);
|
|
55398
55827
|
return Promise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Please select the device to connect'));
|
|
55399
55828
|
}
|
|
55400
55829
|
});
|
|
@@ -55765,7 +56194,7 @@ const DEVICE_SETTINGS_SET_MESSAGE_TYPE = 60412;
|
|
|
55765
56194
|
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE$2 = 60805;
|
|
55766
56195
|
const FILESYSTEM_DIR_MAKE_MESSAGE_TYPE = 60809;
|
|
55767
56196
|
const WALLPAPER_PACKAGE_BLE_CHUNK_SIZE = 1960;
|
|
55768
|
-
const Log$
|
|
56197
|
+
const Log$3 = getLogger(exports.LoggerNames.Method);
|
|
55769
56198
|
function normalizeFileName(fileName, data) {
|
|
55770
56199
|
if (fileName !== undefined && (!fileName || !SAFE_FILE_NAME.test(fileName))) {
|
|
55771
56200
|
throw invalidParameter$1('Parameter [fileName] may only contain letters, numbers, underscores, hyphens and an optional .bin suffix.');
|
|
@@ -55848,6 +56277,7 @@ class DeviceUploadWallpaper extends BaseMethod {
|
|
|
55848
56277
|
chunkSize: this.params.chunkSize,
|
|
55849
56278
|
bleChunkSizeLimit,
|
|
55850
56279
|
maxChunkRetries: 3,
|
|
56280
|
+
recoverConnection: createProtocolV2AssetFileWriteRecovery(this),
|
|
55851
56281
|
overwrite: true,
|
|
55852
56282
|
append: false,
|
|
55853
56283
|
throwIfAborted: () => this.throwIfAborted(),
|
|
@@ -55875,6 +56305,15 @@ class DeviceUploadWallpaper extends BaseMethod {
|
|
|
55875
56305
|
if (useHostAssetPackage)
|
|
55876
56306
|
this.path = WALLPAPER_PACKAGE_PATH;
|
|
55877
56307
|
yield this.upload(this.path, data, useHostAssetPackage ? WALLPAPER_PACKAGE_BLE_CHUNK_SIZE : undefined);
|
|
56308
|
+
this.throwIfAborted();
|
|
56309
|
+
new ProtocolV2UiInteractionCoordinator(this.device, this.postMessage).enterMethodInteraction({
|
|
56310
|
+
request: 'button',
|
|
56311
|
+
source: 'method-lifecycle',
|
|
56312
|
+
reason: 'device-management',
|
|
56313
|
+
completion: 'operation-completed',
|
|
56314
|
+
deviceOnly: true,
|
|
56315
|
+
operation: this.name,
|
|
56316
|
+
});
|
|
55878
56317
|
const response = yield this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
|
|
55879
56318
|
settings: { wallpaper_path: this.path },
|
|
55880
56319
|
});
|
|
@@ -55882,7 +56321,7 @@ class DeviceUploadWallpaper extends BaseMethod {
|
|
|
55882
56321
|
yield this.device.refreshProtocolV2SettingsAfterMutation();
|
|
55883
56322
|
}
|
|
55884
56323
|
catch (error) {
|
|
55885
|
-
Log$
|
|
56324
|
+
Log$3.warn('Protocol V2 wallpaper settings refresh failed after apply', {
|
|
55886
56325
|
error: error instanceof Error ? error.message : String(error),
|
|
55887
56326
|
});
|
|
55888
56327
|
}
|
|
@@ -56039,6 +56478,8 @@ class DeviceUploadNft extends BaseMethod {
|
|
|
56039
56478
|
chunkSize: this.params.chunkSize,
|
|
56040
56479
|
timeoutMs: this.params.timeoutMs,
|
|
56041
56480
|
paceMs: this.params.paceMs,
|
|
56481
|
+
maxChunkRetries: 3,
|
|
56482
|
+
recoverConnection: createProtocolV2AssetFileWriteRecovery(this),
|
|
56042
56483
|
overwrite: true,
|
|
56043
56484
|
append: false,
|
|
56044
56485
|
throwIfAborted: () => this.throwIfAborted(),
|
|
@@ -56093,25 +56534,13 @@ class FileWrite extends BaseMethod {
|
|
|
56093
56534
|
}
|
|
56094
56535
|
run() {
|
|
56095
56536
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56096
|
-
return writeProtocolV2File({
|
|
56097
|
-
|
|
56098
|
-
|
|
56099
|
-
data: this.params.data,
|
|
56100
|
-
offset: this.params.offset,
|
|
56101
|
-
totalSize: this.params.totalSize,
|
|
56102
|
-
chunkSize: this.params.chunkSize,
|
|
56103
|
-
chunkLen: this.params.chunkLen,
|
|
56104
|
-
overwrite: this.params.overwrite,
|
|
56105
|
-
append: this.params.append,
|
|
56106
|
-
uiPercentage: this.params.uiPercentage,
|
|
56107
|
-
timeoutMs: this.params.timeoutMs === undefined ? undefined : Number(this.params.timeoutMs),
|
|
56108
|
-
throwIfAborted: () => this.throwIfAborted(),
|
|
56109
|
-
onProgress: payload => {
|
|
56537
|
+
return writeProtocolV2File(Object.assign(Object.assign({ commands: this.device.commands, path: this.params.path, data: this.params.data, offset: this.params.offset, totalSize: this.params.totalSize, chunkSize: this.params.chunkSize, chunkLen: this.params.chunkLen, overwrite: this.params.overwrite, append: this.params.append, uiPercentage: this.params.uiPercentage, timeoutMs: this.params.timeoutMs === undefined ? undefined : Number(this.params.timeoutMs) }, (this.name === 'uploadPortfolio'
|
|
56538
|
+
? { maxChunkRetries: 3, recoverConnection: createProtocolV2AssetFileWriteRecovery(this) }
|
|
56539
|
+
: {})), { throwIfAborted: () => this.throwIfAborted(), onProgress: payload => {
|
|
56110
56540
|
if (this.params.emitProgress && typeof this.postMessage === 'function') {
|
|
56111
56541
|
this.postMessage(createUiMessage(UI_REQUEST.DEVICE_PROGRESS, payload));
|
|
56112
56542
|
}
|
|
56113
|
-
}
|
|
56114
|
-
});
|
|
56543
|
+
} }));
|
|
56115
56544
|
});
|
|
56116
56545
|
}
|
|
56117
56546
|
}
|
|
@@ -56207,201 +56636,6 @@ class CipherKeyValue extends BaseMethod {
|
|
|
56207
56636
|
}
|
|
56208
56637
|
}
|
|
56209
56638
|
|
|
56210
|
-
const isProtocolV2UiEnabled = (method) => method.protocolV2UiMode !== 'none';
|
|
56211
|
-
const getDisplayState = (value) => {
|
|
56212
|
-
const visited = new Set();
|
|
56213
|
-
let seen = false;
|
|
56214
|
-
let enabled = false;
|
|
56215
|
-
const visit = (current) => {
|
|
56216
|
-
if (current == null || typeof current !== 'object')
|
|
56217
|
-
return;
|
|
56218
|
-
if (visited.has(current))
|
|
56219
|
-
return;
|
|
56220
|
-
visited.add(current);
|
|
56221
|
-
if (Array.isArray(current)) {
|
|
56222
|
-
current.forEach(visit);
|
|
56223
|
-
return;
|
|
56224
|
-
}
|
|
56225
|
-
Object.entries(current).forEach(([key, item]) => {
|
|
56226
|
-
if ((key === 'show_display' || key === 'showOnOneKey') && typeof item === 'boolean') {
|
|
56227
|
-
seen = true;
|
|
56228
|
-
enabled || (enabled = item);
|
|
56229
|
-
return;
|
|
56230
|
-
}
|
|
56231
|
-
visit(item);
|
|
56232
|
-
});
|
|
56233
|
-
};
|
|
56234
|
-
visit(value);
|
|
56235
|
-
return { seen, enabled };
|
|
56236
|
-
};
|
|
56237
|
-
const createMethodInteraction = (reason, operation) => ({
|
|
56238
|
-
request: 'button',
|
|
56239
|
-
source: 'method-lifecycle',
|
|
56240
|
-
reason,
|
|
56241
|
-
completion: 'operation-completed',
|
|
56242
|
-
deviceOnly: true,
|
|
56243
|
-
operation,
|
|
56244
|
-
});
|
|
56245
|
-
const hasCipherConfirmation = (value) => {
|
|
56246
|
-
if (Array.isArray(value))
|
|
56247
|
-
return value.some(hasCipherConfirmation);
|
|
56248
|
-
if (value == null || typeof value !== 'object')
|
|
56249
|
-
return false;
|
|
56250
|
-
const params = value;
|
|
56251
|
-
return params.encrypt === true ? params.ask_on_encrypt === true : params.ask_on_decrypt === true;
|
|
56252
|
-
};
|
|
56253
|
-
const resolveProtocolV2UiInteraction = (method) => {
|
|
56254
|
-
if (method.protocolV2UiInteraction)
|
|
56255
|
-
return method.protocolV2UiInteraction;
|
|
56256
|
-
const operation = method.name;
|
|
56257
|
-
if (!operation)
|
|
56258
|
-
return undefined;
|
|
56259
|
-
const isAddress = /getAddress(?:ByLoop)?$/i.test(operation);
|
|
56260
|
-
const isPublicKey = /getPublicKey$/i.test(operation);
|
|
56261
|
-
if (isAddress || isPublicKey) {
|
|
56262
|
-
const paramsDisplay = getDisplayState(method.params);
|
|
56263
|
-
const payloadDisplay = getDisplayState(method.payload);
|
|
56264
|
-
const display = paramsDisplay.seen ? paramsDisplay : payloadDisplay;
|
|
56265
|
-
const shouldDisplay = display.seen ? display.enabled : isAddress;
|
|
56266
|
-
if (!shouldDisplay)
|
|
56267
|
-
return undefined;
|
|
56268
|
-
return createMethodInteraction(isAddress ? 'address-confirmation' : 'public-key-confirmation', operation);
|
|
56269
|
-
}
|
|
56270
|
-
if (/sign/i.test(operation) || /verifyMessage$/i.test(operation) || operation === 'lnurlAuth') {
|
|
56271
|
-
return createMethodInteraction('signing-confirmation', operation);
|
|
56272
|
-
}
|
|
56273
|
-
if (operation === 'nostrEncryptMessage' || operation === 'nostrDecryptMessage') {
|
|
56274
|
-
const display = getDisplayState(method.params);
|
|
56275
|
-
if (!display.enabled)
|
|
56276
|
-
return undefined;
|
|
56277
|
-
return createMethodInteraction('signing-confirmation', operation);
|
|
56278
|
-
}
|
|
56279
|
-
if (operation === 'cipherKeyValue' && hasCipherConfirmation(method.params)) {
|
|
56280
|
-
return createMethodInteraction('signing-confirmation', operation);
|
|
56281
|
-
}
|
|
56282
|
-
return undefined;
|
|
56283
|
-
};
|
|
56284
|
-
class ProtocolV2UiInteractionCoordinator {
|
|
56285
|
-
constructor(device, postMessage) {
|
|
56286
|
-
this.opened = false;
|
|
56287
|
-
this.closed = false;
|
|
56288
|
-
this.device = device;
|
|
56289
|
-
this.postMessage = postMessage;
|
|
56290
|
-
}
|
|
56291
|
-
enterMethodInteraction(interaction) {
|
|
56292
|
-
var _a, _b, _c, _d;
|
|
56293
|
-
this.methodInteraction = interaction;
|
|
56294
|
-
if (!interaction)
|
|
56295
|
-
return;
|
|
56296
|
-
const { request } = interaction, metadata = __rest(interaction, ["request"]);
|
|
56297
|
-
const interactionMeta = (_b = (_a = this.device).createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, request === 'pin' ? 'pin' : 'button', 'start');
|
|
56298
|
-
this.emit(request === 'pin' ? UI_REQUEST.REQUEST_PIN : UI_REQUEST.REQUEST_BUTTON, Object.assign(Object.assign({ device: this.device.toMessageObject() }, metadata), (interactionMeta ? { interaction: interactionMeta } : {})), `method:${request}:${interaction.reason}:${(_c = interaction.page) !== null && _c !== void 0 ? _c : ''}:${(_d = interaction.operation) !== null && _d !== void 0 ? _d : ''}`);
|
|
56299
|
-
}
|
|
56300
|
-
enterUnlockInteraction(method) {
|
|
56301
|
-
var _a, _b;
|
|
56302
|
-
const interaction = (_b = (_a = this.device).createProtocolV2UiPhaseMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, 'pin', 'start');
|
|
56303
|
-
this.emit(UI_REQUEST.REQUEST_PIN, Object.assign({ device: this.device.toMessageObject(), source: 'unlock-coordinator', reason: 'device-locked', deviceOnly: true, method }, (interaction ? { interaction } : {})), `unlock:${method !== null && method !== void 0 ? method : ''}`);
|
|
56304
|
-
return interaction;
|
|
56305
|
-
}
|
|
56306
|
-
resumeMethodInteraction() {
|
|
56307
|
-
this.enterMethodInteraction(this.methodInteraction);
|
|
56308
|
-
}
|
|
56309
|
-
close(options = {}) {
|
|
56310
|
-
var _a, _b, _c, _d;
|
|
56311
|
-
if ((!options.protocolV2Operation && !this.device.isProtocolV2()) ||
|
|
56312
|
-
(!options.ensureOperationClose &&
|
|
56313
|
-
!this.opened &&
|
|
56314
|
-
!((_b = (_a = this.device).hasOpenProtocolV2UiInteraction) === null || _b === void 0 ? void 0 : _b.call(_a))) ||
|
|
56315
|
-
this.closed)
|
|
56316
|
-
return false;
|
|
56317
|
-
this.closed = true;
|
|
56318
|
-
const interaction = (_d = (_c = this.device).finishProtocolV2UiInteraction) === null || _d === void 0 ? void 0 : _d.call(_c, 'succeeded', {
|
|
56319
|
-
ensureMetadata: options.ensureOperationClose,
|
|
56320
|
-
});
|
|
56321
|
-
const device = this.device.toMessageObject();
|
|
56322
|
-
this.postMessage(interaction
|
|
56323
|
-
? createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW, Object.assign(Object.assign({}, interaction), (device ? { device } : {})))
|
|
56324
|
-
: createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW));
|
|
56325
|
-
return true;
|
|
56326
|
-
}
|
|
56327
|
-
emit(type, payload, phase) {
|
|
56328
|
-
if (!this.device.isProtocolV2() || this.closed || this.currentPhase === phase)
|
|
56329
|
-
return;
|
|
56330
|
-
this.currentPhase = phase;
|
|
56331
|
-
this.opened = true;
|
|
56332
|
-
const message = type === UI_REQUEST.REQUEST_BUTTON
|
|
56333
|
-
? createUiMessage(UI_REQUEST.REQUEST_BUTTON, payload)
|
|
56334
|
-
: createUiMessage(UI_REQUEST.REQUEST_PIN, payload);
|
|
56335
|
-
this.postMessage(message);
|
|
56336
|
-
}
|
|
56337
|
-
}
|
|
56338
|
-
|
|
56339
|
-
const Log$3 = getLogger(exports.LoggerNames.Core);
|
|
56340
|
-
const createProtocolV2UnlockContext = () => ({
|
|
56341
|
-
preflightCompleted: false,
|
|
56342
|
-
preflightStatusRefreshed: false,
|
|
56343
|
-
preflightMainPinSelected: false,
|
|
56344
|
-
});
|
|
56345
|
-
const resolvePreUnlockPinType = (method) => {
|
|
56346
|
-
var _a, _b;
|
|
56347
|
-
if (method.protocolV2PreUnlockPinType !== undefined) {
|
|
56348
|
-
return method.protocolV2PreUnlockPinType;
|
|
56349
|
-
}
|
|
56350
|
-
const targetsKnownHiddenWallet = method.useDevicePassphraseState &&
|
|
56351
|
-
((_a = method.payload) === null || _a === void 0 ? void 0 : _a.useEmptyPassphrase) !== true &&
|
|
56352
|
-
typeof ((_b = method.payload) === null || _b === void 0 ? void 0 : _b.passphraseState) === 'string' &&
|
|
56353
|
-
method.payload.passphraseState.length > 0;
|
|
56354
|
-
return targetsKnownHiddenWallet ? hdTransport.DeviceSessionPinType.Any : hdTransport.DeviceSessionPinType.Main;
|
|
56355
|
-
};
|
|
56356
|
-
function runMethodWithUnlockPolicy(method, device, options = {}) {
|
|
56357
|
-
var _a, _b, _c;
|
|
56358
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
56359
|
-
const { context = createProtocolV2UnlockContext(), uiCoordinator, afterStatusBeforeUnlock, prepare, run: configuredRun, } = options;
|
|
56360
|
-
const run = configuredRun !== null && configuredRun !== void 0 ? configuredRun : (() => method.run());
|
|
56361
|
-
method.protocolV2UnlockContext = context;
|
|
56362
|
-
const shouldEmitUi = isProtocolV2UiEnabled(method);
|
|
56363
|
-
const shouldCoordinateUi = shouldEmitUi && uiCoordinator !== undefined;
|
|
56364
|
-
const requiresPreUnlock = device.isProtocolV2() &&
|
|
56365
|
-
(method.useDevicePassphraseState || method.unlockPolicy === 'unlock-before-run') &&
|
|
56366
|
-
((_a = device.state) === null || _a === void 0 ? void 0 : _a.status.initialized) !== false &&
|
|
56367
|
-
!((_b = device.isBootloader) === null || _b === void 0 ? void 0 : _b.call(device)) &&
|
|
56368
|
-
!((_c = device.isRomloader) === null || _c === void 0 ? void 0 : _c.call(device));
|
|
56369
|
-
if (requiresPreUnlock && !context.preflightCompleted) {
|
|
56370
|
-
const status = yield refreshProtocolV2DeviceStatus(device);
|
|
56371
|
-
if (typeof (status === null || status === void 0 ? void 0 : status.unlocked) !== 'boolean') {
|
|
56372
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 DeviceStatus did not report an explicit unlock state.');
|
|
56373
|
-
}
|
|
56374
|
-
yield (afterStatusBeforeUnlock === null || afterStatusBeforeUnlock === void 0 ? void 0 : afterStatusBeforeUnlock());
|
|
56375
|
-
if (!status.unlocked) {
|
|
56376
|
-
const preUnlockPinType = resolvePreUnlockPinType(method);
|
|
56377
|
-
const unlockInteraction = shouldCoordinateUi
|
|
56378
|
-
? uiCoordinator.enterUnlockInteraction(method.name)
|
|
56379
|
-
: undefined;
|
|
56380
|
-
const unlockedStatus = yield device.unlockDevice(preUnlockPinType, shouldCoordinateUi
|
|
56381
|
-
? { emitUiEvent: false, interaction: unlockInteraction }
|
|
56382
|
-
: {
|
|
56383
|
-
source: 'unlock-coordinator',
|
|
56384
|
-
reason: 'device-locked',
|
|
56385
|
-
deviceOnly: true,
|
|
56386
|
-
method: method.name,
|
|
56387
|
-
});
|
|
56388
|
-
if ((unlockedStatus === null || unlockedStatus === void 0 ? void 0 : unlockedStatus.unlocked) !== true) {
|
|
56389
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 device remained locked after the unlock flow.');
|
|
56390
|
-
}
|
|
56391
|
-
context.preflightMainPinSelected = preUnlockPinType === hdTransport.DeviceSessionPinType.Main;
|
|
56392
|
-
Log$3.debug('Protocol V2 pre-unlock completed', { method: method.name });
|
|
56393
|
-
}
|
|
56394
|
-
context.preflightStatusRefreshed = true;
|
|
56395
|
-
context.preflightCompleted = true;
|
|
56396
|
-
}
|
|
56397
|
-
yield (prepare === null || prepare === void 0 ? void 0 : prepare());
|
|
56398
|
-
if (shouldCoordinateUi) {
|
|
56399
|
-
uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
|
|
56400
|
-
}
|
|
56401
|
-
return run();
|
|
56402
|
-
});
|
|
56403
|
-
}
|
|
56404
|
-
|
|
56405
56639
|
const Mainnet = 'mainnet';
|
|
56406
56640
|
const MoneroNetworkTypes = new Map([
|
|
56407
56641
|
[Mainnet, hdTransport.Messages.MoneroNetworkType.MAINNET],
|