- SshSession::resetConnection(): force-disconnect before each new top-level

backup operation so ssh_scp_new() doesn't fail on a reused stale session
  (reproduces as 'Failed to open channel for scp' right after restore)
- Call resetConnection() at entry of createBackup() and uploadBackup()
- Replace recursive findStackView() in PageSetupWizardEasy with upward
  parent traversal (depth+push check) to avoid JS stack overflow on iOS
  when component tree is large (71 VPN managers in test)
This commit is contained in:
NickVs2015
2026-05-29 15:51:22 +03:00
parent 23b7c26609
commit 40abac8725
4 changed files with 25 additions and 33 deletions
@@ -44,6 +44,11 @@ SshSession::~SshSession()
m_sshClient.disconnectFromHost();
}
void SshSession::resetConnection()
{
m_sshClient.disconnectFromHost();
}
ErrorCode SshSession::runScript(const ServerCredentials &credentials, QString script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
@@ -47,6 +47,9 @@ public:
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting);
/** Force-close the current SSH connection so the next operation starts fresh. */
void resetConnection();
private:
libssh::Client m_sshClient;
};
@@ -62,6 +62,8 @@ void ServersBackupController::createBackup(const ServerCredentials &credentials)
return;
}
m_sshSession.resetConnection();
setStatus(InProgress);
setProgress(0, tr("Starting backup creation..."));
@@ -482,6 +484,8 @@ void ServersBackupController::uploadBackup(const ServerCredentials &credentials,
return;
}
m_sshSession.resetConnection();
// Save restore mode for later use
m_restoreReplaceMode = replaceMode;
+13 -33
View File
@@ -193,45 +193,25 @@ PageType {
// Server already added, as we waited for onInstallServerFinished
Qt.callLater(function() {
var pagePath = "qrc:/ui/qml/Pages2/PageSettingsServerRestoreMode.qml"
// Find main application window
var item = root
while (item.parent) {
item = item.parent
// Traverse upward from root to find the containing StackView.
// StackView has both `push` function and `depth` property.
// This avoids a recursive downward search that causes stack overflow
// on iOS when the component tree is large (many VPN managers).
var stackView = root.parent
while (stackView) {
if (typeof stackView.push === "function" && stackView.hasOwnProperty("depth")) {
break
}
stackView = stackView.parent
}
// Find StackView recursively
function findStackView(obj) {
if (!obj) return null
// Check if object is StackView
if (obj.toString().indexOf("StackView") !== -1 || typeof obj.push === "function") {
return obj
}
// Check children
if (obj.children) {
for (var i = 0; i < obj.children.length; i++) {
var result = findStackView(obj.children[i])
if (result) return result
}
}
// Check contentItem
if (obj.contentItem) {
return findStackView(obj.contentItem)
}
return null
}
var stackView = findStackView(item)
if (stackView) {
console.log("Found StackView, pushing restore mode page")
stackView.push(pagePath, {
"backupFilePath": root.backupFilePath,
"backupFileName": fileName,
"serverName": "", // Will be obtained from ServersModel
"serverName": "",
"serverIp": serverIp,
"isFromSetupWizard": true,
"wizardHostname": root.restoreHostname,