mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
refactor: enhance XrayController to use IPC for process management
- Replaced direct process management with IPC calls for starting and stopping the Xray process. - Improved error handling for IPC communication and config file loading. - Removed unused methods and variables related to direct process handling. - Updated logging to reflect changes in process management.
This commit is contained in:
@@ -155,10 +155,15 @@ QJsonObject HttpApi::handlePostUp()
|
||||
QJsonObject HttpApi::handlePostDown()
|
||||
{
|
||||
if (auto service = m_service.lock()) {
|
||||
service->stopXray();
|
||||
const bool stopped = service->stopXray();
|
||||
QJsonObject response;
|
||||
response["status"] = "success";
|
||||
response["message"] = "Xray process stopped";
|
||||
if (stopped) {
|
||||
response["status"] = "ok";
|
||||
response["description"] = "Xray process stopped";
|
||||
} else {
|
||||
response["status"] = "error";
|
||||
response["description"] = "Failed to stop xray process";
|
||||
}
|
||||
return response;
|
||||
}
|
||||
return { {"status", "error"}, {"message", "Service unavailable"} };
|
||||
|
||||
@@ -44,10 +44,15 @@ bool ProxyService::startXray()
|
||||
bool ProxyService::stopXray()
|
||||
{
|
||||
ProxyLogger::getInstance().info("Stopping Xray");
|
||||
m_xrayController->stop();
|
||||
ProxyLogger::getInstance().info("Xray stopped");
|
||||
emit xrayStatusChanged(false);
|
||||
return true;
|
||||
const bool stopped = m_xrayController->stop();
|
||||
if (stopped) {
|
||||
ProxyLogger::getInstance().info("Xray stopped");
|
||||
emit xrayStatusChanged(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().warning(QString("Failed to stop Xray: %1").arg(m_xrayController->getError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProxyService::isXrayRunning() const
|
||||
@@ -104,7 +109,10 @@ bool ProxyService::removeConfig(const QString &uuid)
|
||||
emit configsChanged();
|
||||
if (uuid == activeUuid && isXrayRunning()) {
|
||||
ProxyLogger::getInstance().info("Removed active config, restarting Xray");
|
||||
stopXray();
|
||||
if (!stopXray()) {
|
||||
ProxyLogger::getInstance().warning("Failed to stop Xray after removing active config");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if there are any configs left
|
||||
QString newActiveUuid = m_configManager->getActiveConfigUuid();
|
||||
@@ -130,7 +138,10 @@ bool ProxyService::activateConfig(const QString &uuid)
|
||||
// If config is successfully activated, restart Xray
|
||||
if (isXrayRunning()) {
|
||||
ProxyLogger::getInstance().info("Restarting Xray with new config");
|
||||
stopXray();
|
||||
if (!stopXray()) {
|
||||
ProxyLogger::getInstance().warning("Failed to stop Xray while activating new config");
|
||||
return false;
|
||||
}
|
||||
return startXray();
|
||||
}
|
||||
return true;
|
||||
@@ -154,7 +165,10 @@ bool ProxyService::updateAllConfigs(const QStringList &serializedConfigs)
|
||||
emit configsChanged();
|
||||
if (isXrayRunning()) {
|
||||
ProxyLogger::getInstance().info("Restarting Xray with updated configs");
|
||||
stopXray();
|
||||
if (!stopXray()) {
|
||||
ProxyLogger::getInstance().warning("Failed to stop Xray while updating configs");
|
||||
return false;
|
||||
}
|
||||
return startXray();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#include "xraycontroller.h"
|
||||
|
||||
#include "proxylogger.h"
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include "core/ipcclient.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
namespace {
|
||||
const QString kIpcUnavailableError = QStringLiteral("Failed to communicate with IPC service");
|
||||
}
|
||||
|
||||
XrayController::XrayController(QObject *parent)
|
||||
: QObject(parent), m_process(nullptr)
|
||||
: QObject(parent)
|
||||
{
|
||||
ProxyLogger::getInstance().debug("XrayController initialized");
|
||||
}
|
||||
@@ -18,99 +22,106 @@ XrayController::~XrayController()
|
||||
|
||||
bool XrayController::start(const QString &configPath)
|
||||
{
|
||||
if (isXrayRunning())
|
||||
{
|
||||
ProxyLogger::getInstance().info("Xray process is already running");
|
||||
|
||||
if (m_isRunning) {
|
||||
ProxyLogger::getInstance().info("Xray is already running");
|
||||
return true;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().info("Request to start Xray via IPC");
|
||||
|
||||
QString xrayPath = getXrayExecutablePath();
|
||||
ProxyLogger::getInstance().debug(QString("Xray executable path: %1").arg(xrayPath));
|
||||
m_lastError.clear();
|
||||
|
||||
if (!QFile::exists(xrayPath))
|
||||
{
|
||||
ProxyLogger::getInstance().error(QString("Xray binary not found at: %1").arg(xrayPath));
|
||||
QString configContent;
|
||||
if (!loadConfigFile(configPath, configContent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!QFile::exists(configPath))
|
||||
{
|
||||
ProxyLogger::getInstance().error(QString("Config file not found at: %1").arg(configPath));
|
||||
const bool ipcResult = IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
iface->xrayStart(configContent);
|
||||
return true;
|
||||
}, []() {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!ipcResult) {
|
||||
m_lastError = kIpcUnavailableError;
|
||||
ProxyLogger::getInstance().error(m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().info("Starting Xray process");
|
||||
m_process.reset(new QProcess(this));
|
||||
m_process->setWorkingDirectory(QFileInfo(xrayPath).dir().absolutePath());
|
||||
m_process->setProgram(xrayPath);
|
||||
m_process->setArguments(getXrayArguments(configPath));
|
||||
|
||||
m_process->start();
|
||||
if (!m_process->waitForStarted())
|
||||
{
|
||||
ProxyLogger::getInstance().error(QString("Failed to start Xray process: %1").arg(m_process->errorString()));
|
||||
m_process.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().info(QString("Xray process started successfully (PID: %1)").arg(m_process->processId()));
|
||||
ProxyLogger::getInstance().info("Xray start command sent to IPC service");
|
||||
m_isRunning = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void XrayController::stop()
|
||||
bool XrayController::stop()
|
||||
{
|
||||
if (!m_process.isNull())
|
||||
{
|
||||
if (m_process->state() == QProcess::Running)
|
||||
{
|
||||
ProxyLogger::getInstance().info(QString("Killing Xray process (PID: %1)").arg(m_process->processId()));
|
||||
m_process->kill();
|
||||
m_process->waitForFinished(3000);
|
||||
}
|
||||
m_process.reset();
|
||||
ProxyLogger::getInstance().info("Xray process stopped");
|
||||
ProxyLogger::getInstance().info("Stopping Xray via IPC");
|
||||
|
||||
const bool ipcResult = IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
iface->xrayStop();
|
||||
return true;
|
||||
}, []() {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!ipcResult) {
|
||||
m_lastError = kIpcUnavailableError;
|
||||
ProxyLogger::getInstance().warning(m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_isRunning = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XrayController::isXrayRunning() const
|
||||
{
|
||||
return !m_process.isNull() && m_process->state() == QProcess::Running;
|
||||
return m_isRunning;
|
||||
}
|
||||
|
||||
qint64 XrayController::getProcessId() const
|
||||
{
|
||||
return m_process ? m_process->processId() : -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString XrayController::getError() const
|
||||
{
|
||||
if (m_process && m_process->error() != QProcess::UnknownError)
|
||||
{
|
||||
QString error = m_process->errorString();
|
||||
ProxyLogger::getInstance().error(QString("Xray process error: %1").arg(error));
|
||||
return error;
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
bool XrayController::loadConfigFile(const QString &configPath, QString &configContent)
|
||||
{
|
||||
if (configPath.isEmpty()) {
|
||||
m_lastError = "Config path is empty";
|
||||
ProxyLogger::getInstance().error(m_lastError);
|
||||
return false;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString XrayController::getXrayExecutablePath() const
|
||||
{
|
||||
QString xrayDir = QCoreApplication::applicationDirPath() + "/bin";
|
||||
QString xrayPath;
|
||||
QFile configFile(configPath);
|
||||
if (!configFile.exists()) {
|
||||
m_lastError = QString("Config file not found at: %1").arg(configPath);
|
||||
ProxyLogger::getInstance().error(m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
xrayPath = QDir(xrayDir).filePath("xray.exe");
|
||||
#else
|
||||
xrayPath = QDir(xrayDir).filePath("xray");
|
||||
#endif
|
||||
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
m_lastError = QString("Failed to open config file: %1").arg(configFile.errorString());
|
||||
ProxyLogger::getInstance().error(m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxyLogger::getInstance().debug(QString("Resolved Xray executable path: %1").arg(xrayPath));
|
||||
return xrayPath;
|
||||
}
|
||||
QByteArray data = configFile.readAll();
|
||||
configFile.close();
|
||||
|
||||
QStringList XrayController::getXrayArguments(const QString &configPath) const
|
||||
{
|
||||
QStringList args = QStringList() << "-c" << configPath << "-format=json";
|
||||
ProxyLogger::getInstance().debug(QString("Xray arguments: %1").arg(args.join(' ')));
|
||||
return args;
|
||||
if (data.isEmpty()) {
|
||||
m_lastError = QString("Config file is empty: %1").arg(configPath);
|
||||
ProxyLogger::getInstance().error(m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
configContent = QString::fromUtf8(data);
|
||||
ProxyLogger::getInstance().debug(QString("Loaded Xray config from %1").arg(configPath));
|
||||
return true;
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QScopedPointer>
|
||||
#include <QString>
|
||||
|
||||
class XrayController : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -12,14 +11,14 @@ public:
|
||||
~XrayController();
|
||||
|
||||
bool start(const QString& configPath);
|
||||
void stop();
|
||||
bool stop();
|
||||
bool isXrayRunning() const;
|
||||
qint64 getProcessId() const;
|
||||
QString getError() const;
|
||||
|
||||
private:
|
||||
QString getXrayExecutablePath() const;
|
||||
QStringList getXrayArguments(const QString& configPath) const;
|
||||
bool loadConfigFile(const QString& configPath, QString& configContent);
|
||||
|
||||
QScopedPointer<QProcess> m_process;
|
||||
bool m_isRunning {false};
|
||||
QString m_lastError;
|
||||
};
|
||||
Reference in New Issue
Block a user