mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 19:00:22 +08:00
614 lines
24 KiB
C++
614 lines
24 KiB
C++
#include "Qv2rayApplication.hpp"
|
|
|
|
#include "3rdparty/libsemver/version.hpp"
|
|
#include "base/Qv2rayBase.hpp"
|
|
#include "common/QvHelpers.hpp"
|
|
#include "common/QvTranslator.hpp"
|
|
#include "core/settings/SettingsBackend.hpp"
|
|
#include "ui/styles/StyleManager.hpp"
|
|
#include "ui/windows/w_MainWindow.hpp"
|
|
|
|
#include <QUrl>
|
|
#include <QUrlQuery>
|
|
|
|
#ifdef QT_DEBUG
|
|
const static inline QString QV2RAY_URL_SCHEME = "qv2ray-debug";
|
|
#else
|
|
const static inline QString QV2RAY_URL_SCHEME = "qv2ray";
|
|
#endif
|
|
|
|
#ifdef Q_OS_WIN
|
|
#include <Winbase.h>
|
|
#endif
|
|
|
|
namespace Qv2ray
|
|
{
|
|
constexpr auto QV2RAY_CONFIG_PATH_ENV_NAME = "QV2RAY_CONFIG_PATH";
|
|
|
|
Qv2rayApplication::Qv2rayApplication(int &argc, char *argv[])
|
|
#ifdef Q_OS_ANDROID
|
|
: QApplication(argc, argv)
|
|
#else
|
|
: SingleApplication(argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion)
|
|
#endif
|
|
{
|
|
LOG(MODULE_INIT, "Qv2ray " QV2RAY_VERSION_STRING " on " + QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture())
|
|
DEBUG(MODULE_INIT, "Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay()))
|
|
DEBUG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO)
|
|
DEBUG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
|
|
DEBUG("QV2RAY_BUILD_NUMBER", QSTRN(QV2RAY_VERSION_BUILD))
|
|
hTray = new QSystemTrayIcon();
|
|
}
|
|
|
|
void Qv2rayApplication::QuitApplication(int retCode)
|
|
{
|
|
isExiting = true;
|
|
QCoreApplication::exit(retCode);
|
|
}
|
|
|
|
Qv2rayApplication::Qv2raySetupStatus Qv2rayApplication::SetupQv2ray()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
SetCurrentDirectory(applicationDirPath().toStdWString().c_str());
|
|
#endif
|
|
// Install a default translater. From the OS/DE
|
|
Qv2rayTranslator = std::make_unique<QvTranslator>();
|
|
Qv2rayTranslator->InstallTranslation(QLocale::system().name());
|
|
//
|
|
setQuitOnLastWindowClosed(false);
|
|
|
|
#ifndef Q_OS_ANDROID
|
|
connect(this, &SingleApplication::receivedMessage, this, &Qv2rayApplication::onMessageReceived, Qt::QueuedConnection);
|
|
connect(this, &SingleApplication::aboutToQuit, this, &Qv2rayApplication::aboutToQuitSlot);
|
|
if (isSecondary())
|
|
{
|
|
if (Qv2rayProcessArgument.arguments.isEmpty())
|
|
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::NORMAL;
|
|
sendMessage(JsonToString(Qv2rayProcessArgument.toJson(), QJsonDocument::Compact).toUtf8());
|
|
return SINGLE_APPLICATION;
|
|
}
|
|
#endif
|
|
|
|
#ifdef Q_OS_WIN
|
|
// Set special font in Windows
|
|
QFont font;
|
|
font.setPointSize(9);
|
|
font.setFamily("Microsoft YaHei");
|
|
setFont(font);
|
|
#endif
|
|
|
|
#ifdef Q_OS_LINUX
|
|
setFallbackSessionManagementEnabled(false);
|
|
connect(this, &QGuiApplication::commitDataRequest, [] {
|
|
RouteManager->SaveRoutes();
|
|
ConnectionManager->SaveConnectionConfig();
|
|
PluginHost->SavePluginSettings();
|
|
SaveGlobalSettings();
|
|
LOG(MODULE_INIT, "Saving settings triggered by session manager.")
|
|
});
|
|
#endif
|
|
return NORMAL;
|
|
}
|
|
|
|
void Qv2rayApplication::aboutToQuitSlot()
|
|
{
|
|
LOG(MODULE_INIT, "Terminating connections and saving data.")
|
|
// Do not change the order.
|
|
ConnectionManager->StopConnection();
|
|
RouteManager->SaveRoutes();
|
|
ConnectionManager->SaveConnectionConfig();
|
|
PluginHost->SavePluginSettings();
|
|
SaveGlobalSettings();
|
|
delete mainWindow;
|
|
delete hTray;
|
|
delete ConnectionManager;
|
|
delete RouteManager;
|
|
delete PluginHost;
|
|
delete StyleManager;
|
|
}
|
|
|
|
void Qv2rayApplication::onMessageReceived(quint32 clientId, QByteArray _msg)
|
|
{
|
|
// Sometimes SingleApplication will send message with clientId == 0, ignore them.
|
|
if (clientId == instanceId())
|
|
return;
|
|
const auto msg = Qv2rayProcessArguments::fromJson(JsonFromString(_msg));
|
|
LOG(MODULE_INIT, "Client ID: " + QSTRN(clientId) + ", message received, version: " + msg.version)
|
|
DEBUG(MODULE_INIT, _msg)
|
|
//
|
|
const auto currentVersion = semver::version::from_string(QV2RAY_VERSION_STRING);
|
|
const auto newVersionString = msg.version.isEmpty() ? "0.0.0" : msg.version.toStdString();
|
|
const auto newVersion = semver::version::from_string(newVersionString);
|
|
//
|
|
if (newVersion > currentVersion)
|
|
{
|
|
const auto newPath = msg.fullArgs.first();
|
|
QString message;
|
|
message += tr("A new version of Qv2ray is attemping to start:") + NEWLINE;
|
|
message += NEWLINE;
|
|
message += tr("New version information: ") + NEWLINE;
|
|
message += tr("Qv2ray version: %1").arg(msg.version) + NEWLINE;
|
|
message += tr("Qv2ray path: %1").arg(newPath) + NEWLINE;
|
|
message += NEWLINE;
|
|
message += tr("Do you want to exit and launch that new version?");
|
|
|
|
const auto result = QvMessageBoxAsk(nullptr, tr("New version detected"), message);
|
|
if (result == QMessageBox::Yes)
|
|
{
|
|
Qv2rayProcessArgument._qvNewVersionPath = newPath;
|
|
QuitApplication(QV2RAY_NEW_VERSION);
|
|
}
|
|
}
|
|
|
|
for (const auto &argument : msg.arguments)
|
|
{
|
|
switch (argument)
|
|
{
|
|
case Qv2rayProcessArguments::EXIT:
|
|
{
|
|
QuitApplication();
|
|
break;
|
|
}
|
|
case Qv2rayProcessArguments::NORMAL:
|
|
{
|
|
mainWindow->show();
|
|
mainWindow->raise();
|
|
mainWindow->activateWindow();
|
|
break;
|
|
}
|
|
case Qv2rayProcessArguments::RECONNECT:
|
|
{
|
|
ConnectionManager->RestartConnection();
|
|
break;
|
|
}
|
|
case Qv2rayProcessArguments::DISCONNECT:
|
|
{
|
|
ConnectionManager->StopConnection();
|
|
break;
|
|
}
|
|
case Qv2rayProcessArguments::QV2RAY_LINK:
|
|
{
|
|
for (const auto &link : msg.links)
|
|
{
|
|
const auto url = QUrl::fromUserInput(link);
|
|
const auto command = url.host();
|
|
auto subcommands = url.path().split("/");
|
|
subcommands.removeAll("");
|
|
QMap<QString, QString> args;
|
|
for (const auto &kvp : QUrlQuery(url).queryItems())
|
|
{
|
|
args.insert(kvp.first, kvp.second);
|
|
}
|
|
if (command == "open")
|
|
{
|
|
emit mainWindow->ProcessCommand(command, subcommands, args);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Qv2rayExitCode Qv2rayApplication::RunQv2ray()
|
|
{
|
|
// Show MainWindow
|
|
mainWindow = new MainWindow();
|
|
if (Qv2rayProcessArgument.arguments.contains(Qv2rayProcessArguments::QV2RAY_LINK))
|
|
{
|
|
for (const auto &link : Qv2rayProcessArgument.links)
|
|
{
|
|
const auto url = QUrl::fromUserInput(link);
|
|
const auto command = url.host();
|
|
auto subcommands = url.path().split("/");
|
|
subcommands.removeAll("");
|
|
QMap<QString, QString> args;
|
|
for (const auto &kvp : QUrlQuery(url).queryItems())
|
|
{
|
|
args.insert(kvp.first, kvp.second);
|
|
}
|
|
if (command == "open")
|
|
{
|
|
emit mainWindow->ProcessCommand(command, subcommands, args);
|
|
}
|
|
}
|
|
}
|
|
#ifdef Q_OS_MACOS
|
|
connect(this, &QApplication::applicationStateChanged, [this](Qt::ApplicationState state) {
|
|
switch (state)
|
|
{
|
|
case Qt::ApplicationActive:
|
|
{
|
|
mainWindow->show();
|
|
mainWindow->raise();
|
|
mainWindow->activateWindow();
|
|
break;
|
|
}
|
|
case Qt::ApplicationHidden:
|
|
case Qt::ApplicationInactive:
|
|
case Qt::ApplicationSuspended: break;
|
|
}
|
|
});
|
|
#endif
|
|
return Qv2rayExitCode(exec());
|
|
}
|
|
|
|
bool Qv2rayApplication::FindAndCreateInitialConfiguration()
|
|
{
|
|
if (initialized)
|
|
{
|
|
LOG(MODULE_INIT, "Qv2ray has already been initialized!")
|
|
return false;
|
|
}
|
|
LOG(MODULE_INIT, "Application exec path: " + applicationDirPath())
|
|
// Non-standard paths needs special handing for "_debug"
|
|
const auto currentPathConfig = applicationDirPath() + "/config" QV2RAY_CONFIG_DIR_SUFFIX;
|
|
const auto homeQv2ray = QDir::homePath() + "/.qv2ray" QV2RAY_CONFIG_DIR_SUFFIX;
|
|
//
|
|
// Standard paths already handles the "_debug" suffix for us.
|
|
const auto configQv2ray = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
|
//
|
|
//
|
|
// Some built-in search paths for Qv2ray to find configs. (load the first one if possible).
|
|
QStringList configFilePaths;
|
|
const auto useManualConfigPath = qEnvironmentVariableIsSet(QV2RAY_CONFIG_PATH_ENV_NAME);
|
|
const auto manualConfigPath = qEnvironmentVariable(QV2RAY_CONFIG_PATH_ENV_NAME);
|
|
if (useManualConfigPath)
|
|
{
|
|
LOG(MODULE_INIT, "Using config path from env: " + manualConfigPath)
|
|
configFilePaths << manualConfigPath;
|
|
}
|
|
else
|
|
{
|
|
configFilePaths << currentPathConfig;
|
|
configFilePaths << configQv2ray;
|
|
configFilePaths << homeQv2ray;
|
|
}
|
|
QString configPath = "";
|
|
bool hasExistingConfig = false;
|
|
|
|
for (const auto &path : configFilePaths)
|
|
{
|
|
// Verify the config path, check if the config file exists and in the
|
|
// correct JSON format. True means we check for config existence as
|
|
// well. ----------------------------------------------|HERE|
|
|
bool isValidConfigPath = CheckSettingsPathAvailability(path, true);
|
|
|
|
// If we already found a valid config file. just simply load it...
|
|
if (hasExistingConfig)
|
|
break;
|
|
|
|
if (isValidConfigPath)
|
|
{
|
|
DEBUG(MODULE_INIT, "Path: " + path + " is valid.")
|
|
configPath = path;
|
|
hasExistingConfig = true;
|
|
}
|
|
else
|
|
{
|
|
LOG(MODULE_INIT, "Path: " + path + " does not contain a valid config file.")
|
|
}
|
|
}
|
|
|
|
if (hasExistingConfig)
|
|
{
|
|
// Use the config path found by the checks above
|
|
SetConfigDirPath(configPath);
|
|
LOG(MODULE_INIT, "Using " + QV2RAY_CONFIG_DIR + " as the config path.")
|
|
}
|
|
else
|
|
{
|
|
// If there's no existing config.
|
|
//
|
|
// Create new config at these dirs, these are default values for each platform.
|
|
if (useManualConfigPath)
|
|
{
|
|
configPath = manualConfigPath;
|
|
}
|
|
else
|
|
{
|
|
#if defined(Q_OS_WIN) && !defined(QV2RAY_NO_ASIDECONFIG)
|
|
configPath = currentPathConfig;
|
|
#else
|
|
configPath = configQv2ray;
|
|
#endif
|
|
}
|
|
|
|
bool hasPossibleNewLocation = QDir().mkpath(configPath) && CheckSettingsPathAvailability(configPath, false);
|
|
// Check if the dirs are write-able
|
|
if (!hasPossibleNewLocation)
|
|
{
|
|
// None of the path above can be used as a dir for storing config.
|
|
// Even the last folder failed to pass the check.
|
|
LOG(MODULE_INIT, "FATAL")
|
|
LOG(MODULE_INIT, " ---> CANNOT find a proper place to store Qv2ray config files.")
|
|
QvMessageBoxWarn(nullptr, tr("Cannot Start Qv2ray"),
|
|
tr("Cannot find a place to store config files.") + NEWLINE + //
|
|
tr("Qv2ray has searched these paths below:") + NEWLINE + NEWLINE + //
|
|
configFilePaths.join(NEWLINE) + NEWLINE + //
|
|
tr("It usually means you don't have the write permission to all of those locations.") + NEWLINE + //
|
|
tr("Qv2ray will now exit.")); //
|
|
return false;
|
|
}
|
|
|
|
// Found a valid config dir, with write permission, but assume no config is located in it.
|
|
LOG(MODULE_INIT, "Set " + configPath + " as the config path.")
|
|
SetConfigDirPath(configPath);
|
|
|
|
if (QFile::exists(QV2RAY_CONFIG_FILE))
|
|
{
|
|
// As we already tried to load config from every possible dir.
|
|
//
|
|
// This condition branch (!hasExistingConfig check) holds the fact that current config dir,
|
|
// should NOT contain any valid file (at least in the same name)
|
|
//
|
|
// It usually means that QV2RAY_CONFIG_FILE here has a corrupted JSON format.
|
|
//
|
|
// Otherwise Qv2ray would have loaded this config already instead of notifying to create a new config in this folder.
|
|
//
|
|
LOG(MODULE_INIT, "This should not occur: Qv2ray config exists but failed to load.")
|
|
QvMessageBoxWarn(nullptr, tr("Failed to initialise Qv2ray"),
|
|
tr("Failed to determine the location of config file:") + NEWLINE + //
|
|
tr("Qv2ray has found a config file, but it failed to be loaded due to some errors.") + NEWLINE + //
|
|
tr("A workaround is to remove the this file and restart Qv2ray:") + NEWLINE + //
|
|
QV2RAY_CONFIG_FILE + NEWLINE + //
|
|
tr("Qv2ray will now exit.") + NEWLINE + //
|
|
tr("Please report if you think it's a bug.")); //
|
|
return false;
|
|
}
|
|
|
|
Qv2rayConfigObject conf;
|
|
conf.kernelConfig.KernelPath(QString(QV2RAY_DEFAULT_VCORE_PATH));
|
|
conf.kernelConfig.AssetsPath(QString(QV2RAY_DEFAULT_VASSETS_PATH));
|
|
conf.logLevel = 3;
|
|
conf.uiConfig.language = QLocale::system().name();
|
|
conf.defaultRouteConfig.dnsConfig.servers << QvConfig_DNS::DNSServerObject{ "1.1.1.1" } //
|
|
<< QvConfig_DNS::DNSServerObject{ "8.8.8.8" } //
|
|
<< QvConfig_DNS::DNSServerObject{ "8.8.4.4" };
|
|
|
|
// Save initial config.
|
|
SaveGlobalSettings(conf);
|
|
LOG(MODULE_INIT, "Created initial config file.")
|
|
}
|
|
|
|
if (!QDir(QV2RAY_GENERATED_DIR).exists())
|
|
{
|
|
// The dir used to generate final config file, for V2Ray interaction.
|
|
QDir().mkdir(QV2RAY_GENERATED_DIR);
|
|
LOG(MODULE_INIT, "Created config generation dir at: " + QV2RAY_GENERATED_DIR)
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Qv2rayApplication::LoadConfiguration()
|
|
{
|
|
// Load the config for upgrade, but do not parse it to the struct.
|
|
auto conf = JsonFromString(StringFromFile(QV2RAY_CONFIG_FILE));
|
|
const auto configVersion = conf["config_version"].toInt();
|
|
|
|
if (configVersion > QV2RAY_CONFIG_VERSION)
|
|
{
|
|
// Config version is larger than the current version...
|
|
// This is rare but it may happen....
|
|
QvMessageBoxWarn(nullptr, tr("Qv2ray Cannot Continue"), //
|
|
tr("You are running a lower version of Qv2ray compared to the current config file.") + NEWLINE + //
|
|
tr("Please check if there's an issue explaining about it.") + NEWLINE + //
|
|
tr("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE + //
|
|
tr("Qv2ray will now exit."));
|
|
return false;
|
|
}
|
|
else if (configVersion < QV2RAY_CONFIG_VERSION)
|
|
{
|
|
// That is the config file needs to be upgraded.
|
|
conf = Qv2ray::UpgradeSettingsVersion(configVersion, QV2RAY_CONFIG_VERSION, conf);
|
|
}
|
|
|
|
// Load config object from upgraded config QJsonObject
|
|
auto confObject = Qv2rayConfigObject::fromJson(conf);
|
|
|
|
const auto allTranslations = Qv2rayTranslator->GetAvailableLanguages();
|
|
const auto osLanguage = QLocale::system().name();
|
|
if (!allTranslations.contains(confObject.uiConfig.language) && allTranslations.contains(osLanguage))
|
|
{
|
|
// If configured language is not found. Set to system language.
|
|
LOG(MODULE_UI, "Fall back language setting to: " + osLanguage)
|
|
confObject.uiConfig.language = osLanguage;
|
|
}
|
|
else if (!allTranslations.isEmpty())
|
|
{
|
|
confObject.uiConfig.language = allTranslations.first();
|
|
}
|
|
|
|
if (!Qv2rayTranslator->InstallTranslation(confObject.uiConfig.language))
|
|
{
|
|
QvMessageBoxWarn(nullptr, "Translation Failed",
|
|
"Cannot load translation for " + confObject.uiConfig.language + NEWLINE + //
|
|
"English is now used." + NEWLINE + NEWLINE + //
|
|
"Please go to Preferences Window to change language or open an Issue");
|
|
confObject.uiConfig.language = "en_US";
|
|
}
|
|
|
|
// Let's save the config.
|
|
SaveGlobalSettings(confObject);
|
|
return true;
|
|
}
|
|
|
|
void Qv2rayApplication::InitializeGlobalVariables()
|
|
{
|
|
StyleManager = new QvStyleManager();
|
|
PluginHost = new QvPluginHost();
|
|
RouteManager = new RouteHandler();
|
|
ConnectionManager = new QvConfigHandler();
|
|
StyleManager->ApplyStyle(GlobalConfig.uiConfig.theme);
|
|
}
|
|
|
|
bool Qv2rayApplication::PreInitialize(int argc, char **argv)
|
|
{
|
|
QString errorMessage;
|
|
|
|
{
|
|
QCoreApplication coreApp(argc, argv);
|
|
const auto &args = coreApp.arguments();
|
|
Qv2rayProcessArgument.version = QV2RAY_VERSION_STRING;
|
|
Qv2rayProcessArgument.fullArgs = args;
|
|
switch (ParseCommandLine(&errorMessage, args))
|
|
{
|
|
case QV2RAY_QUIT: return false;
|
|
case QV2RAY_ERROR: LOG(MODULE_INIT, errorMessage) return false;
|
|
default: break;
|
|
}
|
|
#ifdef Q_OS_WIN
|
|
const auto appPath = QDir::toNativeSeparators(coreApp.applicationFilePath());
|
|
const auto regPath = "HKEY_CURRENT_USER\\Software\\Classes\\" + QV2RAY_URL_SCHEME;
|
|
|
|
QSettings reg(regPath, QSettings::NativeFormat);
|
|
|
|
reg.setValue("Default", "Qv2ray");
|
|
reg.setValue("URL Protocol", "");
|
|
|
|
reg.beginGroup("DefaultIcon");
|
|
reg.setValue("Default", QString("%1,1").arg(appPath));
|
|
reg.endGroup();
|
|
|
|
reg.beginGroup("shell");
|
|
reg.beginGroup("open");
|
|
reg.beginGroup("command");
|
|
reg.setValue("Default", appPath + " %1");
|
|
#endif
|
|
}
|
|
|
|
// noScaleFactors = disable HiDPI
|
|
if (StartupOption.noScaleFactor)
|
|
{
|
|
LOG(MODULE_INIT, "Force set QT_SCALE_FACTOR to 1.")
|
|
DEBUG(MODULE_UI, "Original QT_SCALE_FACTOR was: " + qEnvironmentVariable("QT_SCALE_FACTOR"))
|
|
qputenv("QT_SCALE_FACTOR", "1");
|
|
}
|
|
else
|
|
{
|
|
DEBUG(MODULE_INIT, "High DPI scaling is enabled.")
|
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
#endif
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Qv2rayApplication::commandline_status Qv2rayApplication::ParseCommandLine(QString *errorMessage, const QStringList &_argx_)
|
|
{
|
|
QStringList filteredArgs;
|
|
for (const auto &arg : _argx_)
|
|
{
|
|
#ifdef Q_OS_MACOS
|
|
if (arg.contains("-psn"))
|
|
continue;
|
|
#endif
|
|
filteredArgs << arg;
|
|
}
|
|
QCommandLineParser parser;
|
|
//
|
|
QCommandLineOption noAPIOption("noAPI", tr("Disable gRPC API subsystem"));
|
|
QCommandLineOption noPluginsOption("noPlugin", tr("Disable plugins feature"));
|
|
QCommandLineOption noScaleFactorOption("noScaleFactor", tr("Disable Qt UI scale factor"));
|
|
QCommandLineOption debugOption("debug", tr("Enable debug output"));
|
|
QCommandLineOption noAutoConnectionOption("noAutoConnection", tr("Do not automatically connect"));
|
|
QCommandLineOption disconnectOption("disconnect", tr("Stop current connection"));
|
|
QCommandLineOption reconnectOption("reconnect", tr("Reconnect last connection"));
|
|
QCommandLineOption exitOption("exit", tr("Exit Qv2ray"));
|
|
//
|
|
parser.setApplicationDescription(tr("Qv2ray - A cross-platform Qt frontend for V2Ray."));
|
|
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
|
//
|
|
parser.addOption(noAPIOption);
|
|
parser.addOption(noPluginsOption);
|
|
parser.addOption(noScaleFactorOption);
|
|
parser.addOption(debugOption);
|
|
parser.addOption(noAutoConnectionOption);
|
|
parser.addOption(disconnectOption);
|
|
parser.addOption(reconnectOption);
|
|
parser.addOption(exitOption);
|
|
//
|
|
auto helpOption = parser.addHelpOption();
|
|
auto versionOption = parser.addVersionOption();
|
|
|
|
if (!parser.parse(filteredArgs))
|
|
{
|
|
*errorMessage = parser.errorText();
|
|
return QV2RAY_ERROR;
|
|
}
|
|
|
|
if (parser.isSet(versionOption))
|
|
{
|
|
parser.showVersion();
|
|
return QV2RAY_QUIT;
|
|
}
|
|
|
|
if (parser.isSet(helpOption))
|
|
{
|
|
parser.showHelp();
|
|
return QV2RAY_QUIT;
|
|
}
|
|
|
|
for (const auto &arg : parser.positionalArguments())
|
|
{
|
|
if (arg.startsWith(QV2RAY_URL_SCHEME + "://"))
|
|
{
|
|
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::QV2RAY_LINK;
|
|
Qv2rayProcessArgument.links << arg;
|
|
}
|
|
}
|
|
|
|
if (parser.isSet(exitOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "disconnectOption is set.")
|
|
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::EXIT;
|
|
}
|
|
|
|
if (parser.isSet(disconnectOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "disconnectOption is set.")
|
|
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::DISCONNECT;
|
|
}
|
|
|
|
if (parser.isSet(reconnectOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "reconnectOption is set.")
|
|
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::RECONNECT;
|
|
}
|
|
|
|
if (parser.isSet(noAPIOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "noAPIOption is set.")
|
|
StartupOption.noAPI = true;
|
|
}
|
|
|
|
if (parser.isSet(debugOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "debugOption is set.")
|
|
StartupOption.debugLog = true;
|
|
}
|
|
|
|
if (parser.isSet(noScaleFactorOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "noScaleFactorOption is set.")
|
|
StartupOption.noScaleFactor = true;
|
|
}
|
|
|
|
if (parser.isSet(noAutoConnectionOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "noAutoConnectOption is set.")
|
|
StartupOption.noAutoConnection = true;
|
|
}
|
|
|
|
if (parser.isSet(noPluginsOption))
|
|
{
|
|
DEBUG(MODULE_INIT, "noPluginOption is set.")
|
|
StartupOption.noPlugins = true;
|
|
}
|
|
|
|
return QV2RAY_CONTINUE;
|
|
}
|
|
|
|
} // namespace Qv2ray
|