mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-24 02:00:24 +07:00
feat: msi installer and cli command (#2020)
* feat: Add msi quite installer * chore: update code for new wix * feat: add cpack wix installer * feat: add gihub workflow for msi * chore: fix deploy script * chore: add wix logs * chore: fix msi build * chore: fix msi build * chore: add wix exts log * chore: add cpackwixpatch for registering the service * chore: fix build script * chore: fix wix fragment * feat: add closing app with reinstalling * chore: update version for test * chore: fix build script * feat: added cli commands --connect and --import (#1967) * fix: delete unused file and disable rollback after unsuccessful service start in msi installer * fix: Add deps to msi * fix: msi deps * feat: added os signal handler * fix: incorrect import at the empty client start (#2024) * chore: add force quit for os signal handler * feat: os signal handler improvements * fix: fixed --connection command --------- Co-authored-by: Mykola Baibuz <mykola.baibuz@gmail.com> Co-authored-by: aiamnezia <ai@amnezia.org> Co-authored-by: Mitternacht822 <sb@amnezia.org>
This commit is contained in:
@@ -139,12 +139,28 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
arch: 'x64'
|
arch: 'x64'
|
||||||
|
|
||||||
|
- name: 'Setup .NET SDK'
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: 'Install WiX Toolset'
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
dotnet tool install --global wix --version 4.0.6
|
||||||
|
wix extension add -g WixToolset.UI.wixext/4.0.6
|
||||||
|
wix extension add -g WixToolset.Util.wixext/4.0.6
|
||||||
|
wix extension list -g
|
||||||
|
$wixBinDir = Join-Path $env:USERPROFILE ".dotnet\tools"
|
||||||
|
echo "WIX_BIN_DIR=$wixBinDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||||
|
|
||||||
- name: 'Build project'
|
- name: 'Build project'
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
set BUILD_ARCH=${{ env.BUILD_ARCH }}
|
set BUILD_ARCH=${{ env.BUILD_ARCH }}
|
||||||
set QT_BIN_DIR="${{ runner.temp }}\\Qt\\${{ env.QT_VERSION }}\\msvc2019_64\\bin"
|
set QT_BIN_DIR="${{ runner.temp }}\\Qt\\${{ env.QT_VERSION }}\\msvc2019_64\\bin"
|
||||||
set QIF_BIN_DIR="${{ runner.temp }}\\Qt\\Tools\\QtInstallerFramework\\${{ env.QIF_VERSION }}\\bin"
|
set QIF_BIN_DIR="${{ runner.temp }}\\Qt\\Tools\\QtInstallerFramework\\${{ env.QIF_VERSION }}\\bin"
|
||||||
|
set WIX_BIN_DIR=%USERPROFILE%\.dotnet\tools
|
||||||
call deploy\\build_windows.bat
|
call deploy\\build_windows.bat
|
||||||
|
|
||||||
- name: 'Rename Windows installer'
|
- name: 'Rename Windows installer'
|
||||||
@@ -159,6 +175,13 @@ jobs:
|
|||||||
path: AmneziaVPN_${{ env.VERSION }}_x64.exe
|
path: AmneziaVPN_${{ env.VERSION }}_x64.exe
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
- name: 'Upload MSI installer artifact'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: AmneziaVPN_Windows_MSI_installer
|
||||||
|
path: AmneziaVPN_x${{ env.BUILD_ARCH }}.msi
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
- name: 'Upload unpacked artifact'
|
- name: 'Upload unpacked artifact'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -49,3 +49,36 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
|||||||
|
|
||||||
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(AMNEZIA_STAGE_DIR "${CMAKE_BINARY_DIR}/stage")
|
||||||
|
|
||||||
|
if(WIN32 AND NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||||
|
file(TO_CMAKE_PATH "${AMNEZIA_STAGE_DIR}" AMNEZIA_STAGE_DIR_CMAKE)
|
||||||
|
|
||||||
|
set(CPACK_GENERATOR "WIX")
|
||||||
|
set(CPACK_WIX_VERSION 4)
|
||||||
|
set(CPACK_PACKAGE_NAME "AmneziaVPN")
|
||||||
|
set(CPACK_PACKAGE_VENDOR "AmneziaVPN")
|
||||||
|
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "AmneziaVPN client")
|
||||||
|
set(CPACK_PACKAGE_INSTALL_DIRECTORY "AmneziaVPN")
|
||||||
|
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||||
|
set(CPACK_PACKAGE_EXECUTABLES "AmneziaVPN" "AmneziaVPN")
|
||||||
|
set(CPACK_WIX_UPGRADE_GUID "{2D55AC62-96D6-4692-8C05-0D85BBF95485}")
|
||||||
|
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/client/images/app.ico")
|
||||||
|
|
||||||
|
# WiX patches
|
||||||
|
set(_AMNEZIA_WIX_PATCH_SERVICE "${CMAKE_SOURCE_DIR}/deploy/installer/wix/service_install_patch.xml")
|
||||||
|
set(_AMNEZIA_WIX_PATCH_CLOSE_APP "${CMAKE_SOURCE_DIR}/deploy/installer/wix/close_client_patch.xml")
|
||||||
|
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_SERVICE}" _AMNEZIA_WIX_PATCH_SERVICE_CMAKE)
|
||||||
|
file(TO_CMAKE_PATH "${_AMNEZIA_WIX_PATCH_CLOSE_APP}" _AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE)
|
||||||
|
set(CPACK_WIX_PATCH_FILE "${_AMNEZIA_WIX_PATCH_SERVICE_CMAKE};${_AMNEZIA_WIX_PATCH_CLOSE_APP_CMAKE}")
|
||||||
|
|
||||||
|
# WiX v4 Util extension for CloseApplication + namespace for util
|
||||||
|
set(CPACK_WIX_EXTENSIONS "${CPACK_WIX_EXTENSIONS};WixToolset.Util.wixext")
|
||||||
|
set(CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util")
|
||||||
|
|
||||||
|
set(CPACK_INSTALLED_DIRECTORIES "${AMNEZIA_STAGE_DIR_CMAKE};/")
|
||||||
|
|
||||||
|
include(CPack)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -27,9 +27,13 @@
|
|||||||
#include <QtQuick/QQuickWindow> // for QQuickWindow
|
#include <QtQuick/QQuickWindow> // for QQuickWindow
|
||||||
#include <QWindow> // for qobject_cast<QWindow*>
|
#include <QWindow> // for qobject_cast<QWindow*>
|
||||||
|
|
||||||
|
bool AmneziaApplication::m_forceQuit = false;
|
||||||
|
|
||||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv),
|
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv),
|
||||||
m_optAutostart({QStringLiteral("a"), QStringLiteral("autostart")}, QStringLiteral("System autostart")),
|
m_optAutostart({QStringLiteral("a"), QStringLiteral("autostart")}, QStringLiteral("System autostart")),
|
||||||
m_optCleanup ({QStringLiteral("c"), QStringLiteral("cleanup")}, QStringLiteral("Cleanup logs"))
|
m_optCleanup ({QStringLiteral("c"), QStringLiteral("cleanup")}, QStringLiteral("Cleanup logs")),
|
||||||
|
m_optConnect ({QStringLiteral("connect")}, QStringLiteral("Connect to server by index on startup"), QStringLiteral("index")),
|
||||||
|
m_optImport ({QStringLiteral("import")}, QStringLiteral("Import configuration from data string"), QStringLiteral("data"))
|
||||||
{
|
{
|
||||||
setQuitOnLastWindowClosed(false);
|
setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
@@ -126,6 +130,16 @@ void AmneziaApplication::init()
|
|||||||
m_coreController.reset(new CoreController(m_vpnConnection, m_settings, m_engine));
|
m_coreController.reset(new CoreController(m_vpnConnection, m_settings, m_engine));
|
||||||
|
|
||||||
m_engine->addImportPath("qrc:/ui/qml/Modules/");
|
m_engine->addImportPath("qrc:/ui/qml/Modules/");
|
||||||
|
|
||||||
|
if (m_parser.isSet(m_optImport)) {
|
||||||
|
const QString data = m_parser.value(m_optImport);
|
||||||
|
if (!data.isEmpty()) {
|
||||||
|
if (m_coreController) {
|
||||||
|
m_coreController->importConfigFromData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_engine->load(url);
|
m_engine->load(url);
|
||||||
|
|
||||||
m_coreController->setQmlRoot();
|
m_coreController->setQmlRoot();
|
||||||
@@ -165,6 +179,18 @@ void AmneziaApplication::init()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (m_parser.isSet(m_optConnect)) {
|
||||||
|
bool ok = false;
|
||||||
|
int idx = m_parser.value(m_optConnect).toInt(&ok);
|
||||||
|
if (ok) {
|
||||||
|
QTimer::singleShot(0, this, [this, idx]() {
|
||||||
|
if (m_coreController) {
|
||||||
|
m_coreController->openConnectionByIndex(idx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmneziaApplication::registerTypes()
|
void AmneziaApplication::registerTypes()
|
||||||
@@ -211,6 +237,8 @@ bool AmneziaApplication::parseCommands()
|
|||||||
|
|
||||||
m_parser.addOption(m_optAutostart);
|
m_parser.addOption(m_optAutostart);
|
||||||
m_parser.addOption(m_optCleanup);
|
m_parser.addOption(m_optCleanup);
|
||||||
|
m_parser.addOption(m_optConnect);
|
||||||
|
m_parser.addOption(m_optImport);
|
||||||
|
|
||||||
m_parser.process(*this);
|
m_parser.process(*this);
|
||||||
|
|
||||||
@@ -247,8 +275,12 @@ bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event)
|
|||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
quit();
|
quit();
|
||||||
#else
|
#else
|
||||||
if (m_coreController && m_coreController->pageController()) {
|
if (m_forceQuit) {
|
||||||
m_coreController->pageController()->hideMainWindow();
|
quit();
|
||||||
|
} else {
|
||||||
|
if (m_coreController && m_coreController->pageController()) {
|
||||||
|
m_coreController->pageController()->hideMainWindow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true; // eat the close
|
return true; // eat the close
|
||||||
@@ -257,6 +289,12 @@ bool AmneziaApplication::eventFilter(QObject *watched, QEvent *event)
|
|||||||
return QObject::eventFilter(watched, event);
|
return QObject::eventFilter(watched, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AmneziaApplication::forceQuit()
|
||||||
|
{
|
||||||
|
m_forceQuit = true;
|
||||||
|
quit();
|
||||||
|
}
|
||||||
|
|
||||||
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
||||||
{
|
{
|
||||||
return m_engine;
|
return m_engine;
|
||||||
|
|||||||
@@ -45,7 +45,11 @@ public:
|
|||||||
QNetworkAccessManager *networkManager();
|
QNetworkAccessManager *networkManager();
|
||||||
QClipboard *getClipboard();
|
QClipboard *getClipboard();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void forceQuit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool m_forceQuit;
|
||||||
QQmlApplicationEngine *m_engine {};
|
QQmlApplicationEngine *m_engine {};
|
||||||
std::shared_ptr<Settings> m_settings;
|
std::shared_ptr<Settings> m_settings;
|
||||||
|
|
||||||
@@ -58,6 +62,8 @@ private:
|
|||||||
|
|
||||||
QCommandLineOption m_optAutostart;
|
QCommandLineOption m_optAutostart;
|
||||||
QCommandLineOption m_optCleanup;
|
QCommandLineOption m_optCleanup;
|
||||||
|
QCommandLineOption m_optConnect;
|
||||||
|
QCommandLineOption m_optImport;
|
||||||
|
|
||||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||||
QThread m_vpnConnectionThread;
|
QThread m_vpnConnectionThread;
|
||||||
|
|||||||
@@ -411,3 +411,22 @@ QSharedPointer<PageController> CoreController::pageController() const
|
|||||||
{
|
{
|
||||||
return m_pageController;
|
return m_pageController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CoreController::openConnectionByIndex(int serverIndex)
|
||||||
|
{
|
||||||
|
if (m_serversModel) {
|
||||||
|
m_serversModel->setProcessedServerIndex(serverIndex);
|
||||||
|
m_serversModel->setDefaultServerIndex(serverIndex);
|
||||||
|
}
|
||||||
|
m_connectionController->toggleConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreController::importConfigFromData(const QString &data)
|
||||||
|
{
|
||||||
|
if (!m_importController)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_importController->extractConfigFromData(data)) {
|
||||||
|
m_importController->importConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ public:
|
|||||||
QSharedPointer<PageController> pageController() const;
|
QSharedPointer<PageController> pageController() const;
|
||||||
void setQmlRoot();
|
void setQmlRoot();
|
||||||
|
|
||||||
|
void openConnectionByIndex(int serverIndex);
|
||||||
|
void importConfigFromData(const QString &data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void translationsUpdated();
|
void translationsUpdated();
|
||||||
void websiteUrlChanged(const QString &newUrl);
|
void websiteUrlChanged(const QString &newUrl);
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#include "osSignalHandler.h"
|
#include "osSignalHandler.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QMetaObject>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
|
|
||||||
|
#include "../amnezia_application.h"
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -15,7 +18,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <QMetaObject>
|
#include <QAbstractNativeEventFilter>
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -25,21 +29,30 @@ namespace
|
|||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
static BOOL WINAPI consoleHandler(DWORD signal)
|
class WindowsCloseFilter : public QAbstractNativeEventFilter
|
||||||
{
|
{
|
||||||
switch (signal) {
|
public:
|
||||||
case CTRL_CLOSE_EVENT:
|
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override
|
||||||
case CTRL_C_EVENT:
|
{
|
||||||
case CTRL_BREAK_EVENT:
|
MSG *msg = static_cast<MSG *>(message);
|
||||||
case CTRL_LOGOFF_EVENT:
|
|
||||||
case CTRL_SHUTDOWN_EVENT:
|
switch (msg->message) {
|
||||||
if (QCoreApplication::instance()) {
|
case WM_CLOSE: {
|
||||||
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
|
const HWND active = GetActiveWindow();
|
||||||
|
const HWND self = msg->hwnd;
|
||||||
|
if (active != self) {
|
||||||
|
AmneziaApplication *app = qobject_cast<AmneziaApplication *>(QCoreApplication::instance());
|
||||||
|
if (app) {
|
||||||
|
QMetaObject::invokeMethod(app, "forceQuit", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
}
|
||||||
default: return FALSE;
|
return false;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
|
static WindowsCloseFilter *windowsFilter = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
@@ -70,14 +83,16 @@ namespace
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#elif defined(Q_OS_MACX)
|
#elif defined(Q_OS_MACOS)
|
||||||
static int signalPipe[2] = { -1, -1 };
|
static int signalPipe[2] = { -1, -1 };
|
||||||
static QSocketNotifier *socketNotifier = nullptr;
|
static QSocketNotifier *socketNotifier = nullptr;
|
||||||
|
|
||||||
static void macSignalHandler(int)
|
static void macSignalHandler(int)
|
||||||
{
|
{
|
||||||
const char ch = 1;
|
if (signalPipe[1] >= 0) {
|
||||||
::write(signalPipe[1], &ch, sizeof(ch));
|
const char ch = 1;
|
||||||
|
::write(signalPipe[1], &ch, sizeof(ch));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupUnixSignalHandler()
|
static void setupUnixSignalHandler()
|
||||||
@@ -88,14 +103,6 @@ namespace
|
|||||||
::fcntl(signalPipe[0], F_SETFL, O_NONBLOCK);
|
::fcntl(signalPipe[0], F_SETFL, O_NONBLOCK);
|
||||||
::fcntl(signalPipe[1], F_SETFL, O_NONBLOCK);
|
::fcntl(signalPipe[1], F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
struct sigaction sa {};
|
|
||||||
sa.sa_handler = macSignalHandler;
|
|
||||||
sigemptyset(&sa.sa_mask);
|
|
||||||
sa.sa_flags = 0;
|
|
||||||
|
|
||||||
sigaction(SIGINT, &sa, nullptr);
|
|
||||||
sigaction(SIGTERM, &sa, nullptr);
|
|
||||||
|
|
||||||
socketNotifier = new QSocketNotifier(signalPipe[0], QSocketNotifier::Read, QCoreApplication::instance());
|
socketNotifier = new QSocketNotifier(signalPipe[0], QSocketNotifier::Read, QCoreApplication::instance());
|
||||||
|
|
||||||
QObject::connect(socketNotifier, &QSocketNotifier::activated, QCoreApplication::instance(), [](int) {
|
QObject::connect(socketNotifier, &QSocketNotifier::activated, QCoreApplication::instance(), [](int) {
|
||||||
@@ -103,6 +110,14 @@ namespace
|
|||||||
::read(signalPipe[0], buf, sizeof(buf));
|
::read(signalPipe[0], buf, sizeof(buf));
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct sigaction sa {};
|
||||||
|
sa.sa_handler = macSignalHandler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
|
||||||
|
sigaction(SIGINT, &sa, nullptr);
|
||||||
|
sigaction(SIGTERM, &sa, nullptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -111,6 +126,8 @@ namespace
|
|||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
if (socketNotifier) {
|
if (socketNotifier) {
|
||||||
socketNotifier->setEnabled(false);
|
socketNotifier->setEnabled(false);
|
||||||
|
socketNotifier->deleteLater();
|
||||||
|
socketNotifier = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signalFd >= 0) {
|
if (signalFd >= 0) {
|
||||||
@@ -119,8 +136,17 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(Q_OS_MACOS)
|
#elif defined(Q_OS_MACOS)
|
||||||
|
struct sigaction sa {};
|
||||||
|
sa.sa_handler = SIG_DFL;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigaction(SIGINT, &sa, nullptr);
|
||||||
|
sigaction(SIGTERM, &sa, nullptr);
|
||||||
|
|
||||||
if (socketNotifier) {
|
if (socketNotifier) {
|
||||||
socketNotifier->setEnabled(false);
|
socketNotifier->setEnabled(false);
|
||||||
|
socketNotifier->deleteLater();
|
||||||
|
socketNotifier = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signalPipe[0] >= 0) {
|
if (signalPipe[0] >= 0) {
|
||||||
@@ -133,6 +159,14 @@ namespace
|
|||||||
signalPipe[1] = -1;
|
signalPipe[1] = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if (windowsFilter) {
|
||||||
|
QCoreApplication::instance()->removeNativeEventFilter(windowsFilter);
|
||||||
|
delete windowsFilter;
|
||||||
|
windowsFilter = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,12 +181,13 @@ void OsSignalHandler::setup()
|
|||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MACX)
|
#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MACOS)
|
||||||
setupUnixSignalHandler();
|
setupUnixSignalHandler();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
SetConsoleCtrlHandler(consoleHandler, TRUE);
|
windowsFilter = new WindowsCloseFilter();
|
||||||
|
QCoreApplication::instance()->installNativeEventFilter(windowsFilter);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [] { cleanupUnixSignalHandler(); });
|
QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [] { cleanupUnixSignalHandler(); });
|
||||||
|
|||||||
@@ -8,6 +8,21 @@ set PATH=%QT_BIN_DIR:"=%;%PATH%
|
|||||||
|
|
||||||
echo "Using Qt in %QT_BIN_DIR%"
|
echo "Using Qt in %QT_BIN_DIR%"
|
||||||
echo "Using QIF in %QIF_BIN_DIR%"
|
echo "Using QIF in %QIF_BIN_DIR%"
|
||||||
|
echo "Using WiX in %WIX_BIN_DIR%"
|
||||||
|
|
||||||
|
if "%WIX_BIN_DIR%"=="" (
|
||||||
|
echo "WIX_BIN_DIR is not set"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
set WIX_BIN_DIR_UNQUOTED=%WIX_BIN_DIR:"=%
|
||||||
|
|
||||||
|
set WIX_CLI=%WIX_BIN_DIR_UNQUOTED%\wix.exe
|
||||||
|
|
||||||
|
if not exist "%WIX_CLI%" (
|
||||||
|
echo "WiX CLI (wix.exe) was not found in %WIX_BIN_DIR%"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
REM Hold on to current directory
|
REM Hold on to current directory
|
||||||
set PROJECT_DIR=%cd%
|
set PROJECT_DIR=%cd%
|
||||||
@@ -22,6 +37,8 @@ set PREBILT_DEPLOY_DATA_DIR=%PROJECT_DIR:"=%\client\3rd-prebuilt\deploy-prebuilt
|
|||||||
set DEPLOY_DATA_DIR=%SCRIPT_DIR:"=%\data\windows\x%BUILD_ARCH:"=%
|
set DEPLOY_DATA_DIR=%SCRIPT_DIR:"=%\data\windows\x%BUILD_ARCH:"=%
|
||||||
set INSTALLER_DATA_DIR=%WORK_DIR:"=%\installer\packages\%APP_DOMAIN:"=%\data
|
set INSTALLER_DATA_DIR=%WORK_DIR:"=%\installer\packages\%APP_DOMAIN:"=%\data
|
||||||
set TARGET_FILENAME=%PROJECT_DIR:"=%\%APP_NAME:"=%_x%BUILD_ARCH:"=%.exe
|
set TARGET_FILENAME=%PROJECT_DIR:"=%\%APP_NAME:"=%_x%BUILD_ARCH:"=%.exe
|
||||||
|
set TARGET_MSI_FILENAME=%PROJECT_DIR:"=%\%APP_NAME:"=%_x%BUILD_ARCH:"=%.msi
|
||||||
|
set STAGE_DIR=%WORK_DIR:"=%\stage
|
||||||
|
|
||||||
echo "Environment:"
|
echo "Environment:"
|
||||||
echo "WORK_DIR: %WORK_DIR%"
|
echo "WORK_DIR: %WORK_DIR%"
|
||||||
@@ -32,10 +49,14 @@ echo "OUT_APP_DIR: %OUT_APP_DIR%"
|
|||||||
echo "DEPLOY_DATA_DIR: %DEPLOY_DATA_DIR%"
|
echo "DEPLOY_DATA_DIR: %DEPLOY_DATA_DIR%"
|
||||||
echo "INSTALLER_DATA_DIR: %INSTALLER_DATA_DIR%"
|
echo "INSTALLER_DATA_DIR: %INSTALLER_DATA_DIR%"
|
||||||
echo "TARGET_FILENAME: %TARGET_FILENAME%"
|
echo "TARGET_FILENAME: %TARGET_FILENAME%"
|
||||||
|
echo "TARGET_MSI_FILENAME: %TARGET_MSI_FILENAME%"
|
||||||
|
echo "STAGE_DIR: %STAGE_DIR%"
|
||||||
|
|
||||||
echo "Cleanup..."
|
echo "Cleanup..."
|
||||||
rmdir /Q /S %WORK_DIR%
|
rmdir /Q /S %WORK_DIR%
|
||||||
del %TARGET_FILENAME%
|
del %TARGET_FILENAME%
|
||||||
|
del %TARGET_MSI_FILENAME%
|
||||||
|
rmdir /Q /S "%STAGE_DIR%"
|
||||||
|
|
||||||
mkdir %WORK_DIR%
|
mkdir %WORK_DIR%
|
||||||
|
|
||||||
@@ -56,6 +77,7 @@ mkdir "%OUT_APP_DIR%"
|
|||||||
copy "%WORK_DIR%\service\server\release\%APP_NAME%-service.exe" "%OUT_APP_DIR%"
|
copy "%WORK_DIR%\service\server\release\%APP_NAME%-service.exe" "%OUT_APP_DIR%"
|
||||||
rem copy "%WORK_DIR%\client\%APP_FILENAME%" "%OUT_APP_DIR%"
|
rem copy "%WORK_DIR%\client\%APP_FILENAME%" "%OUT_APP_DIR%"
|
||||||
|
|
||||||
|
copy /Y "%PROJECT_DIR%\client\images\app.ico" "%OUT_APP_DIR%\AmneziaVPN.ico" >nul
|
||||||
|
|
||||||
echo "Signing exe"
|
echo "Signing exe"
|
||||||
cd %OUT_APP_DIR%
|
cd %OUT_APP_DIR%
|
||||||
@@ -89,5 +111,38 @@ timeout 5
|
|||||||
cd %PROJECT_DIR%
|
cd %PROJECT_DIR%
|
||||||
signtool sign /v /n "Privacy Technologies OU" /fd sha256 /tr http://timestamp.comodoca.com/?td=sha256 /td sha256 "%TARGET_FILENAME%"
|
signtool sign /v /n "Privacy Technologies OU" /fd sha256 /tr http://timestamp.comodoca.com/?td=sha256 /td sha256 "%TARGET_FILENAME%"
|
||||||
|
|
||||||
echo "Finished, see %TARGET_FILENAME%"
|
echo "Preparing staging directory for MSI..."
|
||||||
|
rmdir /Q /S "%STAGE_DIR%"
|
||||||
|
mkdir "%STAGE_DIR%"
|
||||||
|
xcopy "%OUT_APP_DIR%" "%STAGE_DIR%" /s /e /y /i /f >nul
|
||||||
|
|
||||||
|
echo "Building MSI via CPack..."
|
||||||
|
rmdir /Q /S "%WORK_DIR%\_CPack_Packages"
|
||||||
|
cd %WORK_DIR%
|
||||||
|
cpack -G WIX -C Release --config "%WORK_DIR%\CPackConfig.cmake"
|
||||||
|
if exist "%WORK_DIR%\_CPack_Packages\win64\WIX\wix.log" (
|
||||||
|
echo ---------------------------------------------
|
||||||
|
echo Contents of wix.log:
|
||||||
|
type "%WORK_DIR%\_CPack_Packages\win64\WIX\wix.log"
|
||||||
|
echo ---------------------------------------------
|
||||||
|
)
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
|
set GENERATED_MSI=
|
||||||
|
for /f "delims=" %%i in ('dir /b /a:-d /o:-d "%WORK_DIR%\*.msi"') do (
|
||||||
|
if not defined GENERATED_MSI set GENERATED_MSI=%WORK_DIR%\%%i
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%GENERATED_MSI%"=="" (
|
||||||
|
echo "Failed to locate generated MSI package"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
copy /Y "%GENERATED_MSI%" "%TARGET_MSI_FILENAME%"
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
||||||
|
cd %PROJECT_DIR%
|
||||||
|
signtool sign /v /n "Privacy Technologies OU" /fd sha256 /tr http://timestamp.comodoca.com/?td=sha256 /td sha256 "%TARGET_MSI_FILENAME%"
|
||||||
|
|
||||||
|
echo "Finished, see %TARGET_FILENAME% and %TARGET_MSI_FILENAME%"
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CPackWiXPatch>
|
||||||
|
<CPackWiXFragment Id="#PRODUCT">
|
||||||
|
<!-- Требует расширение WixToolset.Util.wixext и xmlns util -->
|
||||||
|
<util:CloseApplication
|
||||||
|
Id="CloseAmneziaClient"
|
||||||
|
Target="AmneziaVPN.exe"
|
||||||
|
Description="Closing AmneziaVPN client"
|
||||||
|
TerminateProcess="1"
|
||||||
|
RebootPrompt="no" />
|
||||||
|
</CPackWiXFragment>
|
||||||
|
</CPackWiXPatch>
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CPackWiXPatch>
|
||||||
|
<CPackWiXFragment Id="CM_CP_AmneziaVPN_service.exe">
|
||||||
|
<ServiceInstall
|
||||||
|
Id="AmneziaServiceInstall"
|
||||||
|
Name="AmneziaVPN-service"
|
||||||
|
DisplayName="AmneziaVPN Service"
|
||||||
|
Description="Service for AmneziaVPN"
|
||||||
|
Start="auto"
|
||||||
|
Type="ownProcess"
|
||||||
|
ErrorControl="normal"
|
||||||
|
Vital="no">
|
||||||
|
<ServiceDependency Id="BFE" />
|
||||||
|
<ServiceDependency Id="nsi" />
|
||||||
|
</ServiceInstall>
|
||||||
|
<ServiceControl
|
||||||
|
Id="AmneziaServiceControl"
|
||||||
|
Name="AmneziaVPN-service"
|
||||||
|
Start="install"
|
||||||
|
Stop="both"
|
||||||
|
Remove="uninstall"
|
||||||
|
Wait="yes" />
|
||||||
|
</CPackWiXFragment>
|
||||||
|
</CPackWiXPatch>
|
||||||
Reference in New Issue
Block a user