mirror of
https://github.com/tnodir/fort
synced 2024-11-15 08:46:03 +00:00
UI: Service: Add ability to pause/continue client connections
This commit is contained in:
parent
ca4240dfb1
commit
92869ea5a6
@ -104,6 +104,7 @@ SOURCES += \
|
||||
manager/hotkeymanager.cpp \
|
||||
manager/logger.cpp \
|
||||
manager/nativeeventfilter.cpp \
|
||||
manager/servicemanager.cpp \
|
||||
manager/translationmanager.cpp \
|
||||
manager/windowmanager.cpp \
|
||||
model/applistmodel.cpp \
|
||||
@ -163,7 +164,8 @@ SOURCES += \
|
||||
util/osutil.cpp \
|
||||
util/processinfo.cpp \
|
||||
util/regkey.cpp \
|
||||
util/serviceworker.cpp \
|
||||
util/service/servicemanageriface.cpp \
|
||||
util/service/serviceworker.cpp \
|
||||
util/startuputil.cpp \
|
||||
util/stringutil.cpp \
|
||||
util/textareautil.cpp \
|
||||
@ -273,6 +275,7 @@ HEADERS += \
|
||||
manager/hotkeymanager.h \
|
||||
manager/logger.h \
|
||||
manager/nativeeventfilter.h \
|
||||
manager/servicemanager.h \
|
||||
manager/translationmanager.h \
|
||||
manager/windowmanager.h \
|
||||
model/applistmodel.h \
|
||||
@ -335,7 +338,8 @@ HEADERS += \
|
||||
util/osutil.h \
|
||||
util/processinfo.h \
|
||||
util/regkey.h \
|
||||
util/serviceworker.h \
|
||||
util/service/servicemanageriface.h \
|
||||
util/service/serviceworker.h \
|
||||
util/startuputil.h \
|
||||
util/stringutil.h \
|
||||
util/textareautil.h \
|
||||
|
@ -63,7 +63,10 @@ bool ControlManager::listen()
|
||||
{
|
||||
const auto settings = IoC<FortSettings>();
|
||||
|
||||
Q_ASSERT(!m_server);
|
||||
if (m_server) {
|
||||
return m_server->isListening();
|
||||
}
|
||||
|
||||
m_server = new QLocalServer(this);
|
||||
m_server->setMaxPendingConnections(maxClientsCount);
|
||||
m_server->setSocketOptions(
|
||||
@ -79,6 +82,21 @@ bool ControlManager::listen()
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlManager::close()
|
||||
{
|
||||
if (m_server) {
|
||||
m_server->close();
|
||||
m_server = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ControlManager::closeAllClients()
|
||||
{
|
||||
for (ControlWorker *w : m_clients) {
|
||||
w->close();
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlManager::postCommand()
|
||||
{
|
||||
const auto settings = IoC<FortSettings>();
|
||||
@ -124,7 +142,7 @@ void ControlManager::onNewConnection()
|
||||
|
||||
m_clients.append(w);
|
||||
|
||||
qCDebug(LC) << "Client connected:" << w->id();
|
||||
qCDebug(LC) << "Client connected: id:" << w->id() << "count:" << m_clients.size();
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +155,7 @@ void ControlManager::onDisconnected()
|
||||
w->deleteLater();
|
||||
m_clients.removeOne(w);
|
||||
|
||||
qCDebug(LC) << "Client disconnected:" << w->id();
|
||||
qCDebug(LC) << "Client disconnected: id:" << w->id();
|
||||
}
|
||||
|
||||
bool ControlManager::processRequest(Control::Command command, const QVariantList &args)
|
||||
@ -204,13 +222,6 @@ bool ControlManager::processCommandProg(const ProcessCommandArgs &p)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ControlManager::close()
|
||||
{
|
||||
if (m_server) {
|
||||
m_server->close();
|
||||
}
|
||||
}
|
||||
|
||||
QString ControlManager::getServerName(bool isService)
|
||||
{
|
||||
return QLatin1String(APP_BASE) + (isService ? "Svc" : OsUtil::userName()) + "Pipe";
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "control.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QLocalServer)
|
||||
QT_FORWARD_DECLARE_CLASS(QLocalSocket)
|
||||
|
||||
class ControlWorker;
|
||||
|
||||
@ -40,6 +39,10 @@ public:
|
||||
ControlWorker *newServiceClient(QObject *parent = nullptr) const;
|
||||
|
||||
bool listen();
|
||||
void close();
|
||||
|
||||
void closeAllClients();
|
||||
|
||||
bool postCommand();
|
||||
|
||||
private slots:
|
||||
@ -52,8 +55,6 @@ private:
|
||||
bool processCommand(const ProcessCommandArgs &p);
|
||||
bool processCommandProg(const ProcessCommandArgs &p);
|
||||
|
||||
void close();
|
||||
|
||||
static QString getServerName(bool isService = false);
|
||||
|
||||
private:
|
||||
|
@ -156,6 +156,10 @@ bool ControlWorker::reconnectToServer()
|
||||
|
||||
m_isReconnecting = false;
|
||||
|
||||
if (!connectedToServer) {
|
||||
startReconnectTimer();
|
||||
}
|
||||
|
||||
return connectedToServer;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <manager/hotkeymanager.h>
|
||||
#include <manager/logger.h>
|
||||
#include <manager/nativeeventfilter.h>
|
||||
#include <manager/servicemanager.h>
|
||||
#include <manager/translationmanager.h>
|
||||
#include <model/zonelistmodel.h>
|
||||
#include <rpc/appinfomanagerrpc.h>
|
||||
@ -157,6 +158,9 @@ void FortManager::createManagers()
|
||||
|
||||
if (settings->isService()) {
|
||||
windowManager = new WindowManagerFake();
|
||||
|
||||
// For Service only
|
||||
ioc->setService(new ServiceManager());
|
||||
} else {
|
||||
windowManager = new WindowManager();
|
||||
|
||||
|
70
src/ui/manager/servicemanager.cpp
Normal file
70
src/ui/manager/servicemanager.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "servicemanager.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <qt_windows.h>
|
||||
|
||||
#include <control/controlmanager.h>
|
||||
#include <util/ioc/ioccontainer.h>
|
||||
#include <util/startuputil.h>
|
||||
|
||||
namespace {
|
||||
|
||||
const QLoggingCategory LC("manager.serviceManager");
|
||||
|
||||
}
|
||||
|
||||
ServiceManager::ServiceManager(QObject *parent) : QObject(parent) { }
|
||||
|
||||
ServiceManager::~ServiceManager() { }
|
||||
|
||||
void ServiceManager::setUp()
|
||||
{
|
||||
auto controlManager = IoC()->setUpDependency<ControlManager>();
|
||||
|
||||
connect(this, &ServiceManager::pauseRequested, controlManager, [controlManager] {
|
||||
controlManager->close();
|
||||
controlManager->closeAllClients();
|
||||
});
|
||||
connect(this, &ServiceManager::continueRequested, controlManager, &ControlManager::listen);
|
||||
}
|
||||
|
||||
const wchar_t *ServiceManager::serviceName() const
|
||||
{
|
||||
return StartupUtil::serviceName();
|
||||
}
|
||||
|
||||
void ServiceManager::processControl(quint32 code)
|
||||
{
|
||||
DWORD state = SERVICE_RUNNING;
|
||||
|
||||
switch (code) {
|
||||
case SERVICE_CONTROL_PAUSE: {
|
||||
qCDebug(LC) << "Pause due service control";
|
||||
|
||||
emit pauseRequested();
|
||||
|
||||
state = SERVICE_PAUSED;
|
||||
} break;
|
||||
case SERVICE_CONTROL_CONTINUE: {
|
||||
qCDebug(LC) << "Continue due service control";
|
||||
|
||||
emit continueRequested();
|
||||
|
||||
state = SERVICE_RUNNING;
|
||||
} break;
|
||||
case SERVICE_CONTROL_STOP:
|
||||
case SERVICE_CONTROL_SHUTDOWN: {
|
||||
qCDebug(LC) << "Quit due service control";
|
||||
|
||||
qApp->connect(qApp, &QObject::destroyed, [] { reportStatus(SERVICE_STOPPED); });
|
||||
QCoreApplication::quit(); // it's threadsafe
|
||||
|
||||
state = SERVICE_STOP_PENDING;
|
||||
} break;
|
||||
}
|
||||
|
||||
reportStatus(state);
|
||||
}
|
30
src/ui/manager/servicemanager.h
Normal file
30
src/ui/manager/servicemanager.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef SERVICEMANAGER_H
|
||||
#define SERVICEMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <util/classhelpers.h>
|
||||
#include <util/ioc/iocservice.h>
|
||||
#include <util/service/servicemanageriface.h>
|
||||
|
||||
class ServiceManager : public QObject, public ServiceManagerIface, public IocService
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ServiceManager(QObject *parent = nullptr);
|
||||
~ServiceManager() override;
|
||||
CLASS_DELETE_COPY_MOVE(ServiceManager)
|
||||
|
||||
void setUp() override;
|
||||
|
||||
const wchar_t *serviceName() const override;
|
||||
|
||||
void processControl(quint32 code) override;
|
||||
|
||||
signals:
|
||||
void pauseRequested();
|
||||
void continueRequested();
|
||||
};
|
||||
|
||||
#endif // SERVICEMANAGER_H
|
@ -403,7 +403,7 @@ void RpcManager::setupClient()
|
||||
[&] { invokeOnServer(Control::Rpc_RpcManager_initClient); });
|
||||
|
||||
client()->setIsTryReconnect(true);
|
||||
client()->connectToServer();
|
||||
client()->reconnectToServer();
|
||||
}
|
||||
|
||||
void RpcManager::closeClient()
|
||||
|
33
src/ui/util/service/servicemanageriface.cpp
Normal file
33
src/ui/util/service/servicemanageriface.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "servicemanageriface.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <qt_windows.h>
|
||||
|
||||
/* Service global structure */
|
||||
static struct
|
||||
{
|
||||
SERVICE_STATUS_HANDLE hstatus;
|
||||
SERVICE_STATUS status;
|
||||
} g_service;
|
||||
|
||||
void ServiceManagerIface::initialize(qintptr hstatus)
|
||||
{
|
||||
g_service.hstatus = SERVICE_STATUS_HANDLE(hstatus);
|
||||
|
||||
g_service.status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_service.status.dwControlsAccepted =
|
||||
SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
|
||||
g_service.status.dwWin32ExitCode = NO_ERROR;
|
||||
g_service.status.dwServiceSpecificExitCode = 0;
|
||||
g_service.status.dwCheckPoint = 0;
|
||||
g_service.status.dwWaitHint = 3000;
|
||||
|
||||
reportStatus(SERVICE_RUNNING);
|
||||
}
|
||||
|
||||
void ServiceManagerIface::reportStatus(quint32 code)
|
||||
{
|
||||
g_service.status.dwCurrentState = code;
|
||||
|
||||
SetServiceStatus(g_service.hstatus, &g_service.status);
|
||||
}
|
22
src/ui/util/service/servicemanageriface.h
Normal file
22
src/ui/util/service/servicemanageriface.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef SERVICEMANAGERIFACE_H
|
||||
#define SERVICEMANAGERIFACE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class ServiceManagerIface
|
||||
{
|
||||
public:
|
||||
ServiceManagerIface() = default;
|
||||
virtual ~ServiceManagerIface() = default;
|
||||
|
||||
void initialize(qintptr hstatus);
|
||||
|
||||
virtual const wchar_t *serviceName() const = 0;
|
||||
|
||||
virtual void processControl(quint32 code) = 0;
|
||||
|
||||
protected:
|
||||
static void reportStatus(quint32 code);
|
||||
};
|
||||
|
||||
#endif // SERVICEMANAGERIFACE_H
|
50
src/ui/util/service/serviceworker.cpp
Normal file
50
src/ui/util/service/serviceworker.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "serviceworker.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <qt_windows.h>
|
||||
|
||||
#include "servicemanageriface.h"
|
||||
|
||||
namespace {
|
||||
|
||||
ServiceManagerIface *g_manager = nullptr;
|
||||
|
||||
void WINAPI serviceCtrlHandler(DWORD code)
|
||||
{
|
||||
g_manager->processControl(code);
|
||||
}
|
||||
|
||||
void WINAPI serviceMain(DWORD argc, wchar_t *argv[])
|
||||
{
|
||||
Q_UNUSED(argc);
|
||||
Q_UNUSED(argv);
|
||||
|
||||
const SERVICE_STATUS_HANDLE hstatus =
|
||||
RegisterServiceCtrlHandler(g_manager->serviceName(), serviceCtrlHandler);
|
||||
|
||||
if (hstatus) {
|
||||
g_manager->initialize(qintptr(hstatus));
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI serviceStart(void *arg)
|
||||
{
|
||||
Q_UNUSED(arg);
|
||||
|
||||
wchar_t name[2] = { 0 }; // ignored for SERVICE_WIN32_OWN_PROCESS
|
||||
SERVICE_TABLE_ENTRY table[] = { { name, serviceMain }, { nullptr, nullptr } };
|
||||
|
||||
return !StartServiceCtrlDispatcher(table);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ServiceWorker::run(ServiceManagerIface *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
g_manager = manager;
|
||||
|
||||
DWORD id;
|
||||
const HANDLE hThr = CreateThread(nullptr, 8192, serviceStart, nullptr, 0, &id);
|
||||
CloseHandle(hThr);
|
||||
}
|
@ -3,10 +3,12 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class ServiceManagerIface;
|
||||
|
||||
class ServiceWorker
|
||||
{
|
||||
public:
|
||||
static void run();
|
||||
static void run(ServiceManagerIface *manager);
|
||||
};
|
||||
|
||||
#endif // SERVICEWORKER_H
|
@ -1,78 +0,0 @@
|
||||
#include "serviceworker.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <qt_windows.h>
|
||||
|
||||
#include "startuputil.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const QLoggingCategory LC("util.serviceWorker");
|
||||
|
||||
/* Service global structure */
|
||||
static struct
|
||||
{
|
||||
SERVICE_STATUS status;
|
||||
SERVICE_STATUS_HANDLE hstatus;
|
||||
} g_service;
|
||||
|
||||
void reportServiceStatus(DWORD state)
|
||||
{
|
||||
g_service.status.dwCurrentState = state;
|
||||
SetServiceStatus(g_service.hstatus, &g_service.status);
|
||||
}
|
||||
|
||||
void WINAPI serviceCtrlHandler(DWORD code)
|
||||
{
|
||||
switch (code) {
|
||||
case SERVICE_CONTROL_STOP:
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
qCDebug(LC) << "Quit due service control";
|
||||
|
||||
qApp->connect(qApp, &QObject::destroyed, [] { reportServiceStatus(SERVICE_STOPPED); });
|
||||
QCoreApplication::quit(); // it's threadsafe
|
||||
|
||||
reportServiceStatus(SERVICE_STOP_PENDING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WINAPI serviceMain(DWORD argc, wchar_t *argv[])
|
||||
{
|
||||
Q_UNUSED(argc);
|
||||
Q_UNUSED(argv);
|
||||
|
||||
g_service.hstatus = RegisterServiceCtrlHandler(StartupUtil::serviceName(), serviceCtrlHandler);
|
||||
if (g_service.hstatus) {
|
||||
g_service.status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_service.status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
g_service.status.dwWin32ExitCode = NO_ERROR;
|
||||
g_service.status.dwServiceSpecificExitCode = 0;
|
||||
g_service.status.dwCheckPoint = 0;
|
||||
g_service.status.dwWaitHint = 3000;
|
||||
|
||||
reportServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI serviceStart(void *arg)
|
||||
{
|
||||
Q_UNUSED(arg);
|
||||
|
||||
wchar_t name[2] = { 0 }; // ignored for SERVICE_WIN32_OWN_PROCESS
|
||||
SERVICE_TABLE_ENTRY table[] = { { name, serviceMain }, { nullptr, nullptr } };
|
||||
|
||||
return !StartServiceCtrlDispatcher(table);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ServiceWorker::run()
|
||||
{
|
||||
DWORD id;
|
||||
const HANDLE hThr = CreateThread(nullptr, 8192, serviceStart, nullptr, 0, &id);
|
||||
CloseHandle(hThr);
|
||||
}
|
@ -12,9 +12,10 @@
|
||||
#include <fortmanager.h>
|
||||
#include <fortsettings.h>
|
||||
#include <manager/envmanager.h>
|
||||
#include <manager/servicemanager.h>
|
||||
#include <util/fileutil.h>
|
||||
#include <util/ioc/ioccontainer.h>
|
||||
#include <util/serviceworker.h>
|
||||
#include <util/service/serviceworker.h>
|
||||
#include <util/startuputil.h>
|
||||
|
||||
namespace {
|
||||
@ -135,7 +136,7 @@ int main(int argc, char *argv[])
|
||||
fortManager.initialize();
|
||||
|
||||
if (settings.isService()) {
|
||||
ServiceWorker::run();
|
||||
ServiceWorker::run(IoC<ServiceManager>());
|
||||
} else {
|
||||
fortManager.show();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user