mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 10:50:23 +08:00
refactor: fixed SingleApplication crash, refactored
This commit is contained in:
parent
94d701ce91
commit
4cd00df503
2
3rdparty/SingleApplication
vendored
2
3rdparty/SingleApplication
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 9a408690ceb260a220d50f5070af9bcda58cacc2
|
Subproject commit 0e42d86cecf008e850bc1f7540196de1f6bf182d
|
@ -6,6 +6,7 @@ set(QV2RAY_BASE_SOURCES
|
|||||||
${QV2RAY_BASEDIR_BASE}/Qv2rayBaseApplication.cpp
|
${QV2RAY_BASEDIR_BASE}/Qv2rayBaseApplication.cpp
|
||||||
${QV2RAY_BASEDIR_BASE}/Qv2rayBaseApplication.hpp
|
${QV2RAY_BASEDIR_BASE}/Qv2rayBaseApplication.hpp
|
||||||
# Platform Dependent UI
|
# Platform Dependent UI
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ui/Qv2rayPlatformApplication.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/Qv2rayPlatformApplication.hpp
|
${CMAKE_SOURCE_DIR}/src/ui/Qv2rayPlatformApplication.hpp
|
||||||
#
|
#
|
||||||
${QV2RAY_BASEDIR_BASE}/JsonHelpers.hpp
|
${QV2RAY_BASEDIR_BASE}/JsonHelpers.hpp
|
||||||
|
@ -1 +1 @@
|
|||||||
6000
|
6001
|
||||||
|
@ -47,7 +47,7 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get Configured Config Dir Path
|
// Get Configured Config Dir Path
|
||||||
#define QV2RAY_CONFIG_DIR (qvApplicationInstance->ConfigPath)
|
#define QV2RAY_CONFIG_DIR (QvCoreApplication->ConfigPath)
|
||||||
#define QV2RAY_CONFIG_FILE (QV2RAY_CONFIG_DIR + "Qv2ray.conf")
|
#define QV2RAY_CONFIG_FILE (QV2RAY_CONFIG_DIR + "Qv2ray.conf")
|
||||||
//
|
//
|
||||||
#define QV2RAY_CONNECTIONS_DIR (QV2RAY_CONFIG_DIR + "connections/")
|
#define QV2RAY_CONNECTIONS_DIR (QV2RAY_CONFIG_DIR + "connections/")
|
||||||
@ -67,13 +67,6 @@ using namespace Qv2ray::base::objects::transfer;
|
|||||||
#error Both QV2RAY_DEFAULT_VCORE_PATH and QV2RAY_DEFAULT_VASSETS_PATH need to be presented when using manually specify the paths.
|
#error Both QV2RAY_DEFAULT_VCORE_PATH and QV2RAY_DEFAULT_VASSETS_PATH need to be presented when using manually specify the paths.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QV2RAY_TPROXY_VCORE_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ray" QV2RAY_EXECUTABLE_SUFFIX)
|
|
||||||
#define QV2RAY_TPROXY_VCTL_PATH (QV2RAY_CONFIG_DIR + "vcore/v2ctl" QV2RAY_EXECUTABLE_SUFFIX)
|
|
||||||
|
|
||||||
constexpr auto QV2RAY_VCORE_LOG_DIRNAME = "logs/";
|
|
||||||
constexpr auto QV2RAY_VCORE_ACCESS_LOG_FILENAME = "access.log";
|
|
||||||
constexpr auto QV2RAY_VCORE_ERROR_LOG_FILENAME = "error.log";
|
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
#define ACCESS_OPTIONAL_VALUE(obj) (*obj)
|
#define ACCESS_OPTIONAL_VALUE(obj) (*obj)
|
||||||
#else
|
#else
|
||||||
@ -85,49 +78,14 @@ constexpr auto QV2RAY_VCORE_ERROR_LOG_FILENAME = "error.log";
|
|||||||
#define OUTBOUND_TAG_BLACKHOLE "BLACKHOLE"
|
#define OUTBOUND_TAG_BLACKHOLE "BLACKHOLE"
|
||||||
#define OUTBOUND_TAG_DIRECT "DIRECT"
|
#define OUTBOUND_TAG_DIRECT "DIRECT"
|
||||||
#define OUTBOUND_TAG_PROXY "PROXY"
|
#define OUTBOUND_TAG_PROXY "PROXY"
|
||||||
#define OUTBOUND_TAG_FORWARD_PROXY "_QV2RAY_FORWARD_PROXY_"
|
#define OUTBOUND_TAG_FORWARD_PROXY "QV2RAY_FORWARD_PROXY"
|
||||||
|
|
||||||
#define API_TAG_DEFAULT "_QV2RAY_API_"
|
#define API_TAG_DEFAULT "QV2RAY_API"
|
||||||
#define API_TAG_INBOUND "_QV2RAY_API_INBOUND_"
|
#define API_TAG_INBOUND "QV2RAY_API_INBOUND"
|
||||||
|
|
||||||
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
|
#define QV2RAY_USE_FPROXY_KEY "_QV2RAY_USE_GLOBAL_FORWARD_PROXY_"
|
||||||
|
|
||||||
namespace Qv2ray
|
namespace Qv2ray
|
||||||
{
|
{
|
||||||
inline QStringList Qv2rayAssetsPaths(const QString &dirName)
|
|
||||||
{
|
|
||||||
#define makeAbs(p) QDir(p).absolutePath()
|
|
||||||
// Configuration Path
|
|
||||||
QStringList list;
|
|
||||||
// This is the default behavior on Windows
|
|
||||||
list << makeAbs(QCoreApplication::applicationDirPath() + "/" + dirName);
|
|
||||||
list << makeAbs(QV2RAY_CONFIG_DIR + dirName);
|
|
||||||
list << ":/" + dirName;
|
|
||||||
//
|
|
||||||
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, QStandardPaths::LocateDirectory);
|
|
||||||
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, QStandardPaths::LocateDirectory);
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
// For AppImage?
|
|
||||||
if (qEnvironmentVariableIsSet("APPIMAGE"))
|
|
||||||
list << makeAbs(QCoreApplication::applicationDirPath() + "/../share/qv2ray/" + dirName);
|
|
||||||
// For Snap
|
|
||||||
if (qEnvironmentVariableIsSet("SNAP"))
|
|
||||||
list << makeAbs(qEnvironmentVariable("SNAP") + "/usr/share/qv2ray/" + dirName);
|
|
||||||
// Linux platform directories.
|
|
||||||
list << makeAbs("/usr/local/lib/qv2ray/" + dirName);
|
|
||||||
list << makeAbs("/usr/lib/qv2ray/" + dirName);
|
|
||||||
list << makeAbs("/lib/qv2ray/" + dirName);
|
|
||||||
//
|
|
||||||
list << makeAbs("/usr/local/share/qv2ray/" + dirName);
|
|
||||||
list << makeAbs("/usr/share/qv2ray/" + dirName);
|
|
||||||
#elif defined(Q_OS_MAC)
|
|
||||||
// macOS platform directories.
|
|
||||||
list << QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath();
|
|
||||||
#endif
|
|
||||||
list.removeDuplicates();
|
|
||||||
return list;
|
|
||||||
#undef makeAbs
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Qv2ray
|
} // namespace Qv2ray
|
||||||
|
@ -4,349 +4,68 @@
|
|||||||
#include "core/settings/SettingsBackend.hpp"
|
#include "core/settings/SettingsBackend.hpp"
|
||||||
#include "utils/QvHelpers.hpp"
|
#include "utils/QvHelpers.hpp"
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
|
||||||
const static inline QString QV2RAY_URL_SCHEME = "qv2ray-debug";
|
|
||||||
#else
|
|
||||||
const static inline QString QV2RAY_URL_SCHEME = "qv2ray";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define QV_MODULE_NAME "BaseApplication"
|
#define QV_MODULE_NAME "BaseApplication"
|
||||||
constexpr auto QV2RAY_CONFIG_PATH_ENV_NAME = "QV2RAY_CONFIG_PATH";
|
inline QString makeAbs(const QString &p)
|
||||||
|
{
|
||||||
|
return QDir(p).absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
Qv2rayApplicationManager::Qv2rayApplicationManager()
|
Qv2rayApplicationInterface::Qv2rayApplicationInterface()
|
||||||
{
|
{
|
||||||
ConfigObject = new Qv2rayConfigObject;
|
ConfigObject = new Qv2rayConfigObject;
|
||||||
qvApplicationInstance = this;
|
QvCoreApplication = this;
|
||||||
LOG("Qv2ray " QV2RAY_VERSION_STRING " on " + QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture());
|
LOG("Qv2ray", QV2RAY_VERSION_STRING, "on", QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||||
DEBUG("Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay()));
|
DEBUG("Qv2ray Start Time: ", QTime::currentTime().msecsSinceStartOfDay());
|
||||||
DEBUG(std::string{ "QV2RAY_BUILD_INFO" }, QV2RAY_BUILD_INFO);
|
DEBUG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO);
|
||||||
DEBUG(std::string{ "QV2RAY_BUILD_EXTRA_INFO" }, QV2RAY_BUILD_EXTRA_INFO);
|
DEBUG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO);
|
||||||
DEBUG(std::string{ "QV2RAY_BUILD_NUMBER" }, QSTRN(QV2RAY_VERSION_BUILD));
|
DEBUG("QV2RAY_BUILD_NUMBER", QSTRN(QV2RAY_VERSION_BUILD));
|
||||||
|
QStringList licenseList;
|
||||||
|
licenseList << "This program comes with ABSOLUTELY NO WARRANTY.";
|
||||||
|
licenseList << "This is free software, and you are welcome to redistribute it";
|
||||||
|
licenseList << "under certain conditions.";
|
||||||
|
licenseList << "Copyright (c) 2019-2020 Qv2ray Development Group.";
|
||||||
|
licenseList << "Third-party libraries that have been used in this program can be found in the About page.";
|
||||||
|
LOG(licenseList.join(NEWLINE));
|
||||||
}
|
}
|
||||||
|
|
||||||
Qv2rayApplicationManager::~Qv2rayApplicationManager()
|
Qv2rayApplicationInterface::~Qv2rayApplicationInterface()
|
||||||
{
|
{
|
||||||
delete ConfigObject;
|
delete ConfigObject;
|
||||||
qvApplicationInstance = nullptr;
|
QvCoreApplication = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Qv2rayApplicationManager::LocateConfiguration()
|
QStringList Qv2rayApplicationInterface::GetAssetsPaths(const QString &dirName) const
|
||||||
{
|
{
|
||||||
LOG("Application exec path: " + qApp->applicationDirPath());
|
// Configuration Path
|
||||||
// Non-standard paths needs special handing for "_debug"
|
QStringList list;
|
||||||
const auto currentPathConfig = qApp->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).
|
|
||||||
const auto useManualConfigPath = qEnvironmentVariableIsSet(QV2RAY_CONFIG_PATH_ENV_NAME);
|
|
||||||
const auto manualConfigPath = qEnvironmentVariable(QV2RAY_CONFIG_PATH_ENV_NAME);
|
|
||||||
//
|
|
||||||
QStringList configFilePaths;
|
|
||||||
if (useManualConfigPath)
|
|
||||||
{
|
|
||||||
LOG("Using config path from env: " + manualConfigPath);
|
|
||||||
configFilePaths << manualConfigPath;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
configFilePaths << currentPathConfig;
|
|
||||||
configFilePaths << configQv2ray;
|
|
||||||
configFilePaths << homeQv2ray;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString configPath = "";
|
// Default behavior on Windows
|
||||||
bool hasExistingConfig = false;
|
list << makeAbs(QCoreApplication::applicationDirPath() + "/" + dirName);
|
||||||
for (const auto &path : configFilePaths)
|
list << makeAbs(QV2RAY_CONFIG_DIR + dirName);
|
||||||
{
|
list << ":/" + dirName;
|
||||||
// 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...
|
list << QStandardPaths::locateAll(QStandardPaths::AppDataLocation, dirName, QStandardPaths::LocateDirectory);
|
||||||
if (hasExistingConfig)
|
list << QStandardPaths::locateAll(QStandardPaths::AppConfigLocation, dirName, QStandardPaths::LocateDirectory);
|
||||||
break;
|
|
||||||
|
|
||||||
if (isValidConfigPath)
|
#ifdef Q_OS_UNIX
|
||||||
{
|
if (qEnvironmentVariableIsSet("APPIMAGE"))
|
||||||
DEBUG("Path:", path, " is valid.");
|
list << makeAbs(QCoreApplication::applicationDirPath() + "/../share/qv2ray/" + dirName);
|
||||||
configPath = path;
|
|
||||||
hasExistingConfig = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG("Path:", path, "does not contain a valid config file.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasExistingConfig)
|
if (qEnvironmentVariableIsSet("SNAP"))
|
||||||
{
|
list << makeAbs(qEnvironmentVariable("SNAP") + "/usr/share/qv2ray/" + dirName);
|
||||||
// Use the config path found by the checks above
|
|
||||||
SetConfigDirPath(configPath);
|
list << makeAbs("/usr/local/share/qv2ray/" + dirName);
|
||||||
LOG("Using ", QV2RAY_CONFIG_DIR, " as the config path.");
|
list << makeAbs("/usr/local/lib/qv2ray/" + dirName);
|
||||||
}
|
list << makeAbs("/usr/share/qv2ray/" + dirName);
|
||||||
else
|
list << makeAbs("/usr/lib/qv2ray/" + dirName);
|
||||||
{
|
list << makeAbs("/lib/qv2ray/" + dirName);
|
||||||
// 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
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
bool hasPossibleNewLocation = QDir().mkpath(configPath) && CheckSettingsPathAvailability(configPath, false);
|
#ifdef Q_OS_MAC
|
||||||
// Check if the dirs are write-able
|
// macOS platform directories.
|
||||||
if (!hasPossibleNewLocation)
|
list << QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + dirName).absolutePath();
|
||||||
{
|
|
||||||
// None of the path above can be used as a dir for storing config.
|
|
||||||
// Even the last folder failed to pass the check.
|
|
||||||
LOG("FATAL");
|
|
||||||
LOG(" ---> CANNOT find a proper place to store Qv2ray config files.");
|
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Cannot Start Qv2ray"),
|
|
||||||
QObject::tr("Cannot find a place to store config files.") + NEWLINE + //
|
|
||||||
QObject::tr("Qv2ray has searched these paths below:") + NEWLINE + NEWLINE + //
|
|
||||||
configFilePaths.join(NEWLINE) + NEWLINE + //
|
|
||||||
QObject::tr("It usually means you don't have the write permission to all of those locations.") + NEWLINE + //
|
|
||||||
QObject::tr("Qv2ray will now exit.")); //
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found a valid config dir, with write permission, but assume no config is located in it.
|
|
||||||
LOG("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("This should not occur: Qv2ray config exists but failed to load.");
|
|
||||||
QvMessageBoxWarn(nullptr, QObject::tr("Failed to initialise Qv2ray"),
|
|
||||||
QObject::tr("Failed to determine the location of config file:") + NEWLINE + //
|
|
||||||
QObject::tr("Qv2ray has found a config file, but it failed to be loaded due to some errors.") + NEWLINE + //
|
|
||||||
QObject::tr("A workaround is to remove the this file and restart Qv2ray:") + NEWLINE + //
|
|
||||||
QV2RAY_CONFIG_FILE + NEWLINE + //
|
|
||||||
QObject::tr("Qv2ray will now exit.") + NEWLINE + //
|
|
||||||
QObject::tr("Please report if you think it's a bug.")); //
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalConfig.kernelConfig.KernelPath(QString(QV2RAY_DEFAULT_VCORE_PATH));
|
|
||||||
GlobalConfig.kernelConfig.AssetsPath(QString(QV2RAY_DEFAULT_VASSETS_PATH));
|
|
||||||
GlobalConfig.logLevel = 3;
|
|
||||||
GlobalConfig.uiConfig.language = QLocale::system().name();
|
|
||||||
GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "1.1.1.1" });
|
|
||||||
GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "8.8.8.8" });
|
|
||||||
GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "8.8.4.4" });
|
|
||||||
|
|
||||||
// Save initial config.
|
|
||||||
SaveGlobalSettings();
|
|
||||||
LOG("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("Created config generation dir at: " + QV2RAY_GENERATED_DIR);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// BEGIN LOAD CONFIGURATIONS
|
|
||||||
//
|
|
||||||
{
|
|
||||||
// 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, QObject::tr("Qv2ray Cannot Continue"), //
|
|
||||||
QObject::tr("You are running a lower version of Qv2ray compared to the current config file.") + NEWLINE + //
|
|
||||||
QObject::tr("Please check if there's an issue explaining about it.") + NEWLINE + //
|
|
||||||
QObject::tr("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE + //
|
|
||||||
QObject::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's save the config.
|
|
||||||
GlobalConfig.loadJson(conf);
|
|
||||||
const auto allTranslations = Qv2rayTranslator->GetAvailableLanguages();
|
|
||||||
const auto osLanguage = QLocale::system().name();
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
SaveGlobalSettings();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Qv2rayPreInitResult Qv2rayApplicationManager::StaticPreInitialize(int argc, char **argv)
|
|
||||||
{
|
|
||||||
QString errorMessage;
|
|
||||||
QCoreApplication coreApp(argc, argv);
|
|
||||||
const auto &args = coreApp.arguments();
|
|
||||||
Qv2rayProcessArgument.version = QV2RAY_VERSION_STRING;
|
|
||||||
Qv2rayProcessArgument.fullArgs = args;
|
|
||||||
auto result = ParseCommandLine(&errorMessage, args);
|
|
||||||
LOG("Qv2ray PreInitialization: " + errorMessage);
|
|
||||||
if (result != PRE_INIT_RESULT_CONTINUE)
|
|
||||||
return result;
|
|
||||||
#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
|
#endif
|
||||||
return result;
|
|
||||||
}
|
list.removeDuplicates();
|
||||||
Qv2rayPreInitResult Qv2rayApplicationManager::ParseCommandLine(QString *errorMessage, const QStringList &_argx_)
|
return list;
|
||||||
{
|
|
||||||
QStringList filteredArgs;
|
|
||||||
for (const auto &arg : _argx_)
|
|
||||||
{
|
|
||||||
#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 noScaleFactorOption("noScaleFactor", QObject::tr("Disable Qt UI scale factor"));
|
|
||||||
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(noScaleFactorOption);
|
|
||||||
parser.addOption(debugLogOption);
|
|
||||||
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 PRE_INIT_RESULT_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser.isSet(versionOption))
|
|
||||||
{
|
|
||||||
parser.showVersion();
|
|
||||||
return PRE_INIT_RESULT_QUIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser.isSet(helpOption))
|
|
||||||
{
|
|
||||||
parser.showHelp();
|
|
||||||
return PRE_INIT_RESULT_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("disconnectOption is set.");
|
|
||||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser.isSet(disconnectOption))
|
|
||||||
{
|
|
||||||
DEBUG("disconnectOption is set.");
|
|
||||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::DISCONNECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser.isSet(reconnectOption))
|
|
||||||
{
|
|
||||||
DEBUG("reconnectOption is set.");
|
|
||||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::RECONNECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ProcessExtraStartupOptions(option) \
|
|
||||||
DEBUG("Startup Options:" A(parser.isSet(option##Option))); \
|
|
||||||
StartupOption.option = parser.isSet(option##Option);
|
|
||||||
|
|
||||||
ProcessExtraStartupOptions(noAPI);
|
|
||||||
ProcessExtraStartupOptions(debugLog);
|
|
||||||
ProcessExtraStartupOptions(noScaleFactor);
|
|
||||||
ProcessExtraStartupOptions(noAutoConnection);
|
|
||||||
ProcessExtraStartupOptions(noPlugins);
|
|
||||||
|
|
||||||
*errorMessage = "OK";
|
|
||||||
return PRE_INIT_RESULT_CONTINUE;
|
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,6 @@
|
|||||||
|
|
||||||
namespace Qv2ray
|
namespace Qv2ray
|
||||||
{
|
{
|
||||||
enum Qv2rayExitCode
|
|
||||||
{
|
|
||||||
QVEXIT_NORMAL = 0,
|
|
||||||
QVEXIT_SECONDARY_INSTANCE = 0,
|
|
||||||
QVEXIT_PRE_INITIALIZE_FAIL = -1,
|
|
||||||
QVEXIT_EARLY_SETUP_FAIL = -2,
|
|
||||||
QVEXIT_CONFIG_FILE_FAIL = -3,
|
|
||||||
QVEXIT_SSL_FAIL = -4,
|
|
||||||
QVEXIT_NEW_VERSION = -5
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MessageOpt
|
enum MessageOpt
|
||||||
{
|
{
|
||||||
OK,
|
OK,
|
||||||
@ -27,21 +16,17 @@ namespace Qv2ray
|
|||||||
Ignore
|
Ignore
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Qv2rayPreInitResult
|
enum Qv2rayExitReason
|
||||||
{
|
{
|
||||||
PRE_INIT_RESULT_ERROR,
|
EXIT_NORMAL = 0,
|
||||||
PRE_INIT_RESULT_QUIT,
|
EXIT_NEW_VERSION_TRIGGER = EXIT_NORMAL,
|
||||||
PRE_INIT_RESULT_CONTINUE
|
EXIT_SECONDARY_INSTANCE = EXIT_NORMAL,
|
||||||
|
EXIT_PREINITIALIZATION_FAILED = -1,
|
||||||
|
EXIT_PRECONDITION_FAILED = -2,
|
||||||
|
EXIT_CRASHED = -9,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Qv2raySetupStatus
|
struct Qv2rayStartupArguments
|
||||||
{
|
|
||||||
NORMAL,
|
|
||||||
SINGLE_APPLICATION,
|
|
||||||
FAILED
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Qv2rayProcessArguments
|
|
||||||
{
|
{
|
||||||
enum Argument
|
enum Argument
|
||||||
{
|
{
|
||||||
@ -53,40 +38,45 @@ namespace Qv2ray
|
|||||||
};
|
};
|
||||||
QList<Argument> arguments;
|
QList<Argument> arguments;
|
||||||
QString version;
|
QString version;
|
||||||
|
int buildVersion;
|
||||||
QString data;
|
QString data;
|
||||||
QList<QString> links;
|
QList<QString> links;
|
||||||
QList<QString> fullArgs;
|
QList<QString> fullArgs;
|
||||||
//
|
//
|
||||||
|
bool noAPI;
|
||||||
|
bool noAutoConnection;
|
||||||
|
bool debugLog;
|
||||||
|
bool noPlugins;
|
||||||
|
bool exitQv2ray;
|
||||||
|
//
|
||||||
QString _qvNewVersionPath;
|
QString _qvNewVersionPath;
|
||||||
JSONSTRUCT_REGISTER(Qv2rayProcessArguments, F(arguments, version, data, links, fullArgs))
|
JSONSTRUCT_REGISTER(Qv2rayStartupArguments, F(arguments, data, version, links, fullArgs, buildVersion))
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Qv2rayProcessArguments Qv2rayProcessArgument;
|
class Qv2rayApplicationInterface
|
||||||
class Qv2rayApplicationManager
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Qv2ray::base::config::Qv2rayConfigObject *ConfigObject;
|
Qv2ray::base::config::Qv2rayConfigObject *ConfigObject;
|
||||||
QString ConfigPath;
|
QString ConfigPath;
|
||||||
|
Qv2rayExitReason ExitReason;
|
||||||
|
Qv2rayStartupArguments StartupArguments;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Qv2rayPreInitResult StaticPreInitialize(int argc, char **argv);
|
explicit Qv2rayApplicationInterface();
|
||||||
explicit Qv2rayApplicationManager();
|
~Qv2rayApplicationInterface();
|
||||||
~Qv2rayApplicationManager();
|
|
||||||
virtual bool LocateConfiguration() final;
|
public:
|
||||||
|
virtual QStringList GetAssetsPaths(const QString &dirName) const final;
|
||||||
//
|
//
|
||||||
virtual Qv2raySetupStatus Initialize() = 0;
|
virtual bool Initialize() = 0;
|
||||||
virtual Qv2rayExitCode RunQv2ray() = 0;
|
virtual Qv2rayExitReason RunQv2ray() = 0;
|
||||||
//
|
//
|
||||||
virtual void MessageBoxWarn(QWidget *parent, const QString &title, const QString &text, MessageOpt button) = 0;
|
virtual void MessageBoxWarn(QWidget *parent, const QString &title, const QString &text, MessageOpt button) = 0;
|
||||||
virtual void MessageBoxInfo(QWidget *parent, const QString &title, const QString &text, MessageOpt button) = 0;
|
virtual void MessageBoxInfo(QWidget *parent, const QString &title, const QString &text, MessageOpt button) = 0;
|
||||||
virtual MessageOpt MessageBoxAsk(QWidget *parent, const QString &title, const QString &text, const QList<MessageOpt> &buttons) = 0;
|
virtual MessageOpt MessageBoxAsk(QWidget *parent, const QString &title, const QString &text, const QList<MessageOpt> &buttons) = 0;
|
||||||
virtual void OpenURL(const QString &url) = 0;
|
virtual void OpenURL(const QString &url) = 0;
|
||||||
|
|
||||||
private:
|
|
||||||
static Qv2rayPreInitResult ParseCommandLine(QString *errorMessage, const QStringList &_argx_);
|
|
||||||
};
|
};
|
||||||
inline Qv2rayApplicationManager *qvApplicationInstance = nullptr;
|
inline Qv2rayApplicationInterface *QvCoreApplication = nullptr;
|
||||||
} // namespace Qv2ray
|
} // namespace Qv2ray
|
||||||
|
|
||||||
#define QvCoreApplication static_cast<Qv2rayApplicationManager *>(qvApplicationInstance)
|
#define GlobalConfig (*Qv2ray::QvCoreApplication->ConfigObject)
|
||||||
#define GlobalConfig (*Qv2ray::qvApplicationInstance->ConfigObject)
|
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
|
|
||||||
#define _LOG_ARG_(...) QV2RAY_LOG_PREPEND_CONTENT "[" QV_MODULE_NAME "]", __VA_ARGS__
|
#define _LOG_ARG_(...) QV2RAY_LOG_PREPEND_CONTENT "[" QV_MODULE_NAME "]", __VA_ARGS__
|
||||||
|
|
||||||
#define LOG(...) Qv2ray::base::log_concat<QV2RAY_LOG_NORMAL>(_LOG_ARG_(__VA_ARGS__))
|
#define LOG(...) Qv2ray::base::log_internal<QV2RAY_LOG_NORMAL>(_LOG_ARG_(__VA_ARGS__))
|
||||||
#define DEBUG(...) Qv2ray::base::log_concat<QV2RAY_LOG_DEBUG>(_LOG_ARG_(__VA_ARGS__))
|
#define DEBUG(...) Qv2ray::base::log_internal<QV2RAY_LOG_DEBUG>(_LOG_ARG_(__VA_ARGS__))
|
||||||
|
|
||||||
enum QvLogType
|
enum QvLogType
|
||||||
{
|
{
|
||||||
@ -51,7 +51,7 @@ namespace Qv2ray::base
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<QvLogType t, typename... T>
|
template<QvLogType t, typename... T>
|
||||||
inline void log_concat(T... v)
|
inline void log_internal(T... v)
|
||||||
{
|
{
|
||||||
((logStream << v << " "), ...);
|
((logStream << v << " "), ...);
|
||||||
((tempStream << v << " "), ...);
|
((tempStream << v << " "), ...);
|
||||||
|
@ -80,7 +80,7 @@ namespace Qv2ray::base::objects::complex
|
|||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
explicit OutboundObjectMeta() : metaType(METAOUTBOUND_ORIGINAL){};
|
explicit OutboundObjectMeta() : metaType(METAOUTBOUND_ORIGINAL){};
|
||||||
JSONSTRUCT_REGISTER(OutboundObjectMeta, F(metaType, displayName, connectionId, outboundTags))
|
JSONSTRUCT_REGISTER(OutboundObjectMeta, F(metaType, displayName, connectionId, outboundTags, chainPortAllocation))
|
||||||
};
|
};
|
||||||
|
|
||||||
inline OutboundObjectMeta make_chained_outbound(const QList<QString> &chain, const QString &tag)
|
inline OutboundObjectMeta make_chained_outbound(const QList<QString> &chain, const QString &tag)
|
||||||
|
@ -1,27 +1 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Qv2ray::base
|
|
||||||
{
|
|
||||||
struct QvStartupOptions
|
|
||||||
{
|
|
||||||
/// No API subsystem
|
|
||||||
bool noAPI;
|
|
||||||
|
|
||||||
/// Do not automatically connect to a server
|
|
||||||
bool noAutoConnection;
|
|
||||||
|
|
||||||
/// Enable Debug Log.
|
|
||||||
bool debugLog;
|
|
||||||
|
|
||||||
/// Disable Qt scale factors support.
|
|
||||||
bool noScaleFactor;
|
|
||||||
|
|
||||||
/// Disable all plugin features.
|
|
||||||
bool noPlugins;
|
|
||||||
|
|
||||||
/// Exit existing Qv2ray instance
|
|
||||||
bool exitQv2ray;
|
|
||||||
};
|
|
||||||
} // namespace Qv2ray::base
|
|
||||||
|
|
||||||
inline Qv2ray::base::QvStartupOptions StartupOption = Qv2ray::base::QvStartupOptions();
|
|
||||||
|
@ -12,7 +12,7 @@ namespace Qv2ray::components::plugins
|
|||||||
{
|
{
|
||||||
QvPluginHost::QvPluginHost(QObject *parent) : QObject(parent)
|
QvPluginHost::QvPluginHost(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
if (!StartupOption.noPlugins)
|
if (!QvCoreApplication->StartupArguments.noPlugins)
|
||||||
{
|
{
|
||||||
if (auto dir = QDir(QV2RAY_PLUGIN_SETTINGS_DIR); !dir.exists())
|
if (auto dir = QDir(QV2RAY_PLUGIN_SETTINGS_DIR); !dir.exists())
|
||||||
{
|
{
|
||||||
@ -30,7 +30,7 @@ namespace Qv2ray::components::plugins
|
|||||||
{
|
{
|
||||||
clearPlugins();
|
clearPlugins();
|
||||||
LOG("Reloading plugin list");
|
LOG("Reloading plugin list");
|
||||||
for (const auto &pluginDirPath : Qv2rayAssetsPaths("plugins"))
|
for (const auto &pluginDirPath : QvCoreApplication->GetAssetsPaths("plugins"))
|
||||||
{
|
{
|
||||||
const QStringList entries = QDir(pluginDirPath).entryList(QDir::Files);
|
const QStringList entries = QDir(pluginDirPath).entryList(QDir::Files);
|
||||||
for (const auto &fileName : entries)
|
for (const auto &fileName : entries)
|
||||||
|
@ -11,7 +11,7 @@ using namespace Qv2ray::base;
|
|||||||
QStringList getLanguageSearchPaths()
|
QStringList getLanguageSearchPaths()
|
||||||
{
|
{
|
||||||
// Configuration Path
|
// Configuration Path
|
||||||
QStringList list = Qv2rayAssetsPaths("lang");
|
QStringList list = QvCoreApplication->GetAssetsPaths("lang");
|
||||||
#ifdef QV2RAY_EMBED_TRANSLATIONS
|
#ifdef QV2RAY_EMBED_TRANSLATIONS
|
||||||
// If the translations have been embedded.
|
// If the translations have been embedded.
|
||||||
list << QString(":/translations/");
|
list << QString(":/translations/");
|
||||||
|
@ -19,18 +19,6 @@ namespace Qv2ray::core::kernel
|
|||||||
{ API_OUTBOUND_DIRECT, { "freedom" } },
|
{ API_OUTBOUND_DIRECT, { "freedom" } },
|
||||||
{ API_OUTBOUND_BLACKHOLE, { "blackhole" } } };
|
{ API_OUTBOUND_BLACKHOLE, { "blackhole" } } };
|
||||||
|
|
||||||
// To all contributors:
|
|
||||||
//
|
|
||||||
// You may feel it difficult to understand this part of API backend.
|
|
||||||
// It's been expected that you will take hours to fully understand the tricks and hacks lying deeply in this class.
|
|
||||||
//
|
|
||||||
// The API Worker runs as a daemon together with Qv2ray, on a single thread.
|
|
||||||
// They use a flag, running, to indicate if the API worker should go and fetch the statistics from V2Ray Core.
|
|
||||||
//
|
|
||||||
// The flag, running, will be set to true, immediately after the V2Ray core reported that it's been started.
|
|
||||||
// and will be set to false right before we stopping V2Ray Core.
|
|
||||||
//
|
|
||||||
|
|
||||||
APIWorker::APIWorker()
|
APIWorker::APIWorker()
|
||||||
{
|
{
|
||||||
workThread = new QThread();
|
workThread = new QThread();
|
||||||
|
@ -286,12 +286,11 @@ namespace Qv2ray::core::kernel
|
|||||||
|
|
||||||
if (ValidateConfig(filePath))
|
if (ValidateConfig(filePath))
|
||||||
{
|
{
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
auto env = QProcessEnvironment::systemEnvironment();
|
||||||
env.insert("V2RAY_LOCATION_ASSET", GlobalConfig.kernelConfig.AssetsPath());
|
env.insert("V2RAY_LOCATION_ASSET", GlobalConfig.kernelConfig.AssetsPath());
|
||||||
vProcess->setProcessEnvironment(env);
|
vProcess->setProcessEnvironment(env);
|
||||||
vProcess->start(GlobalConfig.kernelConfig.KernelPath(), { "-config", filePath }, QIODevice::ReadWrite | QIODevice::Text);
|
vProcess->start(GlobalConfig.kernelConfig.KernelPath(), { "-config", filePath }, QIODevice::ReadWrite | QIODevice::Text);
|
||||||
vProcess->waitForStarted();
|
vProcess->waitForStarted();
|
||||||
DEBUG("V2Ray core started.");
|
|
||||||
KernelStarted = true;
|
KernelStarted = true;
|
||||||
|
|
||||||
QMap<bool, QMap<QString, QString>> tagProtocolMap;
|
QMap<bool, QMap<QString, QString>> tagProtocolMap;
|
||||||
@ -312,7 +311,7 @@ namespace Qv2ray::core::kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
apiEnabled = false;
|
apiEnabled = false;
|
||||||
if (StartupOption.noAPI)
|
if (QvCoreApplication->StartupArguments.noAPI)
|
||||||
{
|
{
|
||||||
LOG("API has been disabled by the command line arguments");
|
LOG("API has been disabled by the command line arguments");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "SettingsBackend.hpp"
|
#include "SettingsBackend.hpp"
|
||||||
|
|
||||||
|
#include "base/Qv2rayLog.hpp"
|
||||||
#include "utils/QvHelpers.hpp"
|
#include "utils/QvHelpers.hpp"
|
||||||
|
|
||||||
#define QV_MODULE_NAME "SettingsBackend"
|
#define QV_MODULE_NAME "SettingsBackend"
|
||||||
|
constexpr auto QV2RAY_CONFIG_PATH_ENV_NAME = "QV2RAY_CONFIG_PATH";
|
||||||
|
|
||||||
namespace Qv2ray::core::config
|
namespace Qv2ray::core::config
|
||||||
{
|
{
|
||||||
@ -14,11 +16,11 @@ namespace Qv2ray::core::config
|
|||||||
|
|
||||||
void SetConfigDirPath(const QString &path)
|
void SetConfigDirPath(const QString &path)
|
||||||
{
|
{
|
||||||
qvApplicationInstance->ConfigPath = path;
|
QvCoreApplication->ConfigPath = path;
|
||||||
|
|
||||||
if (!path.endsWith("/"))
|
if (!path.endsWith("/"))
|
||||||
{
|
{
|
||||||
qvApplicationInstance->ConfigPath += "/";
|
QvCoreApplication->ConfigPath += "/";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +92,177 @@ namespace Qv2ray::core::config
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LocateConfiguration()
|
||||||
|
{
|
||||||
|
LOG("Application exec path: " + qApp->applicationDirPath());
|
||||||
|
// Non-standard paths needs special handing for "_debug"
|
||||||
|
const auto currentPathConfig = qApp->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).
|
||||||
|
const auto useManualConfigPath = qEnvironmentVariableIsSet(QV2RAY_CONFIG_PATH_ENV_NAME);
|
||||||
|
const auto manualConfigPath = qEnvironmentVariable(QV2RAY_CONFIG_PATH_ENV_NAME);
|
||||||
|
//
|
||||||
|
QStringList configFilePaths;
|
||||||
|
if (useManualConfigPath)
|
||||||
|
{
|
||||||
|
LOG("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("Path:", path, " is valid.");
|
||||||
|
configPath = path;
|
||||||
|
hasExistingConfig = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG("Path:", path, "does not contain a valid config file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasExistingConfig)
|
||||||
|
{
|
||||||
|
// Use the config path found by the checks above
|
||||||
|
SetConfigDirPath(configPath);
|
||||||
|
LOG("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("FATAL");
|
||||||
|
LOG(" ---> CANNOT find a proper place to store Qv2ray config files.");
|
||||||
|
QvMessageBoxWarn(nullptr, QObject::tr("Cannot Start Qv2ray"),
|
||||||
|
QObject::tr("Cannot find a place to store config files.") + NEWLINE + //
|
||||||
|
QObject::tr("Qv2ray has searched these paths below:") + NEWLINE + NEWLINE + //
|
||||||
|
configFilePaths.join(NEWLINE) + NEWLINE + //
|
||||||
|
QObject::tr("It usually means you don't have the write permission to all of those locations.") + NEWLINE + //
|
||||||
|
QObject::tr("Qv2ray will now exit.")); //
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found a valid config dir, with write permission, but assume no config is located in it.
|
||||||
|
LOG("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("This should not occur: Qv2ray config exists but failed to load.");
|
||||||
|
QvMessageBoxWarn(nullptr, QObject::tr("Failed to initialise Qv2ray"),
|
||||||
|
QObject::tr("Failed to determine the location of config file:") + NEWLINE + //
|
||||||
|
QObject::tr("Qv2ray has found a config file, but it failed to be loaded due to some errors.") + NEWLINE + //
|
||||||
|
QObject::tr("A workaround is to remove the this file and restart Qv2ray:") + NEWLINE + //
|
||||||
|
QV2RAY_CONFIG_FILE + NEWLINE + //
|
||||||
|
QObject::tr("Qv2ray will now exit.") + NEWLINE + //
|
||||||
|
QObject::tr("Please report if you think it's a bug.")); //
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalConfig.kernelConfig.KernelPath(QString(QV2RAY_DEFAULT_VCORE_PATH));
|
||||||
|
GlobalConfig.kernelConfig.AssetsPath(QString(QV2RAY_DEFAULT_VASSETS_PATH));
|
||||||
|
GlobalConfig.logLevel = 3;
|
||||||
|
GlobalConfig.uiConfig.language = QLocale::system().name();
|
||||||
|
GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "1.1.1.1" });
|
||||||
|
GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "8.8.8.8" });
|
||||||
|
GlobalConfig.defaultRouteConfig.dnsConfig.servers.append({ "8.8.4.4" });
|
||||||
|
|
||||||
|
// Save initial config.
|
||||||
|
SaveGlobalSettings();
|
||||||
|
LOG("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("Created config generation dir at: " + QV2RAY_GENERATED_DIR);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// BEGIN LOAD CONFIGURATIONS
|
||||||
|
//
|
||||||
|
{
|
||||||
|
// 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, QObject::tr("Qv2ray Cannot Continue"), //
|
||||||
|
QObject::tr("You are running a lower version of Qv2ray compared to the current config file.") + NEWLINE + //
|
||||||
|
QObject::tr("Please check if there's an issue explaining about it.") + NEWLINE + //
|
||||||
|
QObject::tr("Or submit a new issue if you think this is an error.") + NEWLINE + NEWLINE + //
|
||||||
|
QObject::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's save the config.
|
||||||
|
GlobalConfig.loadJson(conf);
|
||||||
|
SaveGlobalSettings();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Qv2ray::core::config
|
} // namespace Qv2ray::core::config
|
||||||
|
|
||||||
using namespace Qv2ray::core::config;
|
using namespace Qv2ray::core::config;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace Qv2ray::core::config
|
namespace Qv2ray::core::config
|
||||||
{
|
{
|
||||||
void SaveGlobalSettings();
|
void SaveGlobalSettings();
|
||||||
|
bool LocateConfiguration();
|
||||||
void SetConfigDirPath(const QString &path);
|
void SetConfigDirPath(const QString &path);
|
||||||
bool CheckSettingsPathAvailability(const QString &_path, bool checkExistingConfig);
|
bool CheckSettingsPathAvailability(const QString &_path, bool checkExistingConfig);
|
||||||
} // namespace Qv2ray::core::config
|
} // namespace Qv2ray::core::config
|
||||||
|
89
src/main.cpp
89
src/main.cpp
@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
#define QV_MODULE_NAME "Init"
|
#define QV_MODULE_NAME "Init"
|
||||||
|
|
||||||
|
#define EXITCODE_ERROR 1;
|
||||||
|
#define EXITCODE_NORMAL 0
|
||||||
|
|
||||||
int globalArgc;
|
int globalArgc;
|
||||||
char **globalArgv;
|
char **globalArgv;
|
||||||
|
|
||||||
@ -177,6 +180,30 @@ LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void ProcessExitReason(Qv2rayExitReason reason)
|
||||||
|
{ // app.MessageBoxWarn(nullptr, app.tr("Cannot start Qv2ray"), app.tr("Qv2ray early initialization failed."));
|
||||||
|
// return QVEXIT_EARLY_SETUP_FAIL;
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case EXIT_CRASHED:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EXIT_NORMAL:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EXIT_PREINITIALIZATION_FAILED:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EXIT_PRECONDITION_FAILED:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
globalArgc = argc;
|
globalArgc = argc;
|
||||||
@ -195,44 +222,20 @@ int main(int argc, char *argv[])
|
|||||||
// This line must be called before any other ones, since we are using these
|
// This line must be called before any other ones, since we are using these
|
||||||
// values to identify instances.
|
// values to identify instances.
|
||||||
QCoreApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
|
QCoreApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
|
||||||
//
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
QCoreApplication::setApplicationName("qv2ray_debug");
|
QCoreApplication::setApplicationName("qv2ray_debug");
|
||||||
// QApplication::setApplicationDisplayName("Qv2ray - " + QObject::tr("Debug version"));
|
|
||||||
#else
|
#else
|
||||||
QCoreApplication::setApplicationName("qv2ray");
|
QCoreApplication::setApplicationName("qv2ray");
|
||||||
#ifdef QV2RAY_GUI
|
#ifdef QV2RAY_GUI
|
||||||
QApplication::setApplicationDisplayName("Qv2ray");
|
QApplication::setApplicationDisplayName("Qv2ray");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
LOG("LICENCE", NEWLINE //
|
|
||||||
"This program comes with ABSOLUTELY NO WARRANTY." NEWLINE //
|
|
||||||
"This is free software, and you are welcome to redistribute it" NEWLINE //
|
|
||||||
"under certain conditions." NEWLINE NEWLINE //
|
|
||||||
"Copyright (c) 2019-2020 Qv2ray Development Group." NEWLINE //
|
|
||||||
"Third-party libraries that have been used in Qv2ray can be found in the About page." NEWLINE);
|
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
std::cerr << "WARNING: ================ This is a debug build, many features are not stable enough. ================" << std::endl;
|
std::cerr << "WARNING: ================ This is a debug build, many features are not stable enough. ================" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// parse the command line before starting as a Qt application
|
if (qEnvironmentVariableIsSet("QV2RAY_NO_SCALE_FACTORS"))
|
||||||
switch (Qv2rayApplicationManager::StaticPreInitialize(argc, argv))
|
|
||||||
{
|
|
||||||
case PRE_INIT_RESULT_QUIT: return QVEXIT_NORMAL;
|
|
||||||
case PRE_INIT_RESULT_CONTINUE: break;
|
|
||||||
case PRE_INIT_RESULT_ERROR:
|
|
||||||
{
|
|
||||||
BootstrapMessageBox("Cannot Start Qv2ray!", "Early initialization failed!");
|
|
||||||
return QVEXIT_PRE_INITIALIZE_FAIL;
|
|
||||||
}
|
|
||||||
default: Q_UNREACHABLE();
|
|
||||||
}
|
|
||||||
#ifndef QV2RAY_QT6
|
|
||||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
|
||||||
#endif
|
|
||||||
// noScaleFactors = disable HiDPI
|
|
||||||
if (StartupOption.noScaleFactor)
|
|
||||||
{
|
{
|
||||||
LOG("Force set QT_SCALE_FACTOR to 1.");
|
LOG("Force set QT_SCALE_FACTOR to 1.");
|
||||||
DEBUG("UI", "Original QT_SCALE_FACTOR was:", qEnvironmentVariable("QT_SCALE_FACTOR"));
|
DEBUG("UI", "Original QT_SCALE_FACTOR was:", qEnvironmentVariable("QT_SCALE_FACTOR"));
|
||||||
@ -251,6 +254,10 @@ int main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef QV2RAY_QT6
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check OpenSSL version for auto-update and subscriptions
|
// Check OpenSSL version for auto-update and subscriptions
|
||||||
auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString();
|
auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString();
|
||||||
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
|
auto osslCurVersion = QSslSocket::sslLibraryVersionString();
|
||||||
@ -268,28 +275,14 @@ int main(int argc, char *argv[])
|
|||||||
"OSsl.Rq.V=" + osslReqVersion + NEWLINE + //
|
"OSsl.Rq.V=" + osslReqVersion + NEWLINE + //
|
||||||
"OSsl.Cr.V=" + osslCurVersion);
|
"OSsl.Cr.V=" + osslCurVersion);
|
||||||
BootstrapMessageBox(QObject::tr("Cannot start Qv2ray"), QObject::tr("Cannot start Qv2ray without OpenSSL"));
|
BootstrapMessageBox(QObject::tr("Cannot start Qv2ray"), QObject::tr("Cannot start Qv2ray without OpenSSL"));
|
||||||
return QVEXIT_SSL_FAIL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qv2rayApplication app(argc, argv);
|
Qv2rayApplication app(argc, argv);
|
||||||
switch (app.Initialize())
|
if (!app.Initialize())
|
||||||
{
|
{
|
||||||
case NORMAL: break;
|
LOG("Qv2ray initialization failed:", app.ExitReason);
|
||||||
case SINGLE_APPLICATION: return QVEXIT_SECONDARY_INSTANCE;
|
ProcessExitReason(app.ExitReason);
|
||||||
case FAILED:
|
|
||||||
{
|
|
||||||
app.MessageBoxWarn(nullptr, app.tr("Cannot start Qv2ray"), app.tr("Qv2ray early initialization failed."));
|
|
||||||
return QVEXIT_EARLY_SETUP_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Qv2ray Initialize, find possible config paths and verify them.
|
|
||||||
if (!app.LocateConfiguration())
|
|
||||||
{
|
|
||||||
LOG("Cannot load or create initial configuration file.");
|
|
||||||
app.MessageBoxWarn(nullptr, app.tr("Cannot start Qv2ray"), app.tr("Cannot load config file."));
|
|
||||||
return QVEXIT_CONFIG_FILE_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
@ -297,11 +290,11 @@ int main(int argc, char *argv[])
|
|||||||
signal(SIGUSR2, [](int) { ConnectionManager->StopConnection(); });
|
signal(SIGUSR2, [](int) { ConnectionManager->StopConnection(); });
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto rcode = app.RunQv2ray();
|
app.RunQv2ray();
|
||||||
if (rcode == QVEXIT_NEW_VERSION)
|
if (app.ExitReason == EXIT_NEW_VERSION_TRIGGER)
|
||||||
{
|
{
|
||||||
LOG("Starting new version of Qv2ray: " + Qv2rayProcessArgument._qvNewVersionPath);
|
LOG("Starting new version of Qv2ray: " + app.StartupArguments._qvNewVersionPath);
|
||||||
QProcess::startDetached(Qv2rayProcessArgument._qvNewVersionPath, {});
|
QProcess::startDetached(app.StartupArguments._qvNewVersionPath, {});
|
||||||
}
|
}
|
||||||
return rcode;
|
return app.ExitReason;
|
||||||
}
|
}
|
||||||
|
221
src/ui/Qv2rayPlatformApplication.cpp
Normal file
221
src/ui/Qv2rayPlatformApplication.cpp
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
#include "Qv2rayPlatformApplication.hpp"
|
||||||
|
|
||||||
|
#include "core/settings/SettingsBackend.hpp"
|
||||||
|
#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
|
||||||
|
|
||||||
|
bool Qv2rayPlatformApplication::initializeInternal()
|
||||||
|
{
|
||||||
|
QString errorMessage;
|
||||||
|
bool canContinue;
|
||||||
|
auto hasError = parseCommandLine(&errorMessage, &canContinue);
|
||||||
|
if (hasError && !canContinue)
|
||||||
|
return false;
|
||||||
|
#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.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.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#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());
|
||||||
|
//
|
||||||
|
//
|
||||||
|
LocateConfiguration();
|
||||||
|
//
|
||||||
|
const auto allTranslations = Qv2rayTranslator->GetAvailableLanguages();
|
||||||
|
const auto osLanguage = QLocale::system().name();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Qv2rayPlatformApplication::runInternal()
|
||||||
|
{
|
||||||
|
PluginHost = new QvPluginHost();
|
||||||
|
RouteManager = new RouteHandler();
|
||||||
|
ConnectionManager = new QvConfigHandler();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Qv2rayPlatformApplication::quitInternal()
|
||||||
|
{
|
||||||
|
// Do not change the order.
|
||||||
|
ConnectionManager->StopConnection();
|
||||||
|
RouteManager->SaveRoutes();
|
||||||
|
ConnectionManager->SaveConnectionConfig();
|
||||||
|
PluginHost->SavePluginSettings();
|
||||||
|
SaveGlobalSettings();
|
||||||
|
TerminateUI();
|
||||||
|
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;
|
||||||
|
}
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#ifdef QV2RAY_GUI
|
#ifdef QV2RAY_GUI
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QFont>
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
const static inline QMap<MessageOpt, QMessageBox::StandardButton> MessageBoxButtonMap //
|
const static inline QMap<MessageOpt, QMessageBox::StandardButton> MessageBoxButtonMap //
|
||||||
= { { No, QMessageBox::No },
|
= { { No, QMessageBox::No },
|
||||||
@ -37,97 +36,36 @@ const static inline QMap<MessageOpt, QMessageBox::StandardButton> MessageBoxButt
|
|||||||
|
|
||||||
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
||||||
#include <SingleApplication>
|
#include <SingleApplication>
|
||||||
#define QV2RAY_BASE_APPLICATION_CLASS SingleApplication
|
#define QVBASEAPPLICATION SingleApplication
|
||||||
#define QV2RAY_BASE_CLASS_CONSTRUCTOR_ARGS argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion
|
#define QVBASEAPPLICATION_CTORARGS argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion
|
||||||
#else
|
#else
|
||||||
#define QV2RAY_BASE_APPLICATION_CLASS QAPPLICATION_CLASS
|
#define QVBASEAPPLICATION QAPPLICATION_CLASS
|
||||||
#define QV2RAY_BASE_CLASS_CONSTRUCTOR_ARGS argc, argv
|
#define QVBASEAPPLICATION_CTORARGS argc, argv
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Qv2rayPlatformApplication
|
class Qv2rayPlatformApplication
|
||||||
: public QV2RAY_BASE_APPLICATION_CLASS
|
: public QVBASEAPPLICATION
|
||||||
, public Qv2rayApplicationManager
|
, public Qv2rayApplicationInterface
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Qv2rayPlatformApplication(int &argc, char *argv[])
|
Qv2rayPlatformApplication(int &argc, char *argv[]) : QVBASEAPPLICATION(QVBASEAPPLICATION_CTORARGS), Qv2rayApplicationInterface(){};
|
||||||
: QV2RAY_BASE_APPLICATION_CLASS(QV2RAY_BASE_CLASS_CONSTRUCTOR_ARGS), Qv2rayApplicationManager(){};
|
|
||||||
virtual ~Qv2rayPlatformApplication(){};
|
virtual ~Qv2rayPlatformApplication(){};
|
||||||
|
inline void QuitApplication(int retCode = 0)
|
||||||
void QuitApplication(int retCode = 0)
|
|
||||||
{
|
{
|
||||||
QCoreApplication::exit(retCode);
|
QCoreApplication::exit(retCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Qv2raySetupStatus InitializeInternal()
|
bool initializeInternal();
|
||||||
{
|
bool runInternal();
|
||||||
connect(this, &Qv2rayPlatformApplication::aboutToQuit, this, &Qv2rayPlatformApplication::QuitInternal);
|
void quitInternal();
|
||||||
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
|
||||||
connect(this, &SingleApplication::receivedMessage, this, &Qv2rayPlatformApplication::onMessageReceived, Qt::QueuedConnection);
|
|
||||||
if (isSecondary())
|
|
||||||
{
|
|
||||||
if (Qv2rayProcessArgument.arguments.isEmpty())
|
|
||||||
Qv2rayProcessArgument.arguments << Qv2rayProcessArguments::NORMAL;
|
|
||||||
sendMessage(JsonToString(Qv2rayProcessArgument.toJson(), QJsonDocument::Compact).toUtf8());
|
|
||||||
return SINGLE_APPLICATION;
|
|
||||||
}
|
|
||||||
#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());
|
|
||||||
return NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RunInternal()
|
|
||||||
{
|
|
||||||
PluginHost = new QvPluginHost();
|
|
||||||
RouteManager = new RouteHandler();
|
|
||||||
ConnectionManager = new QvConfigHandler();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QuitInternal()
|
|
||||||
{
|
|
||||||
// Do not change the order.
|
|
||||||
ConnectionManager->StopConnection();
|
|
||||||
RouteManager->SaveRoutes();
|
|
||||||
ConnectionManager->SaveConnectionConfig();
|
|
||||||
PluginHost->SavePluginSettings();
|
|
||||||
SaveGlobalSettings();
|
|
||||||
TerminateUI();
|
|
||||||
delete ConnectionManager;
|
|
||||||
delete RouteManager;
|
|
||||||
delete PluginHost;
|
|
||||||
ConnectionManager = nullptr;
|
|
||||||
RouteManager = nullptr;
|
|
||||||
PluginHost = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void TerminateUI() = 0;
|
virtual void TerminateUI() = 0;
|
||||||
|
|
||||||
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
||||||
virtual void onMessageReceived(quint32 clientId, QByteArray msg) = 0;
|
virtual void onMessageReceived(quint32 clientId, QByteArray msg) = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool parseCommandLine(QString *errorMessage, bool *canContinue);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "Qv2rayWidgetApplication.hpp"
|
#include "Qv2rayWidgetApplication.hpp"
|
||||||
|
|
||||||
#include "3rdparty/libsemver/version.hpp"
|
|
||||||
#include "base/Qv2rayBase.hpp"
|
#include "base/Qv2rayBase.hpp"
|
||||||
#include "components/translations/QvTranslator.hpp"
|
#include "components/translations/QvTranslator.hpp"
|
||||||
#include "core/settings/SettingsBackend.hpp"
|
#include "core/settings/SettingsBackend.hpp"
|
||||||
@ -22,61 +21,59 @@
|
|||||||
|
|
||||||
constexpr auto QV2RAY_WIDGETUI_STATE_FILENAME = "UIState.json";
|
constexpr auto QV2RAY_WIDGETUI_STATE_FILENAME = "UIState.json";
|
||||||
|
|
||||||
namespace Qv2ray
|
Qv2rayWidgetApplication::Qv2rayWidgetApplication(int &argc, char *argv[]) : Qv2rayPlatformApplication(argc, argv)
|
||||||
{
|
{
|
||||||
Qv2rayWidgetApplication::Qv2rayWidgetApplication(int &argc, char *argv[]) : Qv2rayPlatformApplication(argc, argv)
|
}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Qv2raySetupStatus Qv2rayWidgetApplication::Initialize()
|
bool Qv2rayWidgetApplication::Initialize()
|
||||||
{
|
{
|
||||||
const auto result = InitializeInternal();
|
const auto result = initializeInternal();
|
||||||
if (result != NORMAL)
|
if (!result)
|
||||||
return result;
|
return false;
|
||||||
setQuitOnLastWindowClosed(false);
|
setQuitOnLastWindowClosed(false);
|
||||||
hTray = new QSystemTrayIcon();
|
hTray = new QSystemTrayIcon();
|
||||||
return NORMAL;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qv2rayWidgetApplication::TerminateUI()
|
void Qv2rayWidgetApplication::TerminateUI()
|
||||||
{
|
{
|
||||||
delete mainWindow;
|
delete mainWindow;
|
||||||
delete hTray;
|
delete hTray;
|
||||||
delete StyleManager;
|
delete StyleManager;
|
||||||
StringToFile(JsonToString(UIStates), QV2RAY_CONFIG_DIR + QV2RAY_WIDGETUI_STATE_FILENAME);
|
StringToFile(JsonToString(UIStates), QV2RAY_CONFIG_DIR + QV2RAY_WIDGETUI_STATE_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
||||||
void Qv2rayWidgetApplication::onMessageReceived(quint32 clientId, QByteArray _msg)
|
void Qv2rayWidgetApplication::onMessageReceived(quint32 clientId, QByteArray _msg)
|
||||||
{
|
{
|
||||||
// Sometimes SingleApplication will send message with clientId == 0, ignore them.
|
// Sometimes SingleApplication will send message with clientId == 0, ignore them.
|
||||||
if (clientId == instanceId())
|
if (clientId == instanceId())
|
||||||
return;
|
return;
|
||||||
const auto msg = Qv2rayProcessArguments::fromJson(JsonFromString(_msg));
|
|
||||||
LOG("Client ID:", clientId, ", message received, version:", msg.version);
|
if (!isInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto msg = Qv2rayStartupArguments::fromJson(JsonFromString(_msg));
|
||||||
|
LOG("Client ID:", clientId, ", message received, version:", msg.buildVersion);
|
||||||
DEBUG(_msg);
|
DEBUG(_msg);
|
||||||
//
|
//
|
||||||
const auto currentVersion = semver::version::from_string(QV2RAY_VERSION_STRING);
|
if (msg.buildVersion > QV2RAY_VERSION_BUILD)
|
||||||
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();
|
const auto newPath = msg.fullArgs.first();
|
||||||
QString message;
|
QString message;
|
||||||
message += tr("A new version of Qv2ray is starting:") + NEWLINE;
|
message += tr("A new version of Qv2ray is starting:") + NEWLINE;
|
||||||
message += NEWLINE;
|
message += NEWLINE;
|
||||||
message += tr("New version information: ") + NEWLINE;
|
message += tr("New version information: ") + NEWLINE;
|
||||||
message += tr("Qv2ray version: %1").arg(msg.version) + NEWLINE;
|
message += tr("Version: %1:%2").arg(msg.version).arg(msg.buildVersion) + NEWLINE;
|
||||||
message += tr("Qv2ray path: %1").arg(newPath) + NEWLINE;
|
message += tr("Path: %1").arg(newPath) + NEWLINE;
|
||||||
message += NEWLINE;
|
message += NEWLINE;
|
||||||
message += tr("Do you want to exit and launch that new version?");
|
message += tr("Do you want to exit and launch that new version?");
|
||||||
|
|
||||||
const auto result = QvMessageBoxAsk(nullptr, tr("New version detected"), message);
|
const auto result = QvMessageBoxAsk(nullptr, tr("New version detected"), message);
|
||||||
if (result == Yes)
|
if (result == Yes)
|
||||||
{
|
{
|
||||||
Qv2rayProcessArgument._qvNewVersionPath = newPath;
|
StartupArguments._qvNewVersionPath = newPath;
|
||||||
QuitApplication(QVEXIT_NEW_VERSION);
|
QuitApplication(EXIT_NEW_VERSION_TRIGGER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,29 +81,29 @@ namespace Qv2ray
|
|||||||
{
|
{
|
||||||
switch (argument)
|
switch (argument)
|
||||||
{
|
{
|
||||||
case Qv2rayProcessArguments::EXIT:
|
case Qv2rayStartupArguments::EXIT:
|
||||||
{
|
{
|
||||||
QuitApplication();
|
QuitApplication();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qv2rayProcessArguments::NORMAL:
|
case Qv2rayStartupArguments::NORMAL:
|
||||||
{
|
{
|
||||||
mainWindow->show();
|
mainWindow->show();
|
||||||
mainWindow->raise();
|
mainWindow->raise();
|
||||||
mainWindow->activateWindow();
|
mainWindow->activateWindow();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qv2rayProcessArguments::RECONNECT:
|
case Qv2rayStartupArguments::RECONNECT:
|
||||||
{
|
{
|
||||||
ConnectionManager->RestartConnection();
|
ConnectionManager->RestartConnection();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qv2rayProcessArguments::DISCONNECT:
|
case Qv2rayStartupArguments::DISCONNECT:
|
||||||
{
|
{
|
||||||
ConnectionManager->StopConnection();
|
ConnectionManager->StopConnection();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qv2rayProcessArguments::QV2RAY_LINK:
|
case Qv2rayStartupArguments::QV2RAY_LINK:
|
||||||
{
|
{
|
||||||
for (const auto &link : msg.links)
|
for (const auto &link : msg.links)
|
||||||
{
|
{
|
||||||
@ -128,20 +125,20 @@ namespace Qv2ray
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Qv2rayExitCode Qv2rayWidgetApplication::RunQv2ray()
|
Qv2rayExitReason Qv2rayWidgetApplication::RunQv2ray()
|
||||||
{
|
{
|
||||||
RunInternal();
|
runInternal();
|
||||||
StyleManager = new QvStyleManager();
|
StyleManager = new QvStyleManager();
|
||||||
StyleManager->ApplyStyle(GlobalConfig.uiConfig.theme);
|
StyleManager->ApplyStyle(GlobalConfig.uiConfig.theme);
|
||||||
// Show MainWindow
|
// Show MainWindow
|
||||||
UIStates = JsonFromString(StringFromFile(QV2RAY_CONFIG_DIR + QV2RAY_WIDGETUI_STATE_FILENAME));
|
UIStates = JsonFromString(StringFromFile(QV2RAY_CONFIG_DIR + QV2RAY_WIDGETUI_STATE_FILENAME));
|
||||||
mainWindow = new MainWindow();
|
mainWindow = new MainWindow();
|
||||||
if (Qv2rayProcessArgument.arguments.contains(Qv2rayProcessArguments::QV2RAY_LINK))
|
if (StartupArguments.arguments.contains(Qv2rayStartupArguments::QV2RAY_LINK))
|
||||||
{
|
{
|
||||||
for (const auto &link : Qv2rayProcessArgument.links)
|
for (const auto &link : StartupArguments.links)
|
||||||
{
|
{
|
||||||
const auto url = QUrl::fromUserInput(link);
|
const auto url = QUrl::fromUserInput(link);
|
||||||
const auto command = url.host();
|
const auto command = url.host();
|
||||||
@ -175,42 +172,41 @@ namespace Qv2ray
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
return (Qv2rayExitCode) exec();
|
isInitialized = true;
|
||||||
}
|
return (Qv2rayExitReason) exec();
|
||||||
|
}
|
||||||
|
|
||||||
void Qv2rayWidgetApplication::OpenURL(const QString &url)
|
void Qv2rayWidgetApplication::OpenURL(const QString &url)
|
||||||
{
|
{
|
||||||
QDesktopServices::openUrl(url);
|
QDesktopServices::openUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qv2rayWidgetApplication::MessageBoxWarn(QWidget *parent, const QString &title, const QString &text, MessageOpt button)
|
void Qv2rayWidgetApplication::MessageBoxWarn(QWidget *parent, const QString &title, const QString &text, MessageOpt button)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(parent, title, text, MessageBoxButtonMap[button]);
|
QMessageBox::warning(parent, title, text, MessageBoxButtonMap[button]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qv2rayWidgetApplication::MessageBoxInfo(QWidget *parent, const QString &title, const QString &text, MessageOpt button)
|
void Qv2rayWidgetApplication::MessageBoxInfo(QWidget *parent, const QString &title, const QString &text, MessageOpt button)
|
||||||
{
|
{
|
||||||
QMessageBox::information(parent, title, text, MessageBoxButtonMap[button]);
|
QMessageBox::information(parent, title, text, MessageBoxButtonMap[button]);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageOpt Qv2rayWidgetApplication::MessageBoxAsk(QWidget *parent, const QString &title, const QString &text, const QList<MessageOpt> &buttons)
|
MessageOpt Qv2rayWidgetApplication::MessageBoxAsk(QWidget *parent, const QString &title, const QString &text, const QList<MessageOpt> &buttons)
|
||||||
{
|
{
|
||||||
QFlags<QMessageBox::StandardButton> btns;
|
QFlags<QMessageBox::StandardButton> btns;
|
||||||
for (const auto &b : buttons)
|
for (const auto &b : buttons)
|
||||||
{
|
{
|
||||||
btns.setFlag(MessageBoxButtonMap[b]);
|
btns.setFlag(MessageBoxButtonMap[b]);
|
||||||
}
|
}
|
||||||
return MessageBoxButtonMap.key(QMessageBox::question(parent, title, text, btns));
|
return MessageBoxButtonMap.key(QMessageBox::question(parent, title, text, btns));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qv2rayWidgetApplication::ShowTrayMessage(const QString &m, const QIcon &icon, int msecs)
|
void Qv2rayWidgetApplication::ShowTrayMessage(const QString &m, const QIcon &icon, int msecs)
|
||||||
{
|
{
|
||||||
hTray->showMessage("Qv2ray", m, icon, msecs);
|
hTray->showMessage("Qv2ray", m, icon, msecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qv2rayWidgetApplication::ShowTrayMessage(const QString &m, QSystemTrayIcon::MessageIcon icon, int msecs)
|
void Qv2rayWidgetApplication::ShowTrayMessage(const QString &m, QSystemTrayIcon::MessageIcon icon, int msecs)
|
||||||
{
|
{
|
||||||
hTray->showMessage("Qv2ray", m, icon, msecs);
|
hTray->showMessage("Qv2ray", m, icon, msecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Qv2ray
|
|
||||||
|
@ -13,8 +13,8 @@ namespace Qv2ray
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit Qv2rayWidgetApplication(int &argc, char *argv[]);
|
explicit Qv2rayWidgetApplication(int &argc, char *argv[]);
|
||||||
Qv2raySetupStatus Initialize() override;
|
bool Initialize() override;
|
||||||
Qv2rayExitCode RunQv2ray() override;
|
Qv2rayExitReason RunQv2ray() override;
|
||||||
QJsonObject UIStates;
|
QJsonObject UIStates;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -31,6 +31,7 @@ namespace Qv2ray
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool isInitialized;
|
||||||
void TerminateUI() override;
|
void TerminateUI() override;
|
||||||
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
#ifndef QV2RAY_NO_SINGLEAPPLICATON
|
||||||
void onMessageReceived(quint32 clientID, QByteArray msg) override;
|
void onMessageReceived(quint32 clientID, QByteArray msg) override;
|
||||||
|
@ -33,7 +33,7 @@ namespace Qv2ray::ui::styles
|
|||||||
styles.insert(key, style);
|
styles.insert(key, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &styleDir : Qv2rayAssetsPaths("uistyles"))
|
for (const auto &styleDir : QvCoreApplication->GetAssetsPaths("uistyles"))
|
||||||
{
|
{
|
||||||
for (const auto &file : GetFileList(QDir(styleDir)))
|
for (const auto &file : GetFileList(QDir(styleDir)))
|
||||||
{
|
{
|
||||||
|
@ -101,7 +101,7 @@ void MainWindow::MWClearSystemProxy()
|
|||||||
|
|
||||||
bool MainWindow::StartAutoConnectionEntry()
|
bool MainWindow::StartAutoConnectionEntry()
|
||||||
{
|
{
|
||||||
if (StartupOption.noAutoConnection)
|
if (QvCoreApplication->StartupArguments.noAutoConnection)
|
||||||
return false;
|
return false;
|
||||||
switch (GlobalConfig.autoStartBehavior)
|
switch (GlobalConfig.autoStartBehavior)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +296,7 @@ void PreferencesWindow::on_buttonBox_accepted()
|
|||||||
ports << CurrentConfig.inboundConfig.tProxySettings.port;
|
ports << CurrentConfig.inboundConfig.tProxySettings.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StartupOption.noAPI)
|
if (!QvCoreApplication->StartupArguments.noAPI)
|
||||||
{
|
{
|
||||||
size++;
|
size++;
|
||||||
ports << CurrentConfig.kernelConfig.statsPort;
|
ports << CurrentConfig.kernelConfig.statsPort;
|
||||||
|
@ -8,15 +8,15 @@ char *fakeArgv[]{};
|
|||||||
|
|
||||||
class QvTestApplication
|
class QvTestApplication
|
||||||
: public QCoreApplication
|
: public QCoreApplication
|
||||||
, public Qv2rayApplicationManager
|
, public Qv2rayApplicationInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit QvTestApplication() : QCoreApplication(fakeArgc, fakeArgv), Qv2rayApplicationManager(){};
|
explicit QvTestApplication() : QCoreApplication(fakeArgc, fakeArgv), Qv2rayApplicationInterface(){};
|
||||||
virtual Qv2raySetupStatus Initialize() override
|
virtual bool Initialize() override
|
||||||
{
|
{
|
||||||
return {};
|
return true;
|
||||||
};
|
};
|
||||||
virtual Qv2rayExitCode RunQv2ray() override
|
virtual Qv2rayExitReason RunQv2ray() override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user