feat: Convert daemon to Qt app and introduce Qt local server

This commit is contained in:
Nick Bolton
2025-02-06 11:22:47 +00:00
parent 95603c82ec
commit c0094554b1
7 changed files with 106 additions and 31 deletions

View File

@ -14,6 +14,8 @@ if(WIN32)
add_executable(${target} WIN32 ${target}.cpp ${CMAKE_CURRENT_BINARY_DIR}/${target}.rc)
find_package(Qt6 COMPONENTS Core Network)
target_link_libraries(
${target}
arch
@ -24,7 +26,8 @@ if(WIN32)
net
platform
app
${libs})
${libs}
Qt6::Core)
install(
TARGETS ${target}

View File

@ -41,8 +41,8 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
Log log;
EventQueue events;
DaemonApp app(&events);
return app.run(__argc, __argv);
DaemonApp app(&events, __argc, __argv);
return DaemonApp::exec();
}
#endif

View File

@ -49,6 +49,8 @@ endif()
####################Start Making Library#########################
set(lib_name app)
set(CMAKE_AUTOMOC ON)
# arch
if(WIN32)
set(PLATFORM_CODE
@ -143,8 +145,12 @@ add_library(${lib_name} STATIC ${PLATFORM_CODE}
XScreen.h
languages/LanguageManager.cpp
languages/LanguageManager.h
ipc/IpcServer2.cpp
ipc/IpcServer2.h
)
find_package(Qt6 COMPONENTS Core Network)
target_link_libraries(${lib_name} PRIVATE Qt6::Core Qt6::Network)
if(WIN32)
target_compile_definitions(${lib_name} PUBLIC HAVE_WINTOAST)
@ -161,6 +167,7 @@ target_include_directories(
if(UNIX)
target_link_libraries(
${lib_name}
PRIVATE
arch
client
ipc
@ -174,12 +181,13 @@ if(UNIX)
)
if(NOT APPLE)
target_link_libraries(${lib_name} pugixml)
target_link_libraries(${lib_name} PRIVATE pugixml)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
target_link_libraries(${lib_name} PkgConfig::lib_glib
PkgConfig::lib_gdkpixbuf PkgConfig::lib_notify)
target_link_libraries(${lib_name}
PRIVATE
PkgConfig::lib_glib PkgConfig::lib_gdkpixbuf PkgConfig::lib_notify)
endif()
endif()
endif()

View File

@ -22,6 +22,7 @@
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcLogOutputter.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer2.h"
#include "ipc/IpcSettingMessage.h"
#include "net/SocketMultiplexer.h"
@ -95,8 +96,16 @@ int winMainLoopStatic(int, const char **)
}
#endif
DaemonApp::DaemonApp(IEventQueue *events) : m_events(events)
DaemonApp::DaemonApp(IEventQueue *events, int argc, char **argv)
: QCoreApplication(argc, argv),
m_events(events),
m_ipcServer2{new deskflow::ipc::IpcServer2(this)}
{
// HACK: init used to be run, which was the main loop.
// now it's used for arg parsing, install/uninstall, etc.
if (init(argc, argv) != kExitSuccess) {
exit(kExitFailed);
}
s_instance = this;
}
@ -105,7 +114,14 @@ DaemonApp::~DaemonApp()
s_instance = nullptr;
}
int DaemonApp::run(int argc, char **argv)
void DaemonApp::startAsync()
{
#if SYSAPI_WIN32
m_watchdog->startAsync();
#endif
}
int DaemonApp::init(int argc, char **argv)
{
bool uninstall = false;
try {
@ -141,27 +157,11 @@ int DaemonApp::run(int argc, char **argv)
}
}
#if SYSAPI_WIN32
if (!foreground) {
#if SYSAPI_WIN32
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
// in that case, but is accessible when running in the foreground.
CLOG->insert(new MSWindowsDebugOutputter()); // NOSONAR -- Adopted by `Log`
}
#endif
if (foreground) {
LOG((CLOG_NOTE "starting daemon in foreground"));
// run process in foreground instead of daemonizing.
// useful for debugging.
mainLoop(false, foreground);
} else {
#if SYSAPI_WIN32
LOG((CLOG_PRINT "daemonizing windows service"));
ARCH->daemonize(kAppName, winMainLoopStatic);
#elif SYSAPI_UNIX
LOG((CLOG_PRINT "daemonizing unix service"));
ARCH->daemonize(kAppName, unixMainLoopStatic);
CLOG->insert(new MSWindowsDebugOutputter()); // NOSONAR - Adopted by `Log`
#endif
}
@ -255,7 +255,7 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground)
void DaemonApp::foregroundError(const char *message)
{
#if SYSAPI_WIN32
MessageBox(NULL, message, "Deskflow Service", MB_OK | MB_ICONERROR);
MessageBoxA(NULL, message, "Deskflow Service", MB_OK | MB_ICONERROR);
#elif SYSAPI_UNIX
cerr << message << endl;
#endif

View File

@ -11,9 +11,16 @@
#include <memory>
#include <string>
#include <QCoreApplication>
class Event;
class IpcLogOutputter;
class FileLogOutputter;
class QLocalServer;
namespace deskflow::ipc {
class IpcServer2;
}
#if SYSAPI_WIN32
class MSWindowsWatchdog;
@ -21,16 +28,16 @@ class MSWindowsWatchdog;
extern const char *const kLogFilename;
class DaemonApp
class DaemonApp : public QCoreApplication
{
public:
DaemonApp(IEventQueue *events);
DaemonApp(IEventQueue *events, int argc, char **argv);
~DaemonApp();
int run(int argc, char **argv);
void startAsync();
void mainLoop(bool logToFile, bool foreground = false);
private:
int init(int argc, char **argv);
void daemonize();
void foregroundError(const char *message);
std::string logFilename();
@ -48,4 +55,5 @@ private:
std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
IEventQueue *m_events = nullptr;
FileLogOutputter *m_fileLogOutputter = nullptr;
std::unique_ptr<deskflow::ipc::IpcServer2> m_ipcServer2;
};

View File

@ -0,0 +1,29 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "IpcServer2.h"
#include "base/Log.h"
#include <QLocalServer>
namespace deskflow::ipc {
const auto kServerName = QStringLiteral("deskflow-daemon");
IpcServer2::IpcServer2(QObject *parent) : QObject(parent), m_server{new QLocalServer(this)}
{
m_server->removeServer(kServerName);
m_server->listen(kServerName);
LOG_INFO("ipc server listening on %s", kServerName.toStdString().c_str());
}
IpcServer2::~IpcServer2()
{
m_server->close();
}
} // namespace deskflow::ipc

View File

@ -0,0 +1,27 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include <QObject>
class QLocalServer;
namespace deskflow::ipc {
class IpcServer2 : public QObject
{
Q_OBJECT
public:
IpcServer2(QObject *parent);
~IpcServer2();
private:
QLocalServer *m_server;
};
} // namespace deskflow::ipc