mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 10:50:23 +08:00
255 lines
8.5 KiB
C++
255 lines
8.5 KiB
C++
#include "Qv2rayPlatformApplication.hpp"
|
|
|
|
#include "core/settings/SettingsBackend.hpp"
|
|
|
|
#include <QSslSocket>
|
|
#define QV_MODULE_NAME "PlatformApplication"
|
|
|
|
#ifdef QT_DEBUG
|
|
const static inline QString QV2RAY_URL_SCHEME = "qv2ray-debug";
|
|
#else
|
|
const static inline QString QV2RAY_URL_SCHEME = "qv2ray";
|
|
#endif
|
|
|
|
QStringList Qv2rayPlatformApplication::CheckPrerequisites()
|
|
{
|
|
QStringList errors;
|
|
if (!QSslSocket::supportsSsl())
|
|
{
|
|
// Check OpenSSL version for auto-update and subscriptions
|
|
const auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString();
|
|
const auto osslCurVersion = QSslSocket::sslLibraryVersionString();
|
|
LOG("Current OpenSSL version: " + osslCurVersion);
|
|
LOG("Required OpenSSL version: " + osslReqVersion);
|
|
errors << "Qv2ray cannot run without OpenSSL.";
|
|
errors << "This is usually caused by using the wrong version of OpenSSL";
|
|
errors << "Required=" + osslReqVersion + "Current=" + osslCurVersion;
|
|
}
|
|
return errors + checkPrerequisitesInternal();
|
|
}
|
|
|
|
bool Qv2rayPlatformApplication::Initialize()
|
|
{
|
|
QString errorMessage;
|
|
bool canContinue;
|
|
const auto hasError = parseCommandLine(&errorMessage, &canContinue);
|
|
if (hasError)
|
|
{
|
|
LOG("Command line:" A(errorMessage));
|
|
if (!canContinue)
|
|
{
|
|
LOG("Fatal, Qv2ray cannot continue.");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
LOG("Non-fatal error, continue starting up.");
|
|
}
|
|
}
|
|
|
|
#ifdef Q_OS_WIN
|
|
const auto appPath = QDir::toNativeSeparators(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
|
|
|
|
connect(this, &Qv2rayPlatformApplication::aboutToQuit, this, &Qv2rayPlatformApplication::quitInternal);
|
|
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
|
connect(this, &SingleApplication::receivedMessage, this, &Qv2rayPlatformApplication::onMessageReceived, Qt::QueuedConnection);
|
|
if (isSecondary())
|
|
{
|
|
StartupArguments.version = QV2RAY_VERSION_STRING;
|
|
StartupArguments.buildVersion = QV2RAY_VERSION_BUILD;
|
|
StartupArguments.fullArgs = arguments();
|
|
if (StartupArguments.arguments.isEmpty())
|
|
StartupArguments.arguments << Qv2rayStartupArguments::NORMAL;
|
|
bool status = sendMessage(JsonToString(StartupArguments.toJson(), QJsonDocument::Compact).toUtf8());
|
|
if (!status)
|
|
LOG("Cannot send message.");
|
|
SetExitReason(EXIT_SECONDARY_INSTANCE);
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
#ifdef QV2RAY_GUI
|
|
#ifdef Q_OS_LINUX
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
setFallbackSessionManagementEnabled(false);
|
|
#endif
|
|
connect(this, &QGuiApplication::commitDataRequest, [] {
|
|
RouteManager->SaveRoutes();
|
|
ConnectionManager->SaveConnectionConfig();
|
|
PluginHost->SavePluginSettings();
|
|
SaveGlobalSettings();
|
|
});
|
|
#endif
|
|
|
|
#ifdef Q_OS_WIN
|
|
SetCurrentDirectory(applicationDirPath().toStdWString().c_str());
|
|
// Set special font in Windows
|
|
QFont font;
|
|
font.setPointSize(9);
|
|
font.setFamily("Microsoft YaHei");
|
|
setFont(font);
|
|
#endif
|
|
#endif
|
|
|
|
// Install a default translater. From the OS/DE
|
|
Qv2rayTranslator = std::make_unique<QvTranslator>();
|
|
Qv2rayTranslator->InstallTranslation(QLocale::system().name());
|
|
const auto allTranslations = Qv2rayTranslator->GetAvailableLanguages();
|
|
const auto osLanguage = QLocale::system().name();
|
|
//
|
|
LocateConfiguration();
|
|
if (!allTranslations.contains(GlobalConfig.uiConfig.language))
|
|
{
|
|
// If we need to reset the language.
|
|
if (allTranslations.contains(osLanguage))
|
|
{
|
|
GlobalConfig.uiConfig.language = osLanguage;
|
|
}
|
|
else if (!allTranslations.isEmpty())
|
|
{
|
|
GlobalConfig.uiConfig.language = allTranslations.first();
|
|
}
|
|
}
|
|
|
|
if (!Qv2rayTranslator->InstallTranslation(GlobalConfig.uiConfig.language))
|
|
{
|
|
QvMessageBoxWarn(nullptr, "Translation Failed",
|
|
"Cannot load translation for " + GlobalConfig.uiConfig.language + NEWLINE + //
|
|
"English is now used." + NEWLINE + NEWLINE + //
|
|
"Please go to Preferences Window to change language or open an Issue");
|
|
GlobalConfig.uiConfig.language = "en_US";
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Qv2rayExitReason Qv2rayPlatformApplication::RunQv2ray()
|
|
{
|
|
PluginHost = new QvPluginHost();
|
|
RouteManager = new RouteHandler();
|
|
ConnectionManager = new QvConfigHandler();
|
|
return runQv2rayInternal();
|
|
}
|
|
|
|
void Qv2rayPlatformApplication::quitInternal()
|
|
{
|
|
// Do not change the order.
|
|
ConnectionManager->StopConnection();
|
|
RouteManager->SaveRoutes();
|
|
ConnectionManager->SaveConnectionConfig();
|
|
PluginHost->SavePluginSettings();
|
|
SaveGlobalSettings();
|
|
terminateUIInternal();
|
|
delete ConnectionManager;
|
|
delete RouteManager;
|
|
delete PluginHost;
|
|
ConnectionManager = nullptr;
|
|
RouteManager = nullptr;
|
|
PluginHost = nullptr;
|
|
}
|
|
|
|
bool Qv2rayPlatformApplication::parseCommandLine(QString *errorMessage, bool *canContinue)
|
|
{
|
|
*canContinue = true;
|
|
QStringList filteredArgs;
|
|
for (const auto &arg : arguments())
|
|
{
|
|
#ifdef Q_OS_MACOS
|
|
if (arg.contains("-psn"))
|
|
continue;
|
|
#endif
|
|
filteredArgs << arg;
|
|
}
|
|
QCommandLineParser parser;
|
|
//
|
|
QCommandLineOption noAPIOption("noAPI", QObject::tr("Disable gRPC API subsystem"));
|
|
QCommandLineOption noPluginsOption("noPlugin", QObject::tr("Disable plugins feature"));
|
|
QCommandLineOption debugLogOption("debug", QObject::tr("Enable debug output"));
|
|
QCommandLineOption noAutoConnectionOption("noAutoConnection", QObject::tr("Do not automatically connect"));
|
|
QCommandLineOption disconnectOption("disconnect", QObject::tr("Stop current connection"));
|
|
QCommandLineOption reconnectOption("reconnect", QObject::tr("Reconnect last connection"));
|
|
QCommandLineOption exitOption("exit", QObject::tr("Exit Qv2ray"));
|
|
//
|
|
parser.setApplicationDescription(QObject::tr("Qv2ray - A cross-platform Qt frontend for V2Ray."));
|
|
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
|
//
|
|
parser.addOption(noAPIOption);
|
|
parser.addOption(noPluginsOption);
|
|
parser.addOption(debugLogOption);
|
|
parser.addOption(noAutoConnectionOption);
|
|
parser.addOption(disconnectOption);
|
|
parser.addOption(reconnectOption);
|
|
parser.addOption(exitOption);
|
|
//
|
|
const auto helpOption = parser.addHelpOption();
|
|
const auto versionOption = parser.addVersionOption();
|
|
|
|
if (!parser.parse(filteredArgs))
|
|
{
|
|
*canContinue = true;
|
|
*errorMessage = parser.errorText();
|
|
return false;
|
|
}
|
|
|
|
if (parser.isSet(versionOption))
|
|
{
|
|
parser.showVersion();
|
|
return true;
|
|
}
|
|
|
|
if (parser.isSet(helpOption))
|
|
{
|
|
parser.showHelp();
|
|
return true;
|
|
}
|
|
|
|
for (const auto &arg : parser.positionalArguments())
|
|
{
|
|
if (arg.startsWith(QV2RAY_URL_SCHEME + "://"))
|
|
{
|
|
StartupArguments.arguments << Qv2rayStartupArguments::QV2RAY_LINK;
|
|
StartupArguments.links << arg;
|
|
}
|
|
}
|
|
|
|
if (parser.isSet(exitOption))
|
|
{
|
|
DEBUG("disconnectOption is set.");
|
|
StartupArguments.arguments << Qv2rayStartupArguments::EXIT;
|
|
}
|
|
|
|
if (parser.isSet(disconnectOption))
|
|
{
|
|
DEBUG("disconnectOption is set.");
|
|
StartupArguments.arguments << Qv2rayStartupArguments::DISCONNECT;
|
|
}
|
|
|
|
if (parser.isSet(reconnectOption))
|
|
{
|
|
DEBUG("reconnectOption is set.");
|
|
StartupArguments.arguments << Qv2rayStartupArguments::RECONNECT;
|
|
}
|
|
|
|
#define ProcessExtraStartupOptions(option) \
|
|
DEBUG("Startup Options:" A(parser.isSet(option##Option))); \
|
|
StartupArguments.option = parser.isSet(option##Option);
|
|
|
|
ProcessExtraStartupOptions(noAPI);
|
|
ProcessExtraStartupOptions(debugLog);
|
|
ProcessExtraStartupOptions(noAutoConnection);
|
|
ProcessExtraStartupOptions(noPlugins);
|
|
return true;
|
|
}
|