mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
fix: add install container and copy config
This commit is contained in:
@@ -6,6 +6,8 @@
|
|||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSet>
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
#include <QJniObject>
|
#include <QJniObject>
|
||||||
#include "platforms/android/android_controller.h"
|
#include "platforms/android/android_controller.h"
|
||||||
@@ -601,6 +603,82 @@ void ServersBackupController::uploadBackupWithStrings(const QString &hostname,
|
|||||||
uploadBackup(credentials, localPath, replaceMode);
|
uploadBackup(credentials, localPath, replaceMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList ServersBackupController::scanBackupForContainers(const QString &localPath)
|
||||||
|
{
|
||||||
|
QStringList containers;
|
||||||
|
|
||||||
|
qDebug() << "Scanning backup file for containers:" << localPath;
|
||||||
|
|
||||||
|
// Для Android URI или обычного пути используем tar для просмотра содержимого
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
QString actualPath = localPath;
|
||||||
|
if (localPath.startsWith("content://")) {
|
||||||
|
// Для Android URI нужно сначала прочитать файл
|
||||||
|
int fd = AndroidController::instance()->getFd(localPath);
|
||||||
|
if (fd < 0) {
|
||||||
|
qWarning() << "Failed to get file descriptor for Android URI";
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file;
|
||||||
|
if (!file.open(fd, QIODevice::ReadOnly)) {
|
||||||
|
qWarning() << "Failed to open file from descriptor";
|
||||||
|
AndroidController::instance()->closeFd();
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data = file.readAll();
|
||||||
|
file.close();
|
||||||
|
AndroidController::instance()->closeFd();
|
||||||
|
|
||||||
|
// Сохраняем во временный файл
|
||||||
|
actualPath = QDir::temp().filePath("backup_scan_temp.tgz");
|
||||||
|
QFile tempFile(actualPath);
|
||||||
|
if (!tempFile.open(QIODevice::WriteOnly)) {
|
||||||
|
qWarning() << "Failed to create temp file for scanning";
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
tempFile.write(data);
|
||||||
|
tempFile.close();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QString actualPath = localPath;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Выполняем команду tar для просмотра содержимого
|
||||||
|
QProcess process;
|
||||||
|
process.start("tar", QStringList() << "-tzf" << actualPath);
|
||||||
|
process.waitForFinished(5000);
|
||||||
|
|
||||||
|
if (process.exitCode() != 0) {
|
||||||
|
qWarning() << "Failed to read backup archive:" << process.readAllStandardError();
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString output = process.readAllStandardOutput();
|
||||||
|
QStringList lines = output.split('\n', Qt::SkipEmptyParts);
|
||||||
|
|
||||||
|
// Ищем директории контейнеров (amnezia-*)
|
||||||
|
QSet<QString> foundContainers;
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
if (line.contains("amnezia-")) {
|
||||||
|
// Извлекаем имя контейнера из пути
|
||||||
|
QStringList parts = line.split('/');
|
||||||
|
for (const QString &part : parts) {
|
||||||
|
if (part.startsWith("amnezia-")) {
|
||||||
|
foundContainers.insert(part);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
containers = foundContainers.values();
|
||||||
|
qDebug() << "Found containers in backup:" << containers;
|
||||||
|
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
void ServersBackupController::deleteBackup(const ServerCredentials &credentials,
|
void ServersBackupController::deleteBackup(const ServerCredentials &credentials,
|
||||||
const QString &backupFilename)
|
const QString &backupFilename)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,6 +131,13 @@ public slots:
|
|||||||
const QString &secretData,
|
const QString &secretData,
|
||||||
const QString &localPath,
|
const QString &localPath,
|
||||||
bool replaceMode = false);
|
bool replaceMode = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сканировать backup файл и определить какие контейнеры в нем есть
|
||||||
|
* @param localPath Путь к локальному backup файлу
|
||||||
|
* @return Список имен контейнеров найденных в backup
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE QStringList scanBackupForContainers(const QString &localPath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Удалить backup с сервера
|
* @brief Удалить backup с сервера
|
||||||
|
|||||||
@@ -178,22 +178,22 @@ PageType {
|
|||||||
|
|
||||||
function onBackupRestored() {
|
function onBackupRestored() {
|
||||||
|
|
||||||
// После успешного восстановления сканируем сервер для обновления информации о контейнерах
|
console.log(" onBackupRestored, isFromSetupWizard:", isFromSetupWizard)
|
||||||
|
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
|
||||||
|
// Для setup wizard устанавливаем default container и сервер
|
||||||
if (isFromSetupWizard && ServersModel.getServersCount() > 0) {
|
if (isFromSetupWizard && ServersModel.getServersCount() > 0) {
|
||||||
var serverIdx = ServersModel.getServersCount() - 1
|
var serverIdx = ServersModel.getServersCount() - 1
|
||||||
console.log(" Setting server as default:", serverIdx)
|
console.log(" Setting server as default:", serverIdx)
|
||||||
ServersModel.setDefaultServerIndex(serverIdx)
|
ServersModel.setDefaultServerIndex(serverIdx)
|
||||||
ServersModel.processedIndex = serverIdx
|
ServersModel.processedIndex = serverIdx
|
||||||
|
|
||||||
// Сканируем сервер для обновления информации о контейнерах
|
// Запускаем timer для установки default container
|
||||||
console.log(" Scanning server for installed containers...")
|
// Контейнеры уже установлены через InstallController, просто ждем обновления модели
|
||||||
PageController.showNotificationMessage(qsTr("Updating container information..."))
|
setDefaultContainerTimer.start()
|
||||||
InstallController.scanServerForInstalledContainers()
|
|
||||||
|
|
||||||
// Timer запустится автоматически после получения сигнала scanServerFinished
|
|
||||||
} else {
|
} else {
|
||||||
console.log(" Skipping default container setup (not from wizard or no servers)")
|
// Для обычного режима сразу переходим
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
navigateToRestoredPage()
|
navigateToRestoredPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,19 +204,7 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
// Удаляем Connections для scanServerFinished - больше не нужен
|
||||||
target: InstallController
|
|
||||||
|
|
||||||
function onScanServerFinished(isInstalledContainerFound) {
|
|
||||||
console.log("Scan finished, containers found:", isInstalledContainerFound)
|
|
||||||
|
|
||||||
// Если это setup wizard и сканирование завершено
|
|
||||||
if (isFromSetupWizard) {
|
|
||||||
// Запускаем timer для установки default container
|
|
||||||
setDefaultContainerTimer.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateToRestoredPage() {
|
function navigateToRestoredPage() {
|
||||||
// Переход на страницу успешного восстановления
|
// Переход на страницу успешного восстановления
|
||||||
|
|||||||
@@ -25,19 +25,97 @@ PageType {
|
|||||||
property string restoreSecretData: ""
|
property string restoreSecretData: ""
|
||||||
property bool waitingForServerToAdd: false
|
property bool waitingForServerToAdd: false
|
||||||
|
|
||||||
|
// Для установки контейнеров из backup
|
||||||
|
property var containersToInstall: []
|
||||||
|
property int currentContainerIndex: 0
|
||||||
|
property bool isInstallingContainers: false
|
||||||
|
|
||||||
// Connections для отслеживания добавления сервера
|
// Connections для отслеживания добавления сервера
|
||||||
Connections {
|
Connections {
|
||||||
target: InstallController
|
target: InstallController
|
||||||
|
|
||||||
function onInstallServerFinished(finishedMessage) {
|
function onInstallServerFinished(finishedMessage) {
|
||||||
if (root.waitingForServerToAdd && root.isRestoreFromBackup && root.backupFilePath.length > 0) {
|
if (root.waitingForServerToAdd && root.isRestoreFromBackup && root.backupFilePath.length > 0) {
|
||||||
console.log("Server added successfully, now showing restore mode page")
|
console.log("Server added successfully, now installing containers from backup...")
|
||||||
root.waitingForServerToAdd = false
|
root.waitingForServerToAdd = false
|
||||||
|
|
||||||
// Запускаем переход на страницу восстановления
|
// Сервер уже создан, устанавливаем флаг в false
|
||||||
navigationTimer.start()
|
InstallController.setShouldCreateServer(false)
|
||||||
|
|
||||||
|
// Начинаем установку контейнеров
|
||||||
|
root.isInstallingContainers = true
|
||||||
|
installNextContainer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onInstallContainerFinished(finishedMessage, isServiceInstall) {
|
||||||
|
if (root.isInstallingContainers) {
|
||||||
|
console.log("Container installed:", finishedMessage)
|
||||||
|
|
||||||
|
// Переходим к следующему контейнеру
|
||||||
|
root.currentContainerIndex++
|
||||||
|
|
||||||
|
if (root.currentContainerIndex < root.containersToInstall.length) {
|
||||||
|
// Устанавливаем следующий контейнер
|
||||||
|
installNextContainer()
|
||||||
|
} else {
|
||||||
|
// Все контейнеры установлены, теперь делаем restore
|
||||||
|
console.log("All containers installed, starting restore...")
|
||||||
|
root.isInstallingContainers = false
|
||||||
|
|
||||||
|
// ВАЖНО: Выключаем busy indicator перед переходом
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
|
||||||
|
// Запускаем переход на страницу выбора режима restore
|
||||||
|
navigationTimer.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для установки следующего контейнера из списка
|
||||||
|
function installNextContainer() {
|
||||||
|
if (root.currentContainerIndex >= root.containersToInstall.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var containerName = root.containersToInstall[root.currentContainerIndex]
|
||||||
|
console.log("Installing container:", containerName, "(", root.currentContainerIndex + 1, "/", root.containersToInstall.length, ")")
|
||||||
|
|
||||||
|
// Конвертируем имя контейнера в DockerContainer enum
|
||||||
|
var dockerContainer = ContainerProps.containerFromString(containerName)
|
||||||
|
|
||||||
|
if (dockerContainer === 0) { // None
|
||||||
|
console.log("Unknown container:", containerName, "skipping...")
|
||||||
|
root.currentContainerIndex++
|
||||||
|
installNextContainer()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем default настройки для контейнера
|
||||||
|
var defaultProtocol = ContainerProps.defaultProtocol(dockerContainer)
|
||||||
|
var defaultPort = ProtocolProps.getPortForInstall(defaultProtocol)
|
||||||
|
var defaultTransport = ProtocolProps.defaultTransportProto(defaultProtocol)
|
||||||
|
|
||||||
|
// Показываем индикатор загрузки с сообщением
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
PageController.showNotificationMessage(qsTr("Installing %1 (%2/%3)...")
|
||||||
|
.arg(containerName)
|
||||||
|
.arg(root.currentContainerIndex + 1)
|
||||||
|
.arg(root.containersToInstall.length))
|
||||||
|
|
||||||
|
// Убеждаемся что credentials установлены
|
||||||
|
console.log("Setting credentials for container installation...")
|
||||||
|
InstallController.setProcessedServerCredentials(root.restoreHostname, root.restoreUsername, root.restoreSecretData)
|
||||||
|
|
||||||
|
// Устанавливаем индекс сервера
|
||||||
|
var serverIdx = ServersModel.getServersCount() - 1
|
||||||
|
ServersModel.processedIndex = serverIdx
|
||||||
|
|
||||||
|
// Устанавливаем контейнер
|
||||||
|
console.log("Calling InstallController.install for docker container:", dockerContainer)
|
||||||
|
ContainersModel.setProcessedContainerIndex(dockerContainer)
|
||||||
|
InstallController.install(dockerContainer, defaultPort, defaultTransport)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Таймер для перехода на страницу выбора режима после выбора файла
|
// Таймер для перехода на страницу выбора режима после выбора файла
|
||||||
@@ -304,6 +382,20 @@ PageType {
|
|||||||
root.backupFilePath = localPath
|
root.backupFilePath = localPath
|
||||||
root.isRestoreFromBackup = true
|
root.isRestoreFromBackup = true
|
||||||
|
|
||||||
|
// Сканируем backup для определения контейнеров
|
||||||
|
console.log("Scanning backup for containers...")
|
||||||
|
var foundContainers = ServersBackupController.scanBackupForContainers(localPath)
|
||||||
|
console.log("Found containers:", foundContainers)
|
||||||
|
|
||||||
|
if (foundContainers.length === 0) {
|
||||||
|
PageController.showErrorMessage(qsTr("No containers found in backup file"))
|
||||||
|
root.isRestoreFromBackup = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root.containersToInstall = foundContainers
|
||||||
|
root.currentContainerIndex = 0
|
||||||
|
|
||||||
// Получаем credentials из PageSetupWizardCredentials через поиск в StackView
|
// Получаем credentials из PageSetupWizardCredentials через поиск в StackView
|
||||||
var credentialsPage = null
|
var credentialsPage = null
|
||||||
var item = root
|
var item = root
|
||||||
|
|||||||
Reference in New Issue
Block a user