Files
amnezia-client/client/core/controllers/serversController.cpp
vkamn 06372c8fd7 refactor: remove serverConfig struct (#2595)
* refactor: remove serverConfig struct

* refactor: add warnings for api v1 configs

* refactor: moved the server type definition to a separate namespace

* refactor: simplified gateway stacks

* fix: fixed server description

* fix: fixed postAsync reply usage

* fix: fixed validateConfig call

* fix: fixed server name in notifications

* fix: fixed initPrepareConfigHandler for lagacy configs
2026-05-15 12:33:36 +08:00

415 lines
14 KiB
C++

#include "serversController.h"
#include "core/utils/serverConfigUtils.h"
#include "core/utils/protocolEnum.h"
#include "core/protocols/protocolUtils.h"
#include "core/utils/constants/configKeys.h"
#include "core/models/containerConfig.h"
#include "core/models/serverDescription.h"
#if defined(Q_OS_IOS) || defined(MACOS_NE)
#include <AmneziaVPN-Swift.h>
#endif
ServersController::ServersController(SecureServersRepository *serversRepository,
SecureAppSettingsRepository *appSettingsRepository, QObject *parent)
: QObject(parent), m_serversRepository(serversRepository), m_appSettingsRepository(appSettingsRepository)
{
ensureDefaultServerValid();
}
void ServersController::ensureDefaultServerValid()
{
if (!getServersCount()) {
return;
}
const QString defaultId = getDefaultServerId();
if (!defaultId.isEmpty() && indexOfServerId(defaultId) >= 0) {
return;
}
const QString firstId = getServerId(0);
if (!firstId.isEmpty()) {
setDefaultServer(firstId);
}
}
bool ServersController::renameServer(const QString &serverId, const QString &name)
{
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
switch (kind) {
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
if (!cfg.has_value()) return false;
cfg->description = name;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true;
}
case serverConfigUtils::ConfigType::SelfHostedUser: {
auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
if (!cfg.has_value()) return false;
cfg->description = name;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true;
}
case serverConfigUtils::ConfigType::Native: {
auto cfg = m_serversRepository->nativeConfig(serverId);
if (!cfg.has_value()) return false;
cfg->description = name;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true;
}
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
case serverConfigUtils::ConfigType::AmneziaFreeV3:
case serverConfigUtils::ConfigType::ExternalPremium: {
auto cfg = m_serversRepository->apiV2Config(serverId);
if (!cfg.has_value()) return false;
cfg->name = name;
cfg->nameOverriddenByUser = true;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true;
}
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
case serverConfigUtils::ConfigType::AmneziaFreeV2:
case serverConfigUtils::ConfigType::Invalid:
default:
return false;
}
}
void ServersController::removeServer(const QString &serverId)
{
m_serversRepository->removeServer(serverId);
}
void ServersController::setDefaultServer(const QString &serverId)
{
m_serversRepository->setDefaultServer(serverId);
}
void ServersController::setDefaultContainer(const QString &serverId, DockerContainer container)
{
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
switch (kind) {
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
if (!cfg.has_value()) return;
cfg->defaultContainer = container;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return;
}
case serverConfigUtils::ConfigType::SelfHostedUser: {
auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
if (!cfg.has_value()) return;
cfg->defaultContainer = container;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return;
}
case serverConfigUtils::ConfigType::Native: {
auto cfg = m_serversRepository->nativeConfig(serverId);
if (!cfg.has_value()) return;
cfg->defaultContainer = container;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return;
}
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
case serverConfigUtils::ConfigType::AmneziaFreeV3:
case serverConfigUtils::ConfigType::ExternalPremium: {
auto cfg = m_serversRepository->apiV2Config(serverId);
if (!cfg.has_value()) return;
cfg->defaultContainer = container;
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return;
}
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
case serverConfigUtils::ConfigType::AmneziaFreeV2:
case serverConfigUtils::ConfigType::Invalid:
default:
return;
}
}
QVector<ServerDescription> ServersController::buildServerDescriptions(bool isAmneziaDnsEnabled) const
{
QVector<ServerDescription> out;
const QVector<QString> ids = m_serversRepository->orderedServerIds();
out.reserve(ids.size());
for (const QString &id : ids) {
ServerDescription d;
using Kind = serverConfigUtils::ConfigType;
const Kind kind = m_serversRepository->serverKind(id);
switch (kind) {
case Kind::SelfHostedAdmin: {
const auto cfg = m_serversRepository->selfHostedAdminConfig(id);
if (!cfg) {
continue;
}
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
break;
}
case Kind::SelfHostedUser: {
const auto cfg = m_serversRepository->selfHostedUserConfig(id);
if (!cfg) {
continue;
}
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
break;
}
case Kind::Native: {
const auto cfg = m_serversRepository->nativeConfig(id);
if (!cfg) {
continue;
}
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
break;
}
case Kind::AmneziaPremiumV2:
case Kind::AmneziaFreeV3:
case Kind::ExternalPremium: {
const auto cfg = m_serversRepository->apiV2Config(id);
if (!cfg) {
continue;
}
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
break;
}
case Kind::AmneziaPremiumV1:
case Kind::AmneziaFreeV2: {
const auto cfg = m_serversRepository->legacyApiConfig(id);
if (!cfg) {
continue;
}
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
break;
}
case Kind::Invalid:
default:
continue;
}
d.serverId = id;
out.append(d);
}
return out;
}
QMap<DockerContainer, ContainerConfig> ServersController::getServerContainersMap(const QString &serverId) const
{
switch (m_serversRepository->serverKind(serverId)) {
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
}
case serverConfigUtils::ConfigType::SelfHostedUser: {
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
}
case serverConfigUtils::ConfigType::Native: {
const auto cfg = m_serversRepository->nativeConfig(serverId);
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
}
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
case serverConfigUtils::ConfigType::AmneziaFreeV3:
case serverConfigUtils::ConfigType::ExternalPremium: {
const auto cfg = m_serversRepository->apiV2Config(serverId);
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
}
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
case serverConfigUtils::ConfigType::AmneziaFreeV2: {
const auto cfg = m_serversRepository->legacyApiConfig(serverId);
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
}
case serverConfigUtils::ConfigType::Invalid:
default:
return {};
}
}
DockerContainer ServersController::getDefaultContainer(const QString &serverId) const
{
switch (m_serversRepository->serverKind(serverId)) {
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
}
case serverConfigUtils::ConfigType::SelfHostedUser: {
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
}
case serverConfigUtils::ConfigType::Native: {
const auto cfg = m_serversRepository->nativeConfig(serverId);
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
}
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
case serverConfigUtils::ConfigType::AmneziaFreeV3:
case serverConfigUtils::ConfigType::ExternalPremium: {
const auto cfg = m_serversRepository->apiV2Config(serverId);
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
}
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
case serverConfigUtils::ConfigType::AmneziaFreeV2: {
const auto cfg = m_serversRepository->legacyApiConfig(serverId);
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
}
case serverConfigUtils::ConfigType::Invalid:
default:
return DockerContainer::None;
}
}
ContainerConfig ServersController::getContainerConfig(const QString &serverId, DockerContainer container) const
{
return getServerContainersMap(serverId).value(container);
}
int ServersController::getDefaultServerIndex() const
{
return m_serversRepository->defaultServerIndex();
}
QString ServersController::getDefaultServerId() const
{
return m_serversRepository->defaultServerId();
}
int ServersController::getServersCount() const
{
return m_serversRepository->serversCount();
}
QString ServersController::getServerId(int serverIndex) const
{
return m_serversRepository->serverIdAt(serverIndex);
}
int ServersController::indexOfServerId(const QString &serverId) const
{
return m_serversRepository->indexOfServerId(serverId);
}
QString ServersController::notificationDisplayName(const QString &serverId) const
{
if (serverId.isEmpty()) {
return {};
}
using Kind = serverConfigUtils::ConfigType;
switch (m_serversRepository->serverKind(serverId)) {
case Kind::SelfHostedAdmin: {
if (const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId)) {
if (!cfg->displayName.isEmpty()) {
return cfg->displayName;
}
}
break;
}
case Kind::SelfHostedUser: {
if (const auto cfg = m_serversRepository->selfHostedUserConfig(serverId)) {
if (!cfg->displayName.isEmpty()) {
return cfg->displayName;
}
}
break;
}
case Kind::Native: {
if (const auto cfg = m_serversRepository->nativeConfig(serverId)) {
if (!cfg->displayName.isEmpty()) {
return cfg->displayName;
}
}
break;
}
case Kind::AmneziaPremiumV2:
case Kind::AmneziaFreeV3:
case Kind::ExternalPremium: {
if (const auto cfg = m_serversRepository->apiV2Config(serverId)) {
if (!cfg->displayName.isEmpty()) {
return cfg->displayName;
}
}
break;
}
case Kind::AmneziaPremiumV1:
case Kind::AmneziaFreeV2: {
if (const auto cfg = m_serversRepository->legacyApiConfig(serverId)) {
if (!cfg->displayName.isEmpty()) {
return cfg->displayName;
}
}
break;
}
default:
break;
}
const int idx = indexOfServerId(serverId);
if (idx >= 0) {
return QString::number(idx + 1);
}
return serverId;
}
std::optional<ApiV2ServerConfig> ServersController::apiV2Config(const QString &serverId) const
{
return m_serversRepository->apiV2Config(serverId);
}
std::optional<SelfHostedAdminServerConfig> ServersController::selfHostedAdminConfig(const QString &serverId) const
{
return m_serversRepository->selfHostedAdminConfig(serverId);
}
ServerCredentials ServersController::getServerCredentials(const QString &serverId) const
{
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
if (cfg.has_value()) {
const ServerCredentials creds = cfg->credentials();
if (creds.isValid()) {
return creds;
}
}
return ServerCredentials {};
}
bool ServersController::isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType,
const QString &serviceProtocol) const
{
const QVector<QString> ids = m_serversRepository->orderedServerIds();
for (const QString &id : ids) {
const auto apiV2 = m_serversRepository->apiV2Config(id);
if (!apiV2.has_value()) {
continue;
}
if (apiV2->apiConfig.userCountryCode == userCountryCode && apiV2->serviceType() == serviceType
&& apiV2->serviceProtocol() == serviceProtocol) {
return true;
}
}
return false;
}
bool ServersController::hasInstalledContainers(const QString &serverId) const
{
const QMap<DockerContainer, ContainerConfig> containers = getServerContainersMap(serverId);
for (auto it = containers.begin(); it != containers.end(); ++it) {
DockerContainer container = it.key();
if (ContainerUtils::containerService(container) == ServiceType::Vpn) {
return true;
}
if (container == DockerContainer::SSXray) {
return true;
}
}
return false;
}
bool ServersController::isLegacyApiV1Server(const QString &serverId) const
{
return !serverId.isEmpty()
&& serverConfigUtils::isLegacyApiSubscription(m_serversRepository->serverKind(serverId));
}