feat: made API port static and proxy port configurable

This commit is contained in:
aiamnezia
2026-01-27 11:09:27 +04:00
parent 35c2e1564b
commit 5fab8363e7
8 changed files with 124 additions and 38 deletions

View File

@@ -37,6 +37,8 @@ CoreController::CoreController(const QSharedPointer<VpnConnection> &vpnConnectio
void CoreController::initLocalProxy()
{
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
constexpr quint16 kLocalProxyApiPort = 49490;
m_proxyServer.reset(new ProxyServer(m_settings, this));
auto syncLocalProxy = [this]() {
@@ -45,7 +47,6 @@ void CoreController::initLocalProxy()
}
const bool httpEnabled = m_settings->isLocalProxyHttpEnabled();
const quint16 port = m_settings->localProxyPort();
if (!httpEnabled) {
qInfo() << "Local proxy: HTTP API disabled";
@@ -53,22 +54,16 @@ void CoreController::initLocalProxy()
return;
}
if (port < 1024) {
qWarning() << "Local proxy: invalid HTTP API port" << port << ", stopping server";
m_proxyServer->stop();
m_settings->setLocalProxyHttpEnabled(false);
emit m_settings->localProxyStartFailed(tr("Local proxy disabled: invalid HTTP API port."));
return;
}
if (!m_proxyServer->start(port)) {
qWarning() << "Local proxy: failed to start on port" << port;
if (!m_proxyServer->start(kLocalProxyApiPort)) {
qWarning() << "Local proxy: failed to start on port" << kLocalProxyApiPort;
m_settings->setLocalProxyHttpEnabled(false);
emit m_settings->localProxyStartFailed(tr("Local proxy failed to start. Check if the port is available."));
return;
}
qInfo() << "Local proxy: running on 127.0.0.1:" << port;
m_proxyServer->syncSettings();
qInfo() << "Local proxy: running on 127.0.0.1:" << kLocalProxyApiPort;
};
syncLocalProxy();

View File

@@ -38,6 +38,45 @@ constexpr char appVersion[] = "app_version";
constexpr char publicKey[] = "public_key";
constexpr char vless[] = "vless";
} // namespace gateway_key
constexpr quint16 kDefaultProxyPort = 10808;
int resolveProxyPort(const std::shared_ptr<Settings> &settings)
{
if (!settings) {
return kDefaultProxyPort;
}
const quint16 port = settings->localProxyPort();
if (port < 1024 || port > 65535) {
return kDefaultProxyPort;
}
return static_cast<int>(port);
}
bool applyProxyPortToConfig(QJsonObject &config, int port)
{
if (!config.contains("inbounds") || !config.value("inbounds").isArray()) {
return false;
}
QJsonArray inbounds = config.value("inbounds").toArray();
if (inbounds.isEmpty() || !inbounds.at(0).isObject()) {
return false;
}
QJsonObject firstInbound = inbounds.at(0).toObject();
firstInbound.insert("port", port);
inbounds[0] = firstInbound;
config.insert("inbounds", inbounds);
return true;
}
QString serializeConfig(const QJsonObject &config)
{
return QString::fromUtf8(QJsonDocument(config).toJson(QJsonDocument::Compact));
}
} // namespace
std::optional<ConfigManager::ConfigData> ConfigManager::buildConfig(QString &errorDescription) const
@@ -96,8 +135,14 @@ std::optional<ConfigManager::ConfigData> ConfigManager::buildConfig(QString &err
ConfigData data;
data.ownerUuid = ownerUuid;
data.serverName = ownerServer->value(amnezia::config_key::name).toString();
data.serializedConfig = *serializedConfig;
data.parsedConfig = doc.object();
const int proxyPort = resolveProxyPort(m_settings);
if (applyProxyPortToConfig(data.parsedConfig, proxyPort)) {
data.serializedConfig = serializeConfig(data.parsedConfig);
} else {
ProxyLogger::getInstance().warning(QStringLiteral("Failed to override local proxy inbound port; using original config"));
data.serializedConfig = *serializedConfig;
}
return data;
}
@@ -158,8 +203,14 @@ std::optional<ConfigManager::ConfigData> ConfigManager::buildConfigWithFetch(QSt
ConfigData data;
data.ownerUuid = ownerUuid;
data.serverName = ownerServer->value(amnezia::config_key::name).toString();
data.serializedConfig = *serializedConfig;
data.parsedConfig = doc.object();
const int proxyPort = resolveProxyPort(m_settings);
if (applyProxyPortToConfig(data.parsedConfig, proxyPort)) {
data.serializedConfig = serializeConfig(data.parsedConfig);
} else {
ProxyLogger::getInstance().warning(QStringLiteral("Failed to override local proxy inbound port; using original config"));
data.serializedConfig = *serializedConfig;
}
return data;
}

View File

@@ -1,15 +1,11 @@
#include "proxyserver.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include "settings.h"
#include <QDebug>
#include <QStandardPaths>
ProxyServer::ProxyServer(const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent)
, m_settings(settings)
, m_service(new ProxyService(settings, this))
{
}
@@ -22,7 +18,7 @@ ProxyServer::~ProxyServer()
bool ProxyServer::start(quint16 port)
{
if (m_isRunning) {
if (m_currentPort == port) {
if (m_currentApiPort == port) {
qInfo() << "Local proxy: already running on port" << port;
return true;
}
@@ -37,20 +33,12 @@ bool ProxyServer::start(quint16 port)
qWarning() << "Local proxy: port is busy:" << port;
m_api.reset();
m_isRunning = false;
m_currentPort = 0;
m_currentApiPort = 0;
return false;
}
// Auto-start Xray if config exists
QJsonObject config = m_service->getConfig();
if (!config.isEmpty()) {
startXrayProcess();
} else {
qDebug() << "No config found, Xray will not start automatically";
}
m_isRunning = true;
m_currentPort = port;
m_currentApiPort = port;
return true;
}
@@ -63,7 +51,8 @@ void ProxyServer::stop()
m_api.reset();
}
m_isRunning = false;
m_currentPort = 0;
m_currentApiPort = 0;
m_currentProxyPort = 0;
}
bool ProxyServer::startXrayProcess()
@@ -74,4 +63,28 @@ bool ProxyServer::startXrayProcess()
void ProxyServer::stopXrayProcess()
{
m_service->stopXray();
}
void ProxyServer::syncSettings()
{
if (!m_isRunning) {
qDebug() << "Local proxy: syncSettings called but server is not running";
return;
}
const quint16 newProxyPort = m_settings ? m_settings->localProxyPort() : 0;
const bool xrayRunning = m_service->isXrayRunning();
if (!xrayRunning) {
qInfo() << "Local proxy: starting Xray on port" << newProxyPort;
m_currentProxyPort = newProxyPort;
startXrayProcess();
return;
}
if (m_currentProxyPort != newProxyPort) {
qInfo() << "Local proxy: proxy port changed from" << m_currentProxyPort << "to" << newProxyPort;
m_currentProxyPort = newProxyPort;
m_service->restartXray();
}
}

View File

@@ -18,15 +18,18 @@ public:
explicit ProxyServer(const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
~ProxyServer();
bool start(quint16 port = 8080);
bool start(quint16 port = 49490);
void stop();
void syncSettings();
private:
bool startXrayProcess();
void stopXrayProcess();
std::shared_ptr<Settings> m_settings;
QScopedPointer<HttpApi> m_api;
QSharedPointer<ProxyService> m_service;
bool m_isRunning {false};
quint16 m_currentPort {0};
quint16 m_currentApiPort {0};
quint16 m_currentProxyPort {0};
};

View File

@@ -89,4 +89,25 @@ qint64 ProxyService::getXrayProcessId() const
QString ProxyService::getXrayError() const
{
return m_xrayController->getError();
}
void ProxyService::clearCache()
{
m_cachedConfig = QJsonObject();
ProxyLogger::getInstance().debug("ProxyService cache cleared");
}
bool ProxyService::restartXray()
{
ProxyLogger::getInstance().info("Restarting Xray with updated config");
clearCache();
if (m_xrayController->isXrayRunning()) {
if (!stopXray()) {
ProxyLogger::getInstance().error("Failed to stop Xray during restart, aborting");
return false;
}
}
return startXray();
}

View File

@@ -25,6 +25,9 @@ public:
qint64 getXrayProcessId() const override;
QString getXrayError() const override;
void clearCache();
bool restartXray();
signals:
void xrayStatusChanged(bool running);

View File

@@ -638,7 +638,7 @@ void Settings::setLocalProxyOwnerUuid(const QString &uuid)
quint16 Settings::localProxyPort() const
{
return value("Conf/localProxyPort", 0).toUInt();
return value("Conf/localProxyPort", 10808).toUInt();
}
void Settings::setLocalProxyPort(quint16 port)

View File

@@ -135,7 +135,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("HTTP API port")
headerText: qsTr("Local proxy port")
enabled: true
@@ -182,7 +182,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("HTTP API controls Xray via /api/v1/up and /api/v1/down. SOCKS inbound stays on port 10808.")
text: qsTr("SOCKS inbound listens on the specified port. Connect your client to 127.0.0.1.")
}
}
}