fix: Fix local proxy UI

This commit is contained in:
aiamnezia
2026-02-13 15:46:27 +04:00
parent 4c2010244b
commit 6518d4866e
14 changed files with 263 additions and 82 deletions
+19 -31
View File
@@ -5,11 +5,11 @@
#include "core/api/apiUtils.h"
#include "core/controllers/gatewayController.h"
#include "core/defs.h"
#include "portavailabilityhelper.h"
#include "proxylogger.h"
#include "settings.h"
#include "version.h"
#include <QHostAddress>
#include <QDir>
#include <QFile>
#include <QJsonArray>
@@ -18,7 +18,6 @@
#include <QSaveFile>
#include <QSysInfo>
#include <QStandardPaths>
#include <QTcpServer>
#include <QUuid>
ConfigManager::ConfigManager(const std::shared_ptr<Settings> &settings)
@@ -84,18 +83,6 @@ QString ConfigManager::serializeConfig(const QJsonObject &config) const
return QString::fromUtf8(QJsonDocument(config).toJson(QJsonDocument::Compact));
}
bool ConfigManager::isPortAvailable(int port) const
{
if (port < kProxyPortMin || port > kProxyPortMax) {
return false;
}
QTcpServer server;
const bool success = server.listen(QHostAddress::LocalHost, static_cast<quint16>(port));
server.close();
return success;
}
std::optional<ConfigManager::ConfigData> ConfigManager::buildConfig(QString &errorDescription) const
{
errorDescription.clear();
@@ -223,29 +210,30 @@ std::optional<ConfigManager::ConfigData> ConfigManager::buildConfigWithFetch(QSt
data.parsedConfig = doc.object();
int selectedPort = resolveProxyPort(m_settings);
const int startPort = selectedPort;
const bool isUserDefinedPort = m_settings->isLocalProxyPortUserDefined();
bool found = false;
for (int port = selectedPort; port <= kProxyPortMax; ++port) {
if (isPortAvailable(port)) {
selectedPort = port;
found = true;
break;
if (!PortAvailabilityHelper::isPortAvailable(selectedPort)) {
const bool canAutoSelect = !isUserDefinedPort && selectedPort == kDefaultProxyPort;
if (canAutoSelect) {
const auto freePort = PortAvailabilityHelper::findFirstAvailablePort(kDefaultProxyPort + 1, kProxyPortMax);
if (!freePort) {
errorDescription = QStringLiteral("No available local proxy port in range %1-%2")
.arg(kDefaultProxyPort + 1)
.arg(kProxyPortMax);
ProxyLogger::getInstance().error(errorDescription);
return std::nullopt;
}
selectedPort = *freePort;
} else {
errorDescription = QStringLiteral("Local proxy port %1 is already in use")
.arg(selectedPort);
ProxyLogger::getInstance().error(errorDescription);
return std::nullopt;
}
}
if (!found) {
errorDescription = QStringLiteral("No available local proxy port in range %1-%2")
.arg(startPort)
.arg(kProxyPortMax);
ProxyLogger::getInstance().error(errorDescription);
return std::nullopt;
}
if (applyProxyPortToConfig(data.parsedConfig, selectedPort)) {
data.serializedConfig = serializeConfig(data.parsedConfig);
if (m_settings && m_settings->localProxyPort() != static_cast<quint16>(selectedPort)) {
m_settings->setLocalProxyPort(static_cast<quint16>(selectedPort));
}
} else {
ProxyLogger::getInstance().warning(QStringLiteral("Failed to override local proxy inbound port; using original config"));
data.serializedConfig = *serializedConfig;
-1
View File
@@ -32,7 +32,6 @@ private:
QString tempDirectory() const;
bool applyProxyPortToConfig(QJsonObject &config, int port) const;
QString serializeConfig(const QJsonObject &config) const;
bool isPortAvailable(int port) const;
std::shared_ptr<Settings> m_settings;
};
@@ -0,0 +1,43 @@
#include "portavailabilityhelper.h"
#include <QHostAddress>
#include <QTcpServer>
namespace {
constexpr int kProxyPortMin = 1024;
constexpr int kProxyPortMax = 65535;
}
bool PortAvailabilityHelper::isPortAvailable(int port)
{
if (port < kProxyPortMin || port > kProxyPortMax) {
return false;
}
QTcpServer server;
const bool success = server.listen(QHostAddress::LocalHost, static_cast<quint16>(port));
server.close();
return success;
}
std::optional<int> PortAvailabilityHelper::findFirstAvailablePort(int startPort, int endPort)
{
if (startPort < kProxyPortMin) {
startPort = kProxyPortMin;
}
if (endPort > kProxyPortMax) {
endPort = kProxyPortMax;
}
if (startPort > endPort) {
return std::nullopt;
}
for (int port = startPort; port <= endPort; ++port) {
if (isPortAvailable(port)) {
return port;
}
}
return std::nullopt;
}
@@ -0,0 +1,11 @@
#pragma once
#include <optional>
class PortAvailabilityHelper
{
public:
static bool isPortAvailable(int port);
static std::optional<int> findFirstAvailablePort(int startPort, int endPort);
};
+14 -7
View File
@@ -65,11 +65,11 @@ void ProxyServer::stopXrayProcess()
m_service->stopXray();
}
void ProxyServer::syncSettings()
bool ProxyServer::syncSettings()
{
if (!m_isRunning) {
qDebug() << "Local proxy: syncSettings called but server is not running";
return;
return false;
}
const quint16 newProxyPort = m_settings ? m_settings->localProxyPort() : 0;
@@ -77,14 +77,21 @@ void ProxyServer::syncSettings()
if (!xrayRunning) {
qInfo() << "Local proxy: starting Xray on port" << newProxyPort;
m_currentProxyPort = newProxyPort;
startXrayProcess();
return;
const bool started = startXrayProcess();
if (started) {
m_currentProxyPort = newProxyPort;
}
return started;
}
if (m_currentProxyPort != newProxyPort) {
qInfo() << "Local proxy: proxy port changed from" << m_currentProxyPort << "to" << newProxyPort;
m_currentProxyPort = newProxyPort;
m_service->restartXray();
const bool restarted = m_service->restartXray();
if (restarted) {
m_currentProxyPort = newProxyPort;
}
return restarted;
}
return true;
}
+1 -1
View File
@@ -20,7 +20,7 @@ public:
bool start(quint16 port = 49490);
void stop();
void syncSettings();
bool syncSettings();
private:
bool startXrayProcess();