From c0094554b13ef4579a9112f9b4c0e5ccd92f9770 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Thu, 6 Feb 2025 11:22:47 +0000 Subject: [PATCH] feat: Convert daemon to Qt app and introduce Qt local server --- src/apps/deskflow-daemon/CMakeLists.txt | 5 ++- src/apps/deskflow-daemon/deskflow-daemon.cpp | 4 +- src/lib/deskflow/CMakeLists.txt | 14 +++++-- src/lib/deskflow/DaemonApp.cpp | 42 ++++++++++---------- src/lib/deskflow/DaemonApp.h | 16 ++++++-- src/lib/deskflow/ipc/IpcServer2.cpp | 29 ++++++++++++++ src/lib/deskflow/ipc/IpcServer2.h | 27 +++++++++++++ 7 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 src/lib/deskflow/ipc/IpcServer2.cpp create mode 100644 src/lib/deskflow/ipc/IpcServer2.h diff --git a/src/apps/deskflow-daemon/CMakeLists.txt b/src/apps/deskflow-daemon/CMakeLists.txt index dbbdf3b4a..46ebab44b 100644 --- a/src/apps/deskflow-daemon/CMakeLists.txt +++ b/src/apps/deskflow-daemon/CMakeLists.txt @@ -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} diff --git a/src/apps/deskflow-daemon/deskflow-daemon.cpp b/src/apps/deskflow-daemon/deskflow-daemon.cpp index f24f2d478..e81d07977 100644 --- a/src/apps/deskflow-daemon/deskflow-daemon.cpp +++ b/src/apps/deskflow-daemon/deskflow-daemon.cpp @@ -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 diff --git a/src/lib/deskflow/CMakeLists.txt b/src/lib/deskflow/CMakeLists.txt index d64cacb12..d0660fa08 100644 --- a/src/lib/deskflow/CMakeLists.txt +++ b/src/lib/deskflow/CMakeLists.txt @@ -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() diff --git a/src/lib/deskflow/DaemonApp.cpp b/src/lib/deskflow/DaemonApp.cpp index c3ab897cd..eeaca1678 100644 --- a/src/lib/deskflow/DaemonApp.cpp +++ b/src/lib/deskflow/DaemonApp.cpp @@ -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 diff --git a/src/lib/deskflow/DaemonApp.h b/src/lib/deskflow/DaemonApp.h index 2bbd96427..5e73b35f6 100644 --- a/src/lib/deskflow/DaemonApp.h +++ b/src/lib/deskflow/DaemonApp.h @@ -11,9 +11,16 @@ #include #include +#include + 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 m_ipcLogOutputter; IEventQueue *m_events = nullptr; FileLogOutputter *m_fileLogOutputter = nullptr; + std::unique_ptr m_ipcServer2; }; diff --git a/src/lib/deskflow/ipc/IpcServer2.cpp b/src/lib/deskflow/ipc/IpcServer2.cpp new file mode 100644 index 000000000..c2aa8fd60 --- /dev/null +++ b/src/lib/deskflow/ipc/IpcServer2.cpp @@ -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 + +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 diff --git a/src/lib/deskflow/ipc/IpcServer2.h b/src/lib/deskflow/ipc/IpcServer2.h new file mode 100644 index 000000000..c240774ed --- /dev/null +++ b/src/lib/deskflow/ipc/IpcServer2.h @@ -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 + +class QLocalServer; + +namespace deskflow::ipc { + +class IpcServer2 : public QObject +{ + Q_OBJECT + +public: + IpcServer2(QObject *parent); + ~IpcServer2(); + +private: + QLocalServer *m_server; +}; + +} // namespace deskflow::ipc