add: added new version auto restart

This commit is contained in:
Qv2ray-dev 2020-06-19 14:00:39 +08:00
parent 601bb116f3
commit b7d7079ea6
5 changed files with 119 additions and 69 deletions

View File

@ -1 +1 @@
5619 5620

View File

@ -1,5 +1,6 @@
#include "Qv2rayApplication.hpp" #include "Qv2rayApplication.hpp"
#include "3rdparty/libsemver/version.hpp"
#include "base/Qv2rayBase.hpp" #include "base/Qv2rayBase.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "common/QvTranslator.hpp" #include "common/QvTranslator.hpp"
@ -23,13 +24,12 @@ namespace Qv2ray
Qv2rayApplication::Qv2rayApplication(int &argc, char *argv[]) Qv2rayApplication::Qv2rayApplication(int &argc, char *argv[])
: SingleApplication(argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion) : SingleApplication(argc, argv, true, User | ExcludeAppPath | ExcludeAppVersion)
{ {
LOG(MODULE_INIT, "Qv2ray Start Time: " + QSTRN(QTime::currentTime().msecsSinceStartOfDay()))
LOG(MODULE_INIT, "Qv2ray " QV2RAY_VERSION_STRING " on " + QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture()) 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_INFO", QV2RAY_BUILD_INFO)
DEBUG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO) DEBUG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
DEBUG("QV2RAY_BUILD_NUMBER", QSTRN(QV2RAY_VERSION_BUILD)) DEBUG("QV2RAY_BUILD_NUMBER", QSTRN(QV2RAY_VERSION_BUILD))
// hTray = new QSystemTrayIcon();
hTray = new QSystemTrayIcon(this);
} }
bool Qv2rayApplication::SetupQv2ray() bool Qv2rayApplication::SetupQv2ray()
@ -37,6 +37,7 @@ namespace Qv2ray
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
SetCurrentDirectory(applicationDirPath().toStdWString().c_str()); SetCurrentDirectory(applicationDirPath().toStdWString().c_str());
#endif #endif
// Install a default translater. From the OS/DE // Install a default translater. From the OS/DE
Qv2rayTranslator = std::make_unique<QvTranslator>(); Qv2rayTranslator = std::make_unique<QvTranslator>();
const auto &systemLang = QLocale::system().name(); const auto &systemLang = QLocale::system().name();
@ -45,19 +46,72 @@ namespace Qv2ray
// //
setQuitOnLastWindowClosed(false); setQuitOnLastWindowClosed(false);
connect(this, &SingleApplication::receivedMessage, this, &Qv2rayApplication::onMessageReceived); connect(this, &SingleApplication::receivedMessage, this, &Qv2rayApplication::onMessageReceived);
connect(this, &SingleApplication::aboutToQuit, this, &Qv2rayApplication::aboutToQuitSlot);
if (isSecondary()) if (isSecondary())
{ {
sendMessage(JsonToString(Qv2rayProcessArgument.toJson(), QJsonDocument::Compact).toUtf8()); sendMessage(JsonToString(Qv2rayProcessArgument.toJson(), QJsonDocument::Compact).toUtf8());
return false; return false;
} }
#ifdef Q_OS_WIN
// Set special font in Windows
QFont font;
font.setPointSize(9);
font.setFamily("Microsoft YaHei");
app.application->setFont(font);
#endif
#ifdef Q_OS_LINUX
setFallbackSessionManagementEnabled(false);
connect(this, &QGuiApplication::commitDataRequest, [] {
ConnectionManager->SaveConnectionConfig();
LOG(MODULE_INIT, "Quit triggered by session manager.")
});
#endif
return true; return true;
} }
void Qv2rayApplication::aboutToQuitSlot()
{
delete mainWindow;
delete hTray;
delete ConnectionManager;
delete RouteManager;
delete PluginHost;
delete StyleManager;
}
void Qv2rayApplication::onMessageReceived(quint32 clientId, QByteArray _msg) void Qv2rayApplication::onMessageReceived(quint32 clientId, QByteArray _msg)
{ {
const auto msg = Qv2rayProcessArguments::fromJson(JsonFromString(_msg)); const auto msg = Qv2rayProcessArguments::fromJson(JsonFromString(_msg));
LOG(MODULE_INIT, "Client ID: " + QSTRN(clientId) + ", message received, version: " + msg.version) LOG(MODULE_INIT, "Client ID: " + QSTRN(clientId) + ", message received, version: " + msg.version)
DEBUG(MODULE_INIT, _msg) DEBUG(MODULE_INIT, _msg)
//
const auto currentVersion = semver::version::from_string(QV2RAY_VERSION_STRING);
const auto newVersion = semver::version::from_string(msg.version.toStdString());
//
if (newVersion > currentVersion)
{
QTimer::singleShot(0, [=]() {
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;
ExitQv2ray(QV2RAY_EXITCODE_NEWVERSION);
}
});
}
for (const auto &argument : msg.arguments) for (const auto &argument : msg.arguments)
{ {
switch (argument) switch (argument)
@ -112,7 +166,15 @@ namespace Qv2ray
{ {
// Show MainWindow // Show MainWindow
mainWindow = new MainWindow(); mainWindow = new MainWindow();
return exec(); exec();
if (Qv2rayProcessArgument._qvNewVersionPath.isEmpty())
{
return 0;
}
else
{
return QV2RAY_EXITCODE_NEWVERSION;
}
} }
bool Qv2rayApplication::FindAndCreateInitialConfiguration() bool Qv2rayApplication::FindAndCreateInitialConfiguration()
@ -318,15 +380,6 @@ namespace Qv2ray
StyleManager->ApplyStyle(GlobalConfig.uiConfig.theme); StyleManager->ApplyStyle(GlobalConfig.uiConfig.theme);
} }
void Qv2rayApplication::DeallocateGlobalVariables()
{
delete mainWindow;
delete ConnectionManager;
delete RouteManager;
delete PluginHost;
delete StyleManager;
}
bool Qv2rayApplication::PreInitilize(int argc, char *argv[]) bool Qv2rayApplication::PreInitilize(int argc, char *argv[])
{ {
QString errorMessage; QString errorMessage;
@ -336,15 +389,15 @@ namespace Qv2ray
const auto &args = coreApp.arguments(); const auto &args = coreApp.arguments();
Qv2rayProcessArgument.version = QV2RAY_VERSION_STRING; Qv2rayProcessArgument.version = QV2RAY_VERSION_STRING;
Qv2rayProcessArgument.fullArgs = args; Qv2rayProcessArgument.fullArgs = args;
switch (ParseCommandLine(&errorMessage)) switch (ParseCommandLine(&errorMessage, args))
{ {
case QV2RAY_QUIT: return false; case QV2RAY_QUIT: return false;
case QV2RAY_ERROR: LOG(MODULE_INIT, errorMessage) return false; case QV2RAY_ERROR: LOG(MODULE_INIT, errorMessage) return false;
default: break; default: break;
} }
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
const auto urlScheme = applicationName(); const auto urlScheme = coreApp.applicationName();
const auto appPath = QDir::toNativeSeparators(applicationFilePath()); const auto appPath = QDir::toNativeSeparators(coreApp.applicationFilePath());
const auto regPath = "HKEY_CURRENT_USER\\Software\\Classes\\" + urlScheme; const auto regPath = "HKEY_CURRENT_USER\\Software\\Classes\\" + urlScheme;
QSettings reg(regPath, QSettings::NativeFormat); QSettings reg(regPath, QSettings::NativeFormat);
@ -381,7 +434,7 @@ namespace Qv2ray
return true; return true;
} }
Qv2rayApplication::commandline_status Qv2rayApplication::ParseCommandLine(QString *errorMessage) Qv2rayApplication::commandline_status Qv2rayApplication::ParseCommandLine(QString *errorMessage, const QStringList &args)
{ {
QCommandLineParser parser; QCommandLineParser parser;
// //
@ -407,7 +460,7 @@ namespace Qv2ray
auto helpOption = parser.addHelpOption(); auto helpOption = parser.addHelpOption();
auto versionOption = parser.addVersionOption(); auto versionOption = parser.addVersionOption();
if (!parser.parse(arguments())) if (!parser.parse(args))
{ {
*errorMessage = parser.errorText(); *errorMessage = parser.errorText();
return QV2RAY_ERROR; return QV2RAY_ERROR;

View File

@ -24,7 +24,9 @@ namespace Qv2ray
QString data; QString data;
QList<QString> links; QList<QString> links;
QList<QString> fullArgs; QList<QString> fullArgs;
//
int _exitCode;
QString _qvNewVersionPath;
JSONSTRUCT_REGISTER(Qv2rayProcessArguments, F(arguments, version, data, links, fullArgs)) JSONSTRUCT_REGISTER(Qv2rayProcessArguments, F(arguments, version, data, links, fullArgs))
}; };
@ -48,7 +50,6 @@ namespace Qv2ray
bool LoadConfiguration(); bool LoadConfiguration();
void InitilizeGlobalVariables(); void InitilizeGlobalVariables();
int RunQv2ray(); int RunQv2ray();
void DeallocateGlobalVariables();
public: public:
QSystemTrayIcon **GetTrayIcon() QSystemTrayIcon **GetTrayIcon()
@ -65,12 +66,13 @@ namespace Qv2ray
} }
private slots: private slots:
void aboutToQuitSlot();
void onMessageReceived(quint32 clientID, QByteArray msg); void onMessageReceived(quint32 clientID, QByteArray msg);
private: private:
QSystemTrayIcon *hTray; QSystemTrayIcon *hTray;
MainWindow *mainWindow; MainWindow *mainWindow;
static commandline_status ParseCommandLine(QString *errorMessage); static commandline_status ParseCommandLine(QString *errorMessage, const QStringList &args);
bool initilized = false; bool initilized = false;
}; };
} // namespace Qv2ray } // namespace Qv2ray

View File

@ -112,15 +112,17 @@ using namespace Qv2ray::base::objects::transfer;
namespace Qv2ray namespace Qv2ray
{ {
constexpr auto QV2RAY_EXITCODE_NORMAL = 0;
constexpr auto QV2RAY_EXITCODE_NEWVERSION = -9;
// Qv2ray runtime config // Qv2ray runtime config
inline bool isExiting = false; inline bool isExiting = false;
inline QString Qv2rayConfigPath = ""; inline QString Qv2rayConfigPath = "";
inline base::config::Qv2rayConfigObject GlobalConfig = base::config::Qv2rayConfigObject(); inline base::config::Qv2rayConfigObject GlobalConfig = base::config::Qv2rayConfigObject();
// //
inline void ExitQv2ray() inline void ExitQv2ray(int retcode = QV2RAY_EXITCODE_NORMAL)
{ {
isExiting = true; isExiting = true;
QCoreApplication::quit(); QCoreApplication::exit(retcode);
} }
inline QStringList Qv2rayAssetsPaths(const QString &dirName) inline QStringList Qv2rayAssetsPaths(const QString &dirName)

View File

@ -1,14 +1,11 @@
#include "Qv2rayApplication.hpp" #include "Qv2rayApplication.hpp"
#include "common/QvHelpers.hpp" #include "common/QvHelpers.hpp"
#include "core/handler/ConfigHandler.hpp" #include "core/handler/ConfigHandler.hpp"
#include "core/settings/SettingsBackend.hpp"
#include <QApplication>
#include <QFileInfo> #include <QFileInfo>
#include <QLocale> #include <QLocale>
#include <QObject> #include <QProcess>
#include <QSslSocket> #include <QSslSocket>
#include <QStandardPaths>
#include <csignal> #include <csignal>
#include <memory> #include <memory>
@ -19,32 +16,8 @@ void signalHandler(int signum)
qvApp->exit(-99); qvApp->exit(-99);
} }
int main(int argc, char *argv[]) int RunQv2rayApplicationScoped(int argc, char *argv[])
{ {
#ifndef Q_OS_WIN
// Register signal handlers.
signal(SIGINT, signalHandler);
signal(SIGHUP, signalHandler);
signal(SIGKILL, signalHandler);
signal(SIGTERM, signalHandler);
#endif
//
// This line must be called before any other ones, since we are using these
// values to identify instances.
Qv2rayApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
//
#ifdef QT_DEBUG
Qv2rayApplication::setApplicationName("qv2ray_debug");
Qv2rayApplication::setApplicationDisplayName("Qv2ray - " + QObject::tr("Debug version"));
#else
Qv2rayApplication::setApplicationName("qv2ray");
Qv2rayApplication::setApplicationDisplayName("Qv2ray");
#endif
//
// parse the command line before starting as a Qt application
if (!Qv2rayApplication::PreInitilize(argc, argv))
return -1;
Qv2rayApplication app(argc, argv); Qv2rayApplication app(argc, argv);
if (!app.SetupQv2ray()) if (!app.SetupQv2ray())
@ -108,27 +81,47 @@ int main(int argc, char *argv[])
app.InitilizeGlobalVariables(); app.InitilizeGlobalVariables();
#ifdef Q_OS_WIN
// Set special font in Windows
QFont font;
font.setPointSize(9);
font.setFamily("Microsoft YaHei");
app.setFont(font);
#endif
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
signal(SIGUSR1, [](int) { ConnectionManager->RestartConnection(); }); signal(SIGUSR1, [](int) { ConnectionManager->RestartConnection(); });
signal(SIGUSR2, [](int) { ConnectionManager->StopConnection(); }); signal(SIGUSR2, [](int) { ConnectionManager->StopConnection(); });
#endif #endif
return app.RunQv2ray();
}
#ifdef Q_OS_LINUX int main(int argc, char *argv[])
qvApp->setFallbackSessionManagementEnabled(false); {
QObject::connect(qvApp, &QGuiApplication::commitDataRequest, [] { #ifndef Q_OS_WIN
ConnectionManager->SaveConnectionConfig(); // Register signal handlers.
LOG(MODULE_INIT, "Quit triggered by session manager.") signal(SIGINT, signalHandler);
}); signal(SIGHUP, signalHandler);
signal(SIGKILL, signalHandler);
signal(SIGTERM, signalHandler);
#endif #endif
auto rcode = app.RunQv2ray(); //
app.DeallocateGlobalVariables(); // This line must be called before any other ones, since we are using these
// values to identify instances.
QApplication::setApplicationVersion(QV2RAY_VERSION_STRING);
//
#ifdef QT_DEBUG
QApplication::setApplicationName("qv2ray_debug");
QApplication::setApplicationDisplayName("Qv2ray - " + QObject::tr("Debug version"));
#else
QApplication::setApplicationName("qv2ray");
QApplication::setApplicationDisplayName("Qv2ray");
#endif
//
// parse the command line before starting as a Qt application
if (!Qv2rayApplication::PreInitilize(argc, argv))
return -1;
const auto rcode = RunQv2rayApplicationScoped(argc, argv);
switch (rcode)
{
case QV2RAY_EXITCODE_NEWVERSION:
{
QProcess::startDetached(Qv2rayProcessArgument._qvNewVersionPath, {});
break;
}
default: break;
}
return rcode; return rcode;
} }