From d6228416a19f3eb70a865d549aab4d637dd62df5 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Fri, 7 Feb 2025 17:02:20 +0000 Subject: [PATCH] refactor: Send log level to daemon over IPC instead of when sending command --- src/apps/deskflow-gui/MainWindow.cpp | 3 + src/lib/gui/config/AppConfig.cpp | 4 ++ src/lib/gui/config/AppConfig.h | 1 + src/lib/gui/config/ElevateMode.h | 18 +++--- src/lib/gui/core/CoreProcess.cpp | 17 +++++- src/lib/gui/core/CoreProcess.h | 1 + src/lib/gui/ipc/DaemonIpcClient.cpp | 83 +++++++++++++++++++--------- src/lib/gui/ipc/DaemonIpcClient.h | 11 ++-- 8 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/apps/deskflow-gui/MainWindow.cpp b/src/apps/deskflow-gui/MainWindow.cpp index f416df7d2..5d6a367eb 100644 --- a/src/apps/deskflow-gui/MainWindow.cpp +++ b/src/apps/deskflow-gui/MainWindow.cpp @@ -296,6 +296,7 @@ void MainWindow::connectSlots() connect(&m_appConfig, &AppConfig::tlsChanged, this, &MainWindow::appConfigTlsChanged); connect(&m_appConfig, &AppConfig::screenNameChanged, this, &MainWindow::updateScreenName); + connect(&m_appConfig, &AppConfig::logLevelChanged, &m_coreProcess, &CoreProcess::applyLogLevel); connect(&m_coreProcess, &CoreProcess::starting, this, &MainWindow::coreProcessStarting, Qt::DirectConnection); connect(&m_coreProcess, &CoreProcess::error, this, &MainWindow::coreProcessError); @@ -631,6 +632,8 @@ void MainWindow::open() qDebug() << "update check disabled"; } + m_coreProcess.applyLogLevel(); + if (m_appConfig.startedBefore()) { m_coreProcess.start(); } diff --git a/src/lib/gui/config/AppConfig.cpp b/src/lib/gui/config/AppConfig.cpp index 41eb2c7f2..dccbe2432 100644 --- a/src/lib/gui/config/AppConfig.cpp +++ b/src/lib/gui/config/AppConfig.cpp @@ -14,6 +14,7 @@ #include #include #include + #include using namespace deskflow::gui; @@ -680,7 +681,10 @@ void AppConfig::setNetworkInterface(const QString &s) void AppConfig::setLogLevel(int i) { + const auto changed = (m_LogLevel != i); m_LogLevel = i; + if (changed) + Q_EMIT logLevelChanged(); } void AppConfig::setLogToFile(bool b) diff --git a/src/lib/gui/config/AppConfig.h b/src/lib/gui/config/AppConfig.h index a86d85753..7ab62a629 100644 --- a/src/lib/gui/config/AppConfig.h +++ b/src/lib/gui/config/AppConfig.h @@ -342,4 +342,5 @@ private: signals: void tlsChanged(); void screenNameChanged(); + void logLevelChanged(); }; diff --git a/src/lib/gui/config/ElevateMode.h b/src/lib/gui/config/ElevateMode.h index a3e63fc2b..94fe95dbb 100644 --- a/src/lib/gui/config/ElevateMode.h +++ b/src/lib/gui/config/ElevateMode.h @@ -1,6 +1,6 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2016 Symless Ltd. + * SPDX-FileCopyrightText: (C) 2016 - 2025 Symless Ltd. * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception */ @@ -9,20 +9,20 @@ /** * @brief The elevate mode tristate determines two behaviors on Windows. * - * The first, switch-on-desk-switch (SodS), passed through deskflowd as a - * command line argument to deskflow core, determines if the server restarts - * when switching Windows desktops (e.g. when Windows UAC dialog pops up). - * The second, passed as a boolean flag to Deskflowd over the IPC inside - * IpcMessageType::CommandMessage, determines whether Deskflow should be started - * with elevated privileges. - * * The matrix for these two behaviors is as follows: * - * | SodS | Elevate | + * | sods | elevate | * |-----------|------------| * kAutomatic | true | false | * kAlways | false | true | * kNever | false | false | + * + * The first, --stop-on-desk-switch (sods), is passed through the daemon as a + * command line argument to the server/client, and determines if it restarts + * when switching Windows desktops (e.g. when Windows UAC dialog pops up). + * + * The second, elevate, is passed as a boolean flag to the daemon over IPC, + * and determines whether the server/client should be started with elevated privileges. */ enum class ElevateMode { diff --git a/src/lib/gui/core/CoreProcess.cpp b/src/lib/gui/core/CoreProcess.cpp index 3020d729a..531d24477 100644 --- a/src/lib/gui/core/CoreProcess.cpp +++ b/src/lib/gui/core/CoreProcess.cpp @@ -242,6 +242,16 @@ void CoreProcess::onProcessFinished(int exitCode, QProcess::ExitStatus) } } +void CoreProcess::applyLogLevel() +{ + if (m_appConfig.processMode() == ProcessMode::kService) { + qDebug() << "setting daemon log level:" << m_appConfig.logLevelText(); + if (!m_daemonIpcClient->sendLogLevel(m_appConfig.logLevelText())) { + qCritical() << "failed to set daemon ipc log level"; + } + } +} + void CoreProcess::startForegroundProcess(const QString &app, const QStringList &args) { using enum ProcessState; @@ -280,7 +290,12 @@ void CoreProcess::startProcessFromDaemon(const QString &app, const QStringList & QString commandQuoted = makeQuotedArgs(app, args); qInfo("running command: %s", qPrintable(commandQuoted)); - m_daemonIpcClient->sendCommand(commandQuoted, m_appConfig.elevateMode()); + + if (!m_daemonIpcClient->sendCommand(commandQuoted, m_appConfig.elevateMode())) { + qCritical("aborting process start, ipc connect failed"); + return; + } + setProcessState(Started); } diff --git a/src/lib/gui/core/CoreProcess.h b/src/lib/gui/core/CoreProcess.h index fedadfcc7..769a6f86a 100644 --- a/src/lib/gui/core/CoreProcess.h +++ b/src/lib/gui/core/CoreProcess.h @@ -90,6 +90,7 @@ public: void stop(std::optional processMode = std::nullopt); void restart(); void cleanup(); + void applyLogLevel(); // getters Mode mode() const diff --git a/src/lib/gui/ipc/DaemonIpcClient.cpp b/src/lib/gui/ipc/DaemonIpcClient.cpp index e01247c2d..2698f9bca 100644 --- a/src/lib/gui/ipc/DaemonIpcClient.cpp +++ b/src/lib/gui/ipc/DaemonIpcClient.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace deskflow::gui::ipc { @@ -20,27 +21,27 @@ DaemonIpcClient::DaemonIpcClient(QObject *parent) : QObject(parent), m_socket{ne { } -DaemonIpcClient::~DaemonIpcClient() -{ -} - -void DaemonIpcClient::connectToServer() +bool DaemonIpcClient::connectToServer() { qInfo("connecting to daemon ipc"); m_socket->connectToServer(kDaemonIpcName); if (!m_socket->waitForConnected(kTimeout)) { - qCritical() << "ipc client failed to connect to server:" << kDaemonIpcName; - return; + qWarning() << "ipc client failed to connect to server:" << kDaemonIpcName; + return false; } - sendMessage("hello", "hello", false); + if (!sendMessage("hello", "hello", false)) { + qWarning() << "ipc client failed to send hello"; + return false; + } connect(m_socket, &QLocalSocket::disconnected, this, &DaemonIpcClient::handleDisconnected); connect(m_socket, &QLocalSocket::errorOccurred, this, &DaemonIpcClient::handleErrorOccurred); m_connected = true; qInfo() << "ipc client connected to server:" << kDaemonIpcName; + return true; } void DaemonIpcClient::handleDisconnected() @@ -55,50 +56,80 @@ void DaemonIpcClient::handleErrorOccurred() m_connected = false; } -void DaemonIpcClient::sendCommand(const QString &command, ElevateMode elevateMode) +bool DaemonIpcClient::keepAlive() { - sendMessage("elevate=" + QString::number(static_cast(elevateMode))); - sendMessage("command=" + command); - sendMessage("restart"); + if (!isConnected() && !connectToServer()) { + qWarning() << "ipc client keep alive failed to connect"; + return false; + } + + if (!sendMessage("noop")) { + qWarning() << "ipc client keep alive ping failed"; + m_connected = false; + return false; + } + + return true; } -void DaemonIpcClient::sendMessage(const QString &message, const QString &expectAck, const bool expectConnected) +bool DaemonIpcClient::sendLogLevel(const QString &logLevel) +{ + if (!keepAlive()) + return false; + + sendMessage("logLevel=" + logLevel); + return true; +} + +bool DaemonIpcClient::sendCommand(const QString &command, ElevateMode elevateMode) +{ + if (!keepAlive()) + return false; + + sendMessage("elevate=" + (elevateMode == ElevateMode::kAlways ? QStringLiteral("yes") : QStringLiteral("no"))); + sendMessage("command=" + command); + sendMessage("restart"); + return true; +} + +bool DaemonIpcClient::sendMessage(const QString &message, const QString &expectAck, const bool expectConnected) { if (expectConnected && !m_connected) { - qCritical() << "cannot send command, ipc not connected"; - return; + qWarning() << "cannot send command, ipc not connected"; + return false; } QByteArray messageData = message.toUtf8() + "\n"; m_socket->write(messageData); if (!m_socket->waitForBytesWritten(kTimeout)) { - qCritical() << "ipc client failed to write command"; - return; + qWarning() << "ipc client failed to write command"; + return false; } if (!m_socket->waitForReadyRead(kTimeout)) { - qCritical() << "ipc client failed to read response"; - return; + qWarning() << "ipc client failed to read response"; + return false; } QByteArray response = m_socket->readAll(); if (response.isEmpty()) { - qCritical() << "ipc client got empty response"; - return; + qWarning() << "ipc client got empty response"; + return false; } QString responseData = QString::fromUtf8(response); if (responseData.isEmpty()) { - qCritical() << "ipc client failed to convert response to string"; - return; + qWarning() << "ipc client failed to convert response to string"; + return false; } if (responseData != expectAck + "\n") { - qCritical() << "ipc client got unexpected response: " << responseData; - return; + qWarning() << "ipc client got unexpected response: " << responseData; + return false; } - qInfo() << "ipc client sent message: " << messageData; + qDebug() << "ipc client sent message: " << messageData; + return true; } } // namespace deskflow::gui::ipc diff --git a/src/lib/gui/ipc/DaemonIpcClient.h b/src/lib/gui/ipc/DaemonIpcClient.h index e7867e9e9..91abe3404 100644 --- a/src/lib/gui/ipc/DaemonIpcClient.h +++ b/src/lib/gui/ipc/DaemonIpcClient.h @@ -19,10 +19,10 @@ class DaemonIpcClient : public QObject Q_OBJECT public: - DaemonIpcClient(QObject *parent = nullptr); - ~DaemonIpcClient(); - void connectToServer(); - void sendCommand(const QString &command, ElevateMode elevateMode); + explicit DaemonIpcClient(QObject *parent = nullptr); + bool connectToServer(); + bool sendLogLevel(const QString &logLevel); + bool sendCommand(const QString &command, ElevateMode elevateMode); bool isConnected() const { @@ -34,7 +34,8 @@ private slots: void handleErrorOccurred(); private: - void sendMessage(const QString &message, const QString &expectAck = "ok", const bool expectConnected = true); + bool keepAlive(); + bool sendMessage(const QString &message, const QString &expectAck = "ok", const bool expectConnected = true); private: QLocalSocket *m_socket;