mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
feat: update ConfigManager and ProxyServer to utilize Settings
- Modified ConfigManager to accept a Settings object for improved configuration management. - Updated ProxyServer to initialize with Settings, enhancing dependency injection.
This commit is contained in:
@@ -1,565 +1,193 @@
|
||||
#include "configmanager.h"
|
||||
#include "core/serialization/serialization.h"
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/api/apiUtils.h"
|
||||
#include "proxylogger.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include "settings.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
#include <QSaveFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QDebug>
|
||||
#include <QUuid>
|
||||
|
||||
ConfigManager::ConfigManager()
|
||||
ConfigManager::ConfigManager(const std::shared_ptr<Settings> &settings)
|
||||
: m_settings(settings)
|
||||
{
|
||||
ProxyLogger::getInstance().debug("Initializing ConfigManager");
|
||||
|
||||
// Create configs directory if it doesn't exist
|
||||
QString configPath = getConfigsPath();
|
||||
ProxyLogger::getInstance().debug(QString("Ensuring config directory exists: %1").arg(configPath));
|
||||
QDir().mkpath(configPath);
|
||||
|
||||
// Read active config UUID and initialize config count
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
m_activeConfigUuid = configsInfo["activeConfigUuid"].toString();
|
||||
m_configCount = configsInfo["configs"].toObject().size();
|
||||
ProxyLogger::getInstance().info(QString("Active config UUID: %1, Total configs: %2")
|
||||
.arg(m_activeConfigUuid.isEmpty() ? "none" : m_activeConfigUuid)
|
||||
.arg(m_configCount));
|
||||
ProxyLogger::getInstance().debug("ConfigManager initialized (Settings-backed)");
|
||||
}
|
||||
|
||||
QString ConfigManager::getConfigsPath() const
|
||||
std::optional<ConfigManager::ConfigData> ConfigManager::buildConfig(QString &errorDescription) const
|
||||
{
|
||||
QString configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
return QDir(configDir).filePath("xray_configs");
|
||||
}
|
||||
errorDescription.clear();
|
||||
|
||||
QString ConfigManager::getActiveConfigPath() const
|
||||
{
|
||||
return QDir(getConfigsPath()).filePath("active_config.json");
|
||||
}
|
||||
|
||||
QString ConfigManager::getConfigsInfoPath() const
|
||||
{
|
||||
return QDir(getConfigsPath()).filePath("configs_info.json");
|
||||
}
|
||||
|
||||
QJsonObject ConfigManager::readConfigsInfo() const
|
||||
{
|
||||
QFile file(getConfigsInfoPath());
|
||||
|
||||
if (!file.exists()) {
|
||||
ProxyLogger::getInstance().info("Configs info file doesn't exist, creating new one");
|
||||
// If file doesn't exist, return empty structure
|
||||
QJsonObject configsInfo;
|
||||
configsInfo["version"] = 1;
|
||||
configsInfo["configs"] = QJsonObject();
|
||||
return configsInfo;
|
||||
if (!m_settings) {
|
||||
const QString message = QStringLiteral("Settings backend is not available");
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to open configs info file: %1").arg(file.errorString()));
|
||||
return QJsonObject();
|
||||
const QString ownerUuid = m_settings->localProxyOwnerUuid();
|
||||
if (ownerUuid.isEmpty()) {
|
||||
const QString message = QStringLiteral("Local proxy owner UUID is not configured");
|
||||
ProxyLogger::getInstance().warning(message);
|
||||
errorDescription = message;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
const auto ownerServer = findServerByUuid(ownerUuid);
|
||||
if (!ownerServer) {
|
||||
const QString message = QStringLiteral("Owner server with UUID %1 not found in Settings").arg(ownerUuid);
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!apiUtils::isPremiumServer(*ownerServer)) {
|
||||
const QString message = QStringLiteral("Server %1 is not premium, local proxy is unavailable")
|
||||
.arg(ownerServer->value(amnezia::config_key::name).toString());
|
||||
ProxyLogger::getInstance().warning(message);
|
||||
errorDescription = message;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto serializedConfig = extractSerializedXrayConfig(*ownerServer);
|
||||
if (!serializedConfig || serializedConfig->isEmpty()) {
|
||||
const QString message = QStringLiteral("Server %1 lacks Xray last_config payload")
|
||||
.arg(ownerServer->value(amnezia::config_key::name).toString());
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to parse configs info file: %1").arg(parseError.errorString()));
|
||||
return QJsonObject();
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(serializedConfig->toUtf8(), &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
const QString message = QStringLiteral("Failed to parse Xray config JSON: %1").arg(parseError.errorString());
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Successfully read configs info file");
|
||||
return doc.object();
|
||||
ConfigData data;
|
||||
data.ownerUuid = ownerUuid;
|
||||
data.serverName = ownerServer->value(amnezia::config_key::name).toString();
|
||||
data.serializedConfig = *serializedConfig;
|
||||
data.parsedConfig = doc.object();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool ConfigManager::writeConfigsInfo(const QJsonObject &configsInfo)
|
||||
bool ConfigManager::writeTempConfig(const QString &serializedConfig, QString &configPath, QString &errorDescription) const
|
||||
{
|
||||
QFile file(getConfigsInfoPath());
|
||||
errorDescription.clear();
|
||||
configPath.clear();
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to open configs info file for writing: %1").arg(file.errorString()));
|
||||
const QString directory = tempDirectory();
|
||||
if (!QDir().mkpath(directory)) {
|
||||
const QString message = QStringLiteral("Failed to create temp config directory: %1").arg(directory);
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_configCount = configsInfo["configs"].toObject().size();
|
||||
ProxyLogger::getInstance().debug(QString("Updated config count: %1").arg(m_configCount));
|
||||
|
||||
QJsonDocument doc(configsInfo);
|
||||
file.write(doc.toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
|
||||
ProxyLogger::getInstance().debug("Successfully wrote configs info file");
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonObject ConfigManager::readActiveConfig() const
|
||||
{
|
||||
QFile file(getActiveConfigPath());
|
||||
|
||||
if (!file.exists()) {
|
||||
ProxyLogger::getInstance().warning(QString("Active config file not found at: %1").arg(getActiveConfigPath()));
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to open active config file: %1").arg(file.errorString()));
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to parse active config file: %1").arg(parseError.errorString()));
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Successfully read active config file");
|
||||
return doc.object();
|
||||
}
|
||||
|
||||
bool ConfigManager::writeActiveConfig(const QJsonObject &config)
|
||||
{
|
||||
ProxyLogger::getInstance().info("Writing new active config");
|
||||
QFile file(getActiveConfigPath());
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to open active config file for writing: %1").arg(file.errorString()));
|
||||
const QString path = tempConfigPath();
|
||||
QSaveFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
const QString message = QStringLiteral("Failed to open temp config file %1: %2").arg(path, file.errorString());
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument doc(config);
|
||||
file.write(doc.toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
if (file.write(serializedConfig.toUtf8()) == -1) {
|
||||
const QString message = QStringLiteral("Failed to write temp config file %1: %2").arg(path, file.errorString());
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Successfully wrote active config file");
|
||||
if (!file.commit()) {
|
||||
const QString message = QStringLiteral("Failed to commit temp config file %1").arg(path);
|
||||
ProxyLogger::getInstance().error(message);
|
||||
errorDescription = message;
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().info(QStringLiteral("Xray config saved to %1").arg(path));
|
||||
configPath = path;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigManager::removeActiveConfigFile()
|
||||
bool ConfigManager::removeTempConfig() const
|
||||
{
|
||||
ProxyLogger::getInstance().info("Removing active config file");
|
||||
QFile file(getActiveConfigPath());
|
||||
|
||||
if (file.exists()) {
|
||||
if (file.remove()) {
|
||||
ProxyLogger::getInstance().debug("Successfully removed active config file");
|
||||
return true;
|
||||
} else {
|
||||
ProxyLogger::getInstance().error(QString("Failed to remove active config file: %1").arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
const QString path = tempConfigPath();
|
||||
QFile file(path);
|
||||
if (!file.exists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Active config file does not exist, nothing to remove");
|
||||
|
||||
if (!file.remove()) {
|
||||
ProxyLogger::getInstance().warning(QStringLiteral("Failed to remove temp config file %1: %2").arg(path, file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug(QStringLiteral("Removed temp config file %1").arg(path));
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ConfigManager::generateUuid() const
|
||||
QString ConfigManager::tempConfigPath() const
|
||||
{
|
||||
return QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
return QDir(tempDirectory()).filePath(QStringLiteral("xray_active.json"));
|
||||
}
|
||||
|
||||
QString ConfigManager::getProtocolFromSerializedConfig(const QString &config) const
|
||||
std::optional<QJsonObject> ConfigManager::findServerByUuid(const QString &uuid) const
|
||||
{
|
||||
if (config.startsWith("vless://")) return "vless";
|
||||
if (config.startsWith("vmess://")) return "vmess";
|
||||
if (config.startsWith("trojan://")) return "trojan";
|
||||
if (config.startsWith("ss://")) return "ss";
|
||||
return QString();
|
||||
}
|
||||
if (!m_settings) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QJsonObject ConfigManager::deserializeConfig(const QString &configStr, QString *prefix, QString *errorMsg)
|
||||
{
|
||||
ProxyLogger::getInstance().debug("Deserializing config");
|
||||
QJsonObject outConfig;
|
||||
|
||||
QString localPrefix;
|
||||
QString localErrorMsg;
|
||||
|
||||
QString* safePrefix = prefix ? prefix : &localPrefix;
|
||||
QString* safeErrorMsg = errorMsg ? errorMsg : &localErrorMsg;
|
||||
|
||||
if (configStr.startsWith("vless://")) {
|
||||
ProxyLogger::getInstance().debug("Deserializing VLESS config");
|
||||
outConfig = amnezia::serialization::vless::Deserialize(configStr, safePrefix, safeErrorMsg);
|
||||
if (safePrefix->contains(QRegularExpression("%[0-9A-Fa-f]{2}"))) {
|
||||
*safePrefix = QString::fromUtf8(QByteArray::fromPercentEncoding(safePrefix->toUtf8()));
|
||||
const QJsonArray servers = m_settings->serversArray();
|
||||
for (const QJsonValue &value : servers) {
|
||||
const QJsonObject server = value.toObject();
|
||||
if (server.value(amnezia::config_key::server_uuid).toString() == uuid) {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
if (configStr.startsWith("vmess://") && configStr.contains("@")) {
|
||||
ProxyLogger::getInstance().debug("Deserializing new VMess config");
|
||||
outConfig = amnezia::serialization::vmess_new::Deserialize(configStr, safePrefix, safeErrorMsg);
|
||||
}
|
||||
|
||||
else if (configStr.startsWith("vmess://")) {
|
||||
ProxyLogger::getInstance().debug("Deserializing VMess config");
|
||||
outConfig = amnezia::serialization::vmess::Deserialize(configStr, safePrefix, safeErrorMsg);
|
||||
}
|
||||
|
||||
if (configStr.startsWith("trojan://")) {
|
||||
ProxyLogger::getInstance().debug("Deserializing Trojan config");
|
||||
outConfig = amnezia::serialization::trojan::Deserialize(configStr, safePrefix, safeErrorMsg);
|
||||
}
|
||||
|
||||
if (configStr.startsWith("ss://") && !configStr.contains("plugin=")) {
|
||||
ProxyLogger::getInstance().debug("Deserializing Shadowsocks config");
|
||||
outConfig = amnezia::serialization::ss::Deserialize(configStr, safePrefix, safeErrorMsg);
|
||||
if (safePrefix->contains(QRegularExpression("%[0-9A-Fa-f]{2}"))) {
|
||||
*safePrefix = QString::fromUtf8(QByteArray::fromPercentEncoding(safePrefix->toUtf8()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!safeErrorMsg->isEmpty()) {
|
||||
ProxyLogger::getInstance().error(QString("Config deserialization error: %1").arg(*safeErrorMsg));
|
||||
}
|
||||
|
||||
return outConfig;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QJsonObject ConfigManager::addInbounds(const QJsonObject &config)
|
||||
std::optional<QString> ConfigManager::extractSerializedXrayConfig(const QJsonObject &server) const
|
||||
{
|
||||
ProxyLogger::getInstance().debug("Adding inbounds configuration");
|
||||
QJsonObject resultConfig = config;
|
||||
const QJsonArray containers = server.value(amnezia::config_key::containers).toArray();
|
||||
const QString targetContainer = ContainerProps::containerToString(amnezia::DockerContainer::Xray);
|
||||
const QString protoKey = ProtocolProps::protoToString(amnezia::Proto::Xray);
|
||||
|
||||
QJsonArray inbounds;
|
||||
QJsonObject socksInbound;
|
||||
socksInbound["listen"] = "127.0.0.1";
|
||||
socksInbound["port"] = 10808;
|
||||
socksInbound["protocol"] = "socks";
|
||||
|
||||
QJsonObject settings;
|
||||
settings["udp"] = true;
|
||||
socksInbound["settings"] = settings;
|
||||
|
||||
inbounds.append(socksInbound);
|
||||
resultConfig["inbounds"] = inbounds;
|
||||
|
||||
ProxyLogger::getInstance().debug("Successfully added SOCKS inbound configuration (port: 10808)");
|
||||
return resultConfig;
|
||||
}
|
||||
|
||||
bool ConfigManager::addConfigs(const QStringList &serializedConfigs)
|
||||
{
|
||||
ProxyLogger::getInstance().info(QString("Adding %1 new config(s)").arg(serializedConfigs.size()));
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
QJsonObject configs = configsInfo["configs"].toObject();
|
||||
QString activeUuid = getActiveConfigUuid();
|
||||
QString firstUuid;
|
||||
|
||||
QSet<QString> existingConfigs;
|
||||
for (auto it = configs.begin(); it != configs.end(); ++it) {
|
||||
QJsonObject configInfo = it.value().toObject();
|
||||
existingConfigs.insert(configInfo["serializedConfig"].toString());
|
||||
}
|
||||
|
||||
for (const QString &serializedConfig : serializedConfigs)
|
||||
{
|
||||
if (existingConfigs.contains(serializedConfig)) {
|
||||
ProxyLogger::getInstance().info("Skipping duplicate config");
|
||||
for (const QJsonValue &value : containers) {
|
||||
const QJsonObject container = value.toObject();
|
||||
if (container.value(amnezia::config_key::container).toString() != targetContainer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString uuid = generateUuid();
|
||||
ProxyLogger::getInstance().debug(QString("Generated new UUID: %1").arg(uuid));
|
||||
|
||||
if (firstUuid.isEmpty()) {
|
||||
firstUuid = uuid;
|
||||
}
|
||||
|
||||
QString prefix;
|
||||
QString errorMsg;
|
||||
ProxyLogger::getInstance().debug(QString("Deserializing config: %1").arg(serializedConfig.left(50) + "..."));
|
||||
QJsonObject config = deserializeConfig(serializedConfig, &prefix, &errorMsg);
|
||||
|
||||
if (!errorMsg.isEmpty()) {
|
||||
ProxyLogger::getInstance().error(QString("Failed to deserialize config: %1").arg(errorMsg));
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject currentConfigInfo;
|
||||
currentConfigInfo["created"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
currentConfigInfo["lastUsed"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
currentConfigInfo["protocol"] = getProtocolFromSerializedConfig(serializedConfig);
|
||||
currentConfigInfo["serializedConfig"] = serializedConfig;
|
||||
currentConfigInfo["name"] = prefix.isEmpty() ? uuid : prefix;
|
||||
currentConfigInfo["isActive"] = false;
|
||||
|
||||
ProxyLogger::getInstance().info(QString("Adding config: UUID=%1, Protocol=%2, Name=%3")
|
||||
.arg(uuid)
|
||||
.arg(currentConfigInfo["protocol"].toString())
|
||||
.arg(currentConfigInfo["name"].toString()));
|
||||
|
||||
configs[uuid] = currentConfigInfo;
|
||||
}
|
||||
|
||||
configsInfo["configs"] = configs;
|
||||
ProxyLogger::getInstance().debug("Writing updated configs info to file");
|
||||
if (!writeConfigsInfo(configsInfo)) {
|
||||
ProxyLogger::getInstance().error("Failed to write configs info");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there's no active config, activate the first added one
|
||||
if (activeUuid.isEmpty() && !firstUuid.isEmpty())
|
||||
{
|
||||
ProxyLogger::getInstance().info(QString("No active config, activating first added config: %1").arg(firstUuid));
|
||||
return activateConfig(firstUuid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigManager::removeConfig(const QString &uuid)
|
||||
{
|
||||
ProxyLogger::getInstance().info(QString("Removing config with UUID: %1").arg(uuid));
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
QJsonObject configs = configsInfo["configs"].toObject();
|
||||
|
||||
// Check if config exists
|
||||
if (!configs.contains(uuid))
|
||||
{
|
||||
ProxyLogger::getInstance().warning(QString("Config with UUID %1 not found").arg(uuid));
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject configToRemove = configs[uuid].toObject();
|
||||
ProxyLogger::getInstance().info(QString("Removing config: Name=%1, Protocol=%2")
|
||||
.arg(configToRemove["name"].toString())
|
||||
.arg(configToRemove["protocol"].toString()));
|
||||
|
||||
// Store current active config UUID
|
||||
bool needToActivateNew = (getActiveConfigUuid() == uuid);
|
||||
|
||||
// Remove config from the list
|
||||
configs.remove(uuid);
|
||||
|
||||
// Save updated configs list (without changing activeConfigUuid)
|
||||
configsInfo["configs"] = configs;
|
||||
ProxyLogger::getInstance().debug("Writing updated configs info to file");
|
||||
if (!writeConfigsInfo(configsInfo))
|
||||
{
|
||||
ProxyLogger::getInstance().error("Failed to write configs info");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If active config was removed, activate a new one
|
||||
if (needToActivateNew)
|
||||
{
|
||||
ProxyLogger::getInstance().info("Removed active config, need to activate a new one");
|
||||
if (configs.isEmpty())
|
||||
{
|
||||
ProxyLogger::getInstance().info("No configs left, clearing active config");
|
||||
if (!activateConfig(QString()))
|
||||
{
|
||||
ProxyLogger::getInstance().error("Failed to clear active config");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString newActiveUuid = configs.keys().first();
|
||||
ProxyLogger::getInstance().info(QString("Activating new config: %1").arg(newActiveUuid));
|
||||
if (!activateConfig(newActiveUuid))
|
||||
{
|
||||
ProxyLogger::getInstance().error(QString("Failed to activate new config: %1").arg(newActiveUuid));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigManager::activateConfig(const QString &uuid)
|
||||
{
|
||||
ProxyLogger::getInstance().info(QString("Activating config: %1").arg(uuid.isEmpty() ? "none" : uuid));
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
QJsonObject configs = configsInfo["configs"].toObject();
|
||||
|
||||
// Reset isActive flag for all configs
|
||||
for (auto it = configs.begin(); it != configs.end(); ++it) {
|
||||
QJsonObject config = it.value().toObject();
|
||||
config["isActive"] = false;
|
||||
it.value() = config;
|
||||
}
|
||||
|
||||
// If uuid is empty, just reset active config
|
||||
if (uuid.isEmpty())
|
||||
{
|
||||
ProxyLogger::getInstance().info("Resetting active config");
|
||||
m_activeConfigUuid = QString();
|
||||
configsInfo["activeConfigUuid"] = QString();
|
||||
configsInfo["configs"] = configs;
|
||||
|
||||
// Write changes to the configs info file
|
||||
if (!writeConfigsInfo(configsInfo)) {
|
||||
ProxyLogger::getInstance().error("Failed to write configs info file");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the active config file
|
||||
ProxyLogger::getInstance().debug("Removing active config file");
|
||||
return removeActiveConfigFile();
|
||||
}
|
||||
|
||||
// Check if config exists
|
||||
if (!configs.contains(uuid))
|
||||
{
|
||||
ProxyLogger::getInstance().error(QString("Config with UUID %1 not found").arg(uuid));
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject currentConfigInfo = configs[uuid].toObject();
|
||||
ProxyLogger::getInstance().info(QString("Activating config: Name=%1, Protocol=%2")
|
||||
.arg(currentConfigInfo["name"].toString())
|
||||
.arg(currentConfigInfo["protocol"].toString()));
|
||||
|
||||
QString serializedConfig = currentConfigInfo["serializedConfig"].toString();
|
||||
|
||||
// Deserialize config and add inbounds
|
||||
QString prefix;
|
||||
QString errorMsg;
|
||||
ProxyLogger::getInstance().debug("Deserializing config for activation");
|
||||
QJsonObject currentConfig = deserializeConfig(serializedConfig, &prefix, &errorMsg);
|
||||
if (currentConfig.isEmpty())
|
||||
{
|
||||
ProxyLogger::getInstance().error(QString("Failed to deserialize config: %1").arg(errorMsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Adding inbounds to config");
|
||||
currentConfig = addInbounds(currentConfig);
|
||||
|
||||
// Update lastUsed and isActive
|
||||
currentConfigInfo["lastUsed"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
currentConfigInfo["isActive"] = true;
|
||||
configs[uuid] = currentConfigInfo;
|
||||
configsInfo["configs"] = configs;
|
||||
|
||||
// Update active config
|
||||
m_activeConfigUuid = uuid;
|
||||
configsInfo["activeConfigUuid"] = uuid;
|
||||
|
||||
// Save changes
|
||||
ProxyLogger::getInstance().debug("Writing updated configs info");
|
||||
if (!writeConfigsInfo(configsInfo))
|
||||
{
|
||||
ProxyLogger::getInstance().error("Failed to write configs info file");
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Writing new active config file");
|
||||
return writeActiveConfig(currentConfig);
|
||||
}
|
||||
|
||||
QJsonObject ConfigManager::getActiveConfig() const
|
||||
{
|
||||
ProxyLogger::getInstance().debug("Getting active config info");
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
QJsonObject configs = configsInfo["configs"].toObject();
|
||||
QString activeUuid = getActiveConfigUuid();
|
||||
|
||||
if (activeUuid.isEmpty() || !configs.contains(activeUuid)) {
|
||||
ProxyLogger::getInstance().debug("No active config found");
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug(QString("Retrieved active config info for UUID: %1").arg(activeUuid));
|
||||
QJsonObject result = configs[activeUuid].toObject();
|
||||
result["id"] = activeUuid;
|
||||
return result;
|
||||
}
|
||||
|
||||
QMap<QString, QJsonObject> ConfigManager::getAllConfigs() const
|
||||
{
|
||||
ProxyLogger::getInstance().debug("Getting all configs");
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
QJsonObject configs = configsInfo["configs"].toObject();
|
||||
|
||||
QMap<QString, QJsonObject> result;
|
||||
for (auto it = configs.begin(); it != configs.end(); ++it)
|
||||
{
|
||||
result[it.key()] = it.value().toObject();
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug(QString("Retrieved %1 configs").arg(result.size()));
|
||||
return result;
|
||||
}
|
||||
|
||||
QMap<QString, QJsonObject> ConfigManager::getConfigsByUuids(const QStringList &uuids) const
|
||||
{
|
||||
ProxyLogger::getInstance().debug(QString("Getting configs for %1 UUIDs").arg(uuids.size()));
|
||||
QMap<QString, QJsonObject> allConfigs = getAllConfigs();
|
||||
if (uuids.isEmpty())
|
||||
{
|
||||
ProxyLogger::getInstance().debug("UUID list is empty, returning all configs");
|
||||
return allConfigs;
|
||||
}
|
||||
|
||||
QMap<QString, QJsonObject> result;
|
||||
for (const QString &uuid : uuids)
|
||||
{
|
||||
if (allConfigs.contains(uuid))
|
||||
{
|
||||
ProxyLogger::getInstance().debug(QString("Found config for UUID: %1").arg(uuid));
|
||||
result[uuid] = allConfigs[uuid];
|
||||
}
|
||||
else
|
||||
{
|
||||
ProxyLogger::getInstance().warning(QString("Config not found for UUID: %1").arg(uuid));
|
||||
result[uuid] = QJsonObject();
|
||||
const QJsonObject proto = container.value(protoKey).toObject();
|
||||
const QString serialized = proto.value(amnezia::config_key::last_config).toString();
|
||||
if (!serialized.isEmpty()) {
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug(QString("Retrieved %1 configs out of %2 requested").arg(result.size()).arg(uuids.size()));
|
||||
return result;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool ConfigManager::updateAllConfigs(const QStringList &serializedConfigs)
|
||||
QString ConfigManager::tempDirectory() const
|
||||
{
|
||||
ProxyLogger::getInstance().info(QString("Updating all configs with %1 new config(s)").arg(serializedConfigs.size()));
|
||||
|
||||
ProxyLogger::getInstance().debug("Clearing existing configs");
|
||||
if (!clearConfigs()) {
|
||||
ProxyLogger::getInstance().error("Failed to clear existing configs");
|
||||
return false;
|
||||
const QString baseDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
if (baseDir.isEmpty()) {
|
||||
return QDir::temp().filePath(QStringLiteral("amnezia_local_proxy"));
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Adding new configs");
|
||||
bool success = addConfigs(serializedConfigs);
|
||||
if (success) {
|
||||
ProxyLogger::getInstance().info("Successfully updated all configs");
|
||||
} else {
|
||||
ProxyLogger::getInstance().error("Failed to add new configs");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ConfigManager::clearConfigs()
|
||||
{
|
||||
ProxyLogger::getInstance().info("Clearing all configs");
|
||||
QJsonObject configsInfo = readConfigsInfo();
|
||||
configsInfo["configs"] = QJsonObject();
|
||||
|
||||
if (!writeConfigsInfo(configsInfo)) {
|
||||
ProxyLogger::getInstance().error("Failed to clear configs info");
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug("Resetting active config");
|
||||
bool success = activateConfig(QString());
|
||||
if (success) {
|
||||
ProxyLogger::getInstance().info("Successfully cleared all configs");
|
||||
} else {
|
||||
ProxyLogger::getInstance().error("Failed to reset active config");
|
||||
}
|
||||
return success;
|
||||
return QDir(baseDir).filePath(QStringLiteral("local_proxy"));
|
||||
}
|
||||
Reference in New Issue
Block a user