update: separate XRaySubscriptionConfig from NativeServerConfig and fixed some bugs

This commit is contained in:
MrMirDan
2026-05-16 12:22:26 +03:00
parent 476f16d027
commit 73e0c9b92e
15 changed files with 230 additions and 107 deletions

View File

@@ -16,8 +16,6 @@
#include <QTimer>
#include <algorithm>
#include <iostream>
#include "core/utils/containerEnum.h"
#include "core/utils/containers/containerUtils.h"
#include "core/utils/protocolEnum.h"
@@ -500,9 +498,9 @@ ImportController::ImportResult ImportController::importLink(const QUrl &url)
}
serverConfig.insert(configKey::description, m_appSettingsRepository->nextAvailableServerName());
serverConfig["xray_subscription_config"] = configStrings;
serverConfig["xray_subscription_config_name"] = configNames;
serverConfig["xray_subscription_config_current"] = 0;
serverConfig[configKey::xraySubscriptionConfig] = configStrings;
serverConfig[configKey::xraySubscriptionConfigName] = configNames;
serverConfig[configKey::xraySubscriptionConfigCurrent] = 0;
result.config = serverConfig;
@@ -516,10 +514,8 @@ ImportController::ImportResult ImportController::editServerConfigWithData(QStrin
if (result.errorCode != ErrorCode::NoError)
return result;
const ServerConfig currentServerConfig = m_serversRepository->server(serverIndex);
const QJsonObject currentConfig = m_serversRepository->server(serverIndex).toJson();
QJsonObject editedConfig = result.config;
const QJsonObject currentConfig = currentServerConfig.toJson();
for (auto it = uiConfig.begin(); it != uiConfig.end(); ++it) {
editedConfig.insert(it.key(), it.value());
@@ -529,16 +525,16 @@ ImportController::ImportResult ImportController::editServerConfigWithData(QStrin
editedConfig.insert(configKey::description, currentConfig.value(configKey::description));
}
if (currentConfig.contains("xray_subscription_config")) {
editedConfig.insert("xray_subscription_config", currentConfig.value("xray_subscription_config"));
if (currentConfig.contains(configKey::xraySubscriptionConfig)) {
editedConfig.insert(configKey::xraySubscriptionConfig, currentConfig.value(configKey::xraySubscriptionConfig));
}
if (currentConfig.contains("xray_subscription_config_name")) {
editedConfig.insert("xray_subscription_config_name", currentConfig.value("xray_subscription_config_name"));
if (currentConfig.contains(configKey::xraySubscriptionConfigName)) {
editedConfig.insert(configKey::xraySubscriptionConfigName, currentConfig.value(configKey::xraySubscriptionConfigName));
}
if (currentConfig.contains("xray_subscription_config_current")) {
editedConfig.insert("xray_subscription_config_current", currentConfig.value("xray_subscription_config_current"));
if (currentConfig.contains(configKey::xraySubscriptionConfigCurrent)) {
editedConfig.insert(configKey::xraySubscriptionConfigCurrent, currentConfig.value(configKey::xraySubscriptionConfigCurrent));
}
const ServerConfig finalServerConfig = ServerConfig::fromJson(editedConfig);

View File

@@ -58,29 +58,29 @@ void ServersController::clearCachedProfile(int serverIndex, DockerContainer cont
m_serversRepository->clearLastConnectionConfig(serverIndex, container);
}
void ServersController::setCurrentConfigIndex(const int index)
void ServersController::setCurrentConfigIndex(const int serverIndex, const int index)
{
m_serversRepository->setCurrentConfigIndex(index);
m_serversRepository->setCurrentConfigIndex(serverIndex, index);
}
int ServersController::getCurrentConfigIndex() const
int ServersController::getCurrentConfigIndex(const int serverIndex) const
{
return m_serversRepository->getCurrentConfigIndex();
return m_serversRepository->getCurrentConfigIndex(serverIndex);
}
QString ServersController::getConfigString(const int index) const
QString ServersController::getConfigString(const int serverIndex, const int index) const
{
return m_serversRepository->getConfigString(index);
return m_serversRepository->getConfigString(serverIndex, index);
}
QString ServersController::getConfigName(const int index) const
QString ServersController::getConfigName(const int serverIndex, const int index) const
{
return m_serversRepository->getConfigName(index);
return m_serversRepository->getConfigName(serverIndex, index);
}
QJsonArray ServersController::getConfigNames() const
QJsonArray ServersController::getConfigNames(const int serverIndex) const
{
return m_serversRepository->getConfigNames();
return m_serversRepository->getConfigNames(serverIndex);
}
QJsonArray ServersController::getServersArray() const

View File

@@ -65,11 +65,11 @@ public:
void clearCachedProfile(int serverIndex, DockerContainer container);
// XRay subscription config getters/setters
void setCurrentConfigIndex(int index);
int getCurrentConfigIndex() const;
QString getConfigString(const int index) const;
QString getConfigName(const int index) const;
QJsonArray getConfigNames() const;
void setCurrentConfigIndex(const int serverIndex, int index);
int getCurrentConfigIndex(const int serverIndex) const;
QString getConfigString(const int serverIndex, const int index) const;
QString getConfigName(const int serverIndex, const int index) const;
QJsonArray getConfigNames(const int serverIndex) const;
// Getters
QJsonArray getServersArray() const;

View File

@@ -5,7 +5,6 @@
#include "core/utils/containerEnum.h"
#include "core/utils/containers/containerUtils.h"
#include "core/utils/protocolEnum.h"
#include "core/utils/protocolEnum.h"
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/utils/constants/protocolConstants.h"
@@ -58,18 +57,6 @@ QJsonObject NativeServerConfig::toJson() const
if (!dns2.isEmpty()) {
obj[configKey::dns2] = dns2;
}
if (configString) {
obj[QLatin1String("xray_subscription_config")] = configString.value();
}
if (configName) {
obj[QLatin1String("xray_subscription_config_name")] = configName.value();
}
if (currentConfig) {
obj[QLatin1String("xray_subscription_config_current")] = currentConfig.value();
}
return obj;
}
@@ -98,15 +85,6 @@ NativeServerConfig NativeServerConfig::fromJson(const QJsonObject& json)
config.dns1 = json.value(configKey::dns1).toString();
config.dns2 = json.value(configKey::dns2).toString();
if (json.contains(QLatin1String("xray_subscription_config")))
config.configString = json.value(QLatin1String("xray_subscription_config")).toArray();
if (json.contains(QLatin1String("xray_subscription_config_name")))
config.configName = json.value(QLatin1String("xray_subscription_config_name")).toArray();
if (json.contains(QLatin1String("xray_subscription_config_current")))
config.currentConfig = json.value(QLatin1String("xray_subscription_config_current")).toInt();
return config;
}

View File

@@ -23,10 +23,6 @@ struct NativeServerConfig {
DockerContainer defaultContainer;
QString dns1;
QString dns2;
std::optional<QJsonArray> configString;
std::optional<QJsonArray> configName;
std::optional<int> currentConfig;
bool hasContainers() const;
ContainerConfig containerConfig(DockerContainer container) const;

View File

@@ -0,0 +1,105 @@
#include "xraySubscriptionConfig.h"
#include <QJsonArray>
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/utils/constants/protocolConstants.h"
#include "core/utils/containerEnum.h"
#include "core/utils/containers/containerUtils.h"
#include "core/utils/protocolEnum.h"
namespace amnezia
{
using namespace ContainerEnumNS;
bool XRaySubscriptionConfig::hasContainers() const
{
return !containers.isEmpty();
}
ContainerConfig XRaySubscriptionConfig::containerConfig(DockerContainer container) const
{
if (!containers.contains(container)) {
return ContainerConfig {};
}
return containers.value(container);
}
QJsonObject XRaySubscriptionConfig::toJson() const
{
QJsonObject obj;
if (!description.isEmpty()) {
obj[configKey::description] = this->description;
}
if (!hostName.isEmpty()) {
obj[configKey::hostName] = hostName;
}
QJsonArray containersArray;
for (auto it = containers.begin(); it != containers.end(); ++it) {
QJsonObject containerObj = it.value().toJson();
containersArray.append(containerObj);
}
if (!containersArray.isEmpty()) {
obj[configKey::containers] = containersArray;
}
if (defaultContainer != DockerContainer::None) {
obj[configKey::defaultContainer] = ContainerUtils::containerToString(defaultContainer);
}
if (!dns1.isEmpty()) {
obj[configKey::dns1] = dns1;
}
if (!dns2.isEmpty()) {
obj[configKey::dns2] = dns2;
}
if (!configString.isEmpty()) {
obj[configKey::xraySubscriptionConfig] = configString;
}
if (!configName.isEmpty()) {
obj[configKey::xraySubscriptionConfigName] = configName;
}
if (currentConfig > -1) {
obj[configKey::xraySubscriptionConfigCurrent] = currentConfig;
}
return obj;
}
XRaySubscriptionConfig XRaySubscriptionConfig::fromJson(const QJsonObject &json)
{
XRaySubscriptionConfig config;
config.description = json.value(configKey::description).toString();
config.hostName = json.value(configKey::hostName).toString();
QJsonArray containersArray = json.value(configKey::containers).toArray();
for (const QJsonValue &val : containersArray) {
QJsonObject containerObj = val.toObject();
ContainerConfig containerConfig = ContainerConfig::fromJson(containerObj);
QString containerStr = containerObj.value(configKey::container).toString();
DockerContainer container = ContainerUtils::containerFromString(containerStr);
config.containers.insert(container, containerConfig);
}
QString defaultContainerStr = json.value(configKey::defaultContainer).toString();
config.defaultContainer = ContainerUtils::containerFromString(defaultContainerStr);
config.dns1 = json.value(configKey::dns1).toString();
config.dns2 = json.value(configKey::dns2).toString();
config.configString = json.value(configKey::xraySubscriptionConfig).toArray();
config.configName = json.value(configKey::xraySubscriptionConfigName).toArray();
config.currentConfig = json.value(configKey::xraySubscriptionConfigCurrent).toInt();
return config;
}
} // namespace amnezia

View File

@@ -0,0 +1,40 @@
#ifndef XRAYSUBSCRIPTIONCONFIG_H
#define XRAYSUBSCRIPTIONCONFIG_H
#include <QJsonArray>
#include <QJsonObject>
#include <QMap>
#include <optional>
#include "core/models/containerConfig.h"
#include "core/utils/containerEnum.h"
#include "core/utils/containers/containerUtils.h"
#include "core/utils/protocolEnum.h"
namespace amnezia
{
using namespace ContainerEnumNS;
struct XRaySubscriptionConfig
{
QString description;
QString hostName;
QMap<DockerContainer, ContainerConfig> containers;
DockerContainer defaultContainer;
QString dns1;
QString dns2;
QJsonArray configString;
QJsonArray configName;
int currentConfig;
bool hasContainers() const;
ContainerConfig containerConfig(DockerContainer container) const;
QJsonObject toJson() const;
static XRaySubscriptionConfig fromJson(const QJsonObject &json);
};
} // namespace amnezia
#endif // XRAYSUBSCRIPTIONCONFIG_H

View File

@@ -91,7 +91,7 @@ int ServerConfig::configVersion() const
} else if constexpr (std::is_same_v<T, ApiV2ServerConfig>) {
return apiDefs::ConfigSource::AmneziaGateway;
}
return 0; // SelfHostedServerConfig or NativeServerConfig
return 0; // SelfHostedServerConfig or NativeServerConfig or XRaySubscriptionConfig
}, data);
}
@@ -120,8 +120,9 @@ bool ServerConfig::isApiConfig() const
return isApiV1() || isApiV2();
}
bool ServerConfig::isXRayConfig() const {
return isNative() && std::get<NativeServerConfig>(data).configString.has_value();
bool ServerConfig::isXRayConfig() const
{
return std::holds_alternative<XRaySubscriptionConfig>(data);
}
QJsonObject ServerConfig::toJson() const
@@ -135,6 +136,10 @@ ServerConfig ServerConfig::fromJson(const QJsonObject& json)
switch (configType) {
case apiDefs::ConfigType::SelfHosted: {
if (json.contains(configKey::xraySubscriptionConfig)) {
return ServerConfig {XRaySubscriptionConfig::fromJson(json)};
}
bool hasThirdPartyConfig = false;
QJsonArray containersArray = json.value(configKey::containers).toArray();
for (const QJsonValue& val : containersArray) {

View File

@@ -10,6 +10,7 @@
#include "core/utils/protocolEnum.h"
#include "core/models/selfhosted/selfHostedServerConfig.h"
#include "core/models/selfhosted/nativeServerConfig.h"
#include "core/models/selfhosted/xraySubscriptionConfig.h"
#include "core/models/api/apiV1ServerConfig.h"
#include "core/models/api/apiV2ServerConfig.h"
#include "core/models/containerConfig.h"
@@ -23,6 +24,7 @@ struct ServerConfig {
using Variant = std::variant<
SelfHostedServerConfig,
NativeServerConfig,
XRaySubscriptionConfig,
ApiV1ServerConfig,
ApiV2ServerConfig
>;

View File

@@ -176,71 +176,62 @@ void SecureServersRepository::clearLastConnectionConfig(int serverIndex, DockerC
setContainerConfig(serverIndex, container, containerCfg);
}
void SecureServersRepository::setCurrentConfigIndex(const int index)
void SecureServersRepository::setCurrentConfigIndex(const int serverIndex, const int index)
{
ServerConfig serverConfig = server(m_defaultServerIndex);
NativeServerConfig *xrayConfig = serverConfig.as<NativeServerConfig>();
ServerConfig serverConfig = server(serverIndex);
xrayConfig->currentConfig = index;
editServer(m_defaultServerIndex, serverConfig);
if (serverConfig.isXRayConfig()) {
XRaySubscriptionConfig* xrayConfig = serverConfig.as<XRaySubscriptionConfig>();
if (xrayConfig && xrayConfig->currentConfig != index) {
xrayConfig->currentConfig = index;
editServer(serverIndex, serverConfig);
}
}
}
int SecureServersRepository::getCurrentConfigIndex() const
int SecureServersRepository::getCurrentConfigIndex(const int serverIndex) const
{
const ServerConfig serverConfig = server(m_defaultServerIndex);
ServerConfig serverConfig = server(serverIndex);
if (!serverConfig.isXRayConfig())
return int();
const NativeServerConfig *xrayConfig = serverConfig.as<NativeServerConfig>();
if (!xrayConfig->currentConfig.has_value())
const XRaySubscriptionConfig* xrayConfig = serverConfig.as<XRaySubscriptionConfig>();
if (xrayConfig->currentConfig < 0)
return int();
return xrayConfig->currentConfig.value();
return xrayConfig->currentConfig;
}
QString SecureServersRepository::getConfigString(const int index) const
QString SecureServersRepository::getConfigString(const int serverIndex, const int index) const
{
const ServerConfig serverConfig = server(m_defaultServerIndex);
ServerConfig serverConfig = server(serverIndex);
if (!serverConfig.isXRayConfig())
return QString();
const NativeServerConfig *xrayConfig = serverConfig.as<NativeServerConfig>();
if (!xrayConfig->configString.has_value())
const XRaySubscriptionConfig* xrayConfig = serverConfig.as<XRaySubscriptionConfig>();
if (xrayConfig->configString.isEmpty())
return QString();
if (index < 0 || index >= xrayConfig->configString.value().size())
return QString();
return xrayConfig->configString.value().at(index).toString();
return xrayConfig->configString.at(index).toString();
}
QString SecureServersRepository::getConfigName(const int index) const
QString SecureServersRepository::getConfigName(const int serverIndex, const int index) const
{
const ServerConfig serverConfig = server(m_defaultServerIndex);
if (!serverConfig.isXRayConfig())
return QString();
const NativeServerConfig *xrayConfig = serverConfig.as<NativeServerConfig>();
if (!xrayConfig->configName.has_value())
return QString();
if (index < 0 || index >= xrayConfig->configName.value().size())
return QString();
return xrayConfig->configName.value().at(index).toString();
QJsonArray names = getConfigNames(serverIndex);
return names.at(index).toString();
}
QJsonArray SecureServersRepository::getConfigNames() const
QJsonArray SecureServersRepository::getConfigNames(const int serverIndex) const
{
const ServerConfig serverConfig = server(m_defaultServerIndex);
ServerConfig serverConfig = server(serverIndex);
if (!serverConfig.isXRayConfig())
return QJsonArray();
const NativeServerConfig *xrayConfig = serverConfig.as<NativeServerConfig>();
if (!xrayConfig->configName.has_value())
const XRaySubscriptionConfig* xrayConfig = serverConfig.as<XRaySubscriptionConfig>();
if (xrayConfig->configName.isEmpty())
return QJsonArray();
return xrayConfig->configName.value();
return xrayConfig->configName;
}
ServerCredentials SecureServersRepository::serverCredentials(int index) const

View File

@@ -35,11 +35,11 @@ public:
void setContainerConfig(int serverIndex, DockerContainer container, const ContainerConfig &config);
void clearLastConnectionConfig(int serverIndex, DockerContainer container);
void setCurrentConfigIndex(int index);
int getCurrentConfigIndex() const;
QString getConfigString(const int index) const;
QString getConfigName(const int index) const;
QJsonArray getConfigNames() const;
void setCurrentConfigIndex(const int serverIndex, int index);
int getCurrentConfigIndex(const int serverIndex) const;
QString getConfigString(const int serverIndex, const int index) const;
QString getConfigName(const int serverIndex, const int index) const;
QJsonArray getConfigNames(const int serverIndex) const;
ServerCredentials serverCredentials(int index) const;
bool hasServerWithVpnKey(const QString &vpnKey) const;

View File

@@ -32,6 +32,10 @@ namespace amnezia
constexpr QLatin1String protocol("protocol");
constexpr QLatin1String protocols("protocols");
constexpr QLatin1String xraySubscriptionConfig("xray_subscription_config");
constexpr QLatin1String xraySubscriptionConfigName("xray_subscription_config_name");
constexpr QLatin1String xraySubscriptionConfigCurrent("xray_subscription_config_current");
constexpr QLatin1String remote("remote");
constexpr QLatin1String transportProto("transport_proto");
constexpr QLatin1String cipher("cipher");

View File

@@ -379,6 +379,9 @@ QString ServersUiController::getDefaultServerDescription(const ServerConfig& ser
} else if (server.isApiV1()) {
const ApiV1ServerConfig* apiV1 = server.as<ApiV1ServerConfig>();
return apiV1 ? apiV1->description : QString();
} else if (server.isXRayConfig()) {
const XRaySubscriptionConfig *xray = server.as<XRaySubscriptionConfig>();
return xray ? xray->configName.at(xray->currentConfig).toString() : server.description();
} else {
ServerCredentials credentials = m_serversController->getServerCredentials(index);
if (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty()) {
@@ -461,27 +464,27 @@ QString ServersUiController::adDescription() const
void ServersUiController::setCurrentConfigIndex(const int index)
{
m_serversController->setCurrentConfigIndex(index);
m_serversController->setCurrentConfigIndex(m_processedServerIndex, index);
}
int ServersUiController::getCurrentConfigIndex() const
{
return m_serversController->getCurrentConfigIndex();
return m_serversController->getCurrentConfigIndex(m_processedServerIndex);
}
QString ServersUiController::getConfigString(const int index) const
{
return m_serversController->getConfigString(index);
return m_serversController->getConfigString(m_processedServerIndex, index);
}
QString ServersUiController::getConfigName(const int index) const
{
return m_serversController->getConfigName(index);
return m_serversController->getConfigName(m_processedServerIndex, index);
}
QJsonArray ServersUiController::getConfigNames() const
{
return m_serversController->getConfigNames();
return m_serversController->getConfigNames(m_processedServerIndex);
}
void ServersUiController::updateContainersModel()

View File

@@ -98,7 +98,7 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
}
case ServerDescriptionRole: {
auto description = getServerDescription(server, index.row());
return configVersion ? description : description + server.hostName();
return configVersion ? description : server.isXRayConfig() ? description : description + server.hostName();
}
case HostNameRole: return server.hostName();
case CredentialsRole: return QVariant::fromValue(serverCredentials(index.row()));
@@ -213,7 +213,7 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
}
case IsXRayConfigSelectionAvailableRole: {
if (server.isXRayConfig()) {
return server.as<NativeServerConfig>()->configString.has_value();
return !server.as<XRaySubscriptionConfig>()->configString.isEmpty();
}
}
}
@@ -257,6 +257,9 @@ QString ServersModel::getServerDescription(const ServerConfig &server, const int
} else if (server.isApiV1()) {
const ApiV1ServerConfig *apiV1 = server.as<ApiV1ServerConfig>();
return apiV1 ? apiV1->description : server.description();
} else if (server.isXRayConfig()) {
const XRaySubscriptionConfig *xray = server.as<XRaySubscriptionConfig>();
return xray ? xray->configName.at(xray->currentConfig).toString() : server.description();
} else if (data(index, HasWriteAccessRole).toBool()) {
QMap<DockerContainer, ContainerConfig> containers = server.containers();
bool isDnsInstalled = containers.contains(DockerContainer::Dns);

View File

@@ -68,7 +68,7 @@ ListViewType {
text: name
descriptionText: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
? (isSubscriptionExpired ? qsTr("Subscription expired. Please renew") : qsTr("Subscription expiring soon"))
: (isXRayConfigSelectionAvailable ? ServersUiController.getConfigName(ServersUiController.getCurrentConfigIndex()) : serverDescription)
: serverDescription
descriptionColor: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
? (isSubscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot)
: AmneziaStyle.color.mutedGray