refactor: Send log level to daemon over IPC instead of when sending command

This commit is contained in:
Nick Bolton
2025-02-07 17:02:20 +00:00
parent 80cc323f5a
commit d6228416a1
8 changed files with 97 additions and 41 deletions

View File

@ -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();
}

View File

@ -14,6 +14,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <QVariant>
#include <functional>
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)

View File

@ -342,4 +342,5 @@ private:
signals:
void tlsChanged();
void screenNameChanged();
void logLevelChanged();
};

View File

@ -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
{

View File

@ -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);
}

View File

@ -90,6 +90,7 @@ public:
void stop(std::optional<ProcessMode> processMode = std::nullopt);
void restart();
void cleanup();
void applyLogLevel();
// getters
Mode mode() const

View File

@ -11,6 +11,7 @@
#include <QDebug>
#include <QLocalSocket>
#include <QObject>
#include <QString>
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<int>(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

View File

@ -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;