From 901dacf59321af9e9309a32d0590cde5ee6a56f3 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Tue, 15 Apr 2025 21:52:36 +0100 Subject: [PATCH] feat(daemon): Friendly message on daemon connection error --- src/lib/gui/MainWindow.cpp | 41 ++++++++++++++++------------- src/lib/gui/MainWindow.h | 1 + src/lib/gui/Messages.cpp | 31 ++++++++++++++++++++++ src/lib/gui/Messages.h | 2 ++ src/lib/gui/core/CoreProcess.cpp | 14 +++++++--- src/lib/gui/core/CoreProcess.h | 2 ++ src/lib/gui/ipc/DaemonIpcClient.cpp | 19 +++++++++---- src/lib/gui/ipc/DaemonIpcClient.h | 4 +-- 8 files changed, 86 insertions(+), 28 deletions(-) diff --git a/src/lib/gui/MainWindow.cpp b/src/lib/gui/MainWindow.cpp index 7c510d628..7dd810a36 100644 --- a/src/lib/gui/MainWindow.cpp +++ b/src/lib/gui/MainWindow.cpp @@ -289,6 +289,7 @@ void MainWindow::connectSlots() connect(&m_coreProcess, &CoreProcess::processStateChanged, this, &MainWindow::coreProcessStateChanged); connect(&m_coreProcess, &CoreProcess::connectionStateChanged, this, &MainWindow::coreConnectionStateChanged); connect(&m_coreProcess, &CoreProcess::secureSocket, this, &MainWindow::secureSocket); + connect(&m_coreProcess, &CoreProcess::daemonIpcClientConnectFailed, this, &MainWindow::daemonIpcClientConnectFailed); connect(m_actionAbout, &QAction::triggered, this, &MainWindow::openAboutDialog); connect(m_actionClearSettings, &QAction::triggered, this, &MainWindow::clearSettings); @@ -365,6 +366,21 @@ void MainWindow::firstShown() // hacky and fragile, so maybe there's a better approach. const auto kCriticalDialogDelay = 100; QTimer::singleShot(kCriticalDialogDelay, this, &messages::raiseCriticalDialog); + + if (!Settings::value(Settings::Gui::AutoUpdateCheck).isValid()) { + showAndActivate(); + Settings::setValue(Settings::Gui::AutoUpdateCheck, messages::showUpdateCheckOption(this)); + } + + if (Settings::value(Settings::Gui::AutoUpdateCheck).toBool()) { + m_versionChecker.checkLatest(); + } else { + qDebug() << "update check disabled"; + } + + if (Settings::value(Settings::Core::StartedBefore).toBool()) { + m_coreProcess.start(); + } } void MainWindow::settingsChanged(const QString &key) @@ -603,24 +619,6 @@ void MainWindow::serverConnectionConfigureClient(const QString &clientName) void MainWindow::open() { - - if (!Settings::value(Settings::Gui::AutoUpdateCheck).isValid()) { - showAndActivate(); - Settings::setValue(Settings::Gui::AutoUpdateCheck, messages::showUpdateCheckOption(this)); - } - - if (Settings::value(Settings::Gui::AutoUpdateCheck).toBool()) { - m_versionChecker.checkLatest(); - } else { - qDebug() << "update check disabled"; - } - - m_coreProcess.applyLogLevel(); - - if (Settings::value(Settings::Core::StartedBefore).toBool()) { - m_coreProcess.start(); - } - Settings::value(Settings::Gui::Autohide).toBool() ? hide() : showAndActivate(); } @@ -1137,3 +1135,10 @@ bool MainWindow::regenerateLocalFingerprints() updateLocalFingerprint(); return true; } + +void MainWindow::daemonIpcClientConnectFailed() +{ + if (deskflow::gui::messages::showDaemonOffline(this)) { + m_coreProcess.retryDaemon(); + } +} diff --git a/src/lib/gui/MainWindow.h b/src/lib/gui/MainWindow.h index ab828e5be..61b66f6af 100644 --- a/src/lib/gui/MainWindow.h +++ b/src/lib/gui/MainWindow.h @@ -158,6 +158,7 @@ private: void showAndActivate(); void showHostNameEditor(); void setHostName(); + void daemonIpcClientConnectFailed(); /** * @brief trustedFingerprintDb get the fingerprintDb for the trusted clients or trusted servers. diff --git a/src/lib/gui/Messages.cpp b/src/lib/gui/Messages.cpp index e55b6e944..32ad9c028 100644 --- a/src/lib/gui/Messages.cpp +++ b/src/lib/gui/Messages.cpp @@ -309,4 +309,35 @@ bool showUpdateCheckOption(QWidget *parent) return message.clickedButton() == checkButton; } +bool showDaemonOffline(QWidget *parent) +{ + QMessageBox message(parent); + message.setIcon(QMessageBox::Warning); + message.setWindowTitle(QObject::tr("Background service offline")); + + message.addButton(QObject::tr("Retry"), QMessageBox::AcceptRole); + const auto ignore = message.addButton(QObject::tr("Ignore"), QMessageBox::RejectRole); + const auto disable = message.addButton(QObject::tr("Disable"), QMessageBox::NoRole); + + message.setText(QString( + "

There was a problem finding the %1 background service (daemon).

" + "

The background service makes %1 work with UAC prompts and the login screen.

" + "

If don't want to use the background service and intentionally stopped it, " + "you can prevent it's use by disabling this feature.

" + "

If you did not stop the background service intentionally, there may be a problem with it. " + "Please retry or try restarting the %1 service from the Windows services program.

" + ) + .arg(kAppName)); + message.exec(); + + if (message.clickedButton() == ignore) { + return false; + } else if (message.clickedButton() == disable) { + Settings::setValue(Settings::Core::ProcessMode, Settings::ProcessMode::Desktop); + return false; + } + + return true; +} + } // namespace deskflow::gui::messages diff --git a/src/lib/gui/Messages.h b/src/lib/gui/Messages.h index 1f1eb8df1..f035e2092 100644 --- a/src/lib/gui/Messages.h +++ b/src/lib/gui/Messages.h @@ -49,4 +49,6 @@ void showWaylandLibraryError(QWidget *parent); bool showUpdateCheckOption(QWidget *parent); +bool showDaemonOffline(QWidget *parent); + } // namespace deskflow::gui::messages diff --git a/src/lib/gui/core/CoreProcess.cpp b/src/lib/gui/core/CoreProcess.cpp index 63acf8cb2..cf0e221d5 100644 --- a/src/lib/gui/core/CoreProcess.cpp +++ b/src/lib/gui/core/CoreProcess.cpp @@ -140,6 +140,7 @@ CoreProcess::CoreProcess(const IServerConfig &serverConfig, std::shared_ptrprocess(), &QProcessProxy::finished, this, &CoreProcess::onProcessFinished); @@ -224,7 +225,7 @@ void CoreProcess::applyLogLevel() if (processMode == ProcessMode::Service) { qDebug() << "setting daemon log level:" << Settings::logLevelText(); if (!m_daemonIpcClient->sendLogLevel(Settings::logLevelText())) { - qCritical() << "failed to set daemon ipc log level"; + qWarning() << "failed to set daemon ipc log level"; } } } @@ -263,7 +264,7 @@ void CoreProcess::startProcessFromDaemon(const QString &app, const QStringList & qInfo("running command: %s", qPrintable(commandQuoted)); if (!m_daemonIpcClient->sendStartProcess(commandQuoted, Settings::value(Settings::Daemon::Elevate).toBool())) { - qCritical("cannot start process, ipc command failed"); + qWarning("cannot start process, ipc command failed"); return; } @@ -297,7 +298,7 @@ void CoreProcess::stopProcessFromDaemon() } if (!m_daemonIpcClient->sendStopProcess()) { - qCritical("cannot stop process, ipc command failed"); + qWarning("cannot stop process, ipc command failed"); return; } @@ -736,4 +737,11 @@ void CoreProcess::clearSettings() m_daemonIpcClient->sendClearSettings(); } +void CoreProcess::retryDaemon() +{ + if (m_daemonIpcClient->connectToServer()) { + qInfo("successfully reconnected to daemon"); + } +} + } // namespace deskflow::gui diff --git a/src/lib/gui/core/CoreProcess.h b/src/lib/gui/core/CoreProcess.h index fba64a684..03b0ed110 100644 --- a/src/lib/gui/core/CoreProcess.h +++ b/src/lib/gui/core/CoreProcess.h @@ -79,6 +79,7 @@ public: void cleanup(); void applyLogLevel(); void clearSettings(); + void retryDaemon(); // getters Settings::CoreMode mode() const @@ -119,6 +120,7 @@ signals: void connectionStateChanged(ConnectionState state); void processStateChanged(ProcessState state); void secureSocket(bool enabled); + void daemonIpcClientConnectFailed(); private slots: void onProcessFinished(int exitCode, QProcess::ExitStatus); diff --git a/src/lib/gui/ipc/DaemonIpcClient.cpp b/src/lib/gui/ipc/DaemonIpcClient.cpp index 12d1930e8..20b570620 100644 --- a/src/lib/gui/ipc/DaemonIpcClient.cpp +++ b/src/lib/gui/ipc/DaemonIpcClient.cpp @@ -27,20 +27,32 @@ DaemonIpcClient::DaemonIpcClient(QObject *parent) bool DaemonIpcClient::connectToServer() { - qDebug() << "daemon ipc client connecting to server:" << kDaemonIpcName; + if (m_connecting) { + qDebug() << "daemon ipc client already connecting to server"; + return false; + } + qDebug() << "daemon ipc client connecting to server:" << kDaemonIpcName; + m_connecting = true; m_socket->connectToServer(kDaemonIpcName); + if (!m_socket->waitForConnected(kTimeout)) { qWarning() << "daemon ipc client failed to connect"; + m_connecting = false; + Q_EMIT connectFailed(); return false; } if (!sendMessage("hello", "hello", false)) { qWarning() << "daemon ipc client failed to send hello"; + m_connecting = false; + Q_EMIT connectFailed(); return false; } + m_connecting = false; m_connected = true; + qDebug() << "daemon ipc client connected"; Q_EMIT connected(); @@ -51,10 +63,7 @@ void DaemonIpcClient::handleDisconnected() { qWarning() << "daemon ipc client disconnected from server"; m_connected = false; - - if (!connectToServer()) { - qWarning() << "daemon ipc client failed to reconnect to server"; - } + Q_EMIT connectFailed(); } void DaemonIpcClient::handleErrorOccurred() diff --git a/src/lib/gui/ipc/DaemonIpcClient.h b/src/lib/gui/ipc/DaemonIpcClient.h index df694d528..6b52b9d47 100644 --- a/src/lib/gui/ipc/DaemonIpcClient.h +++ b/src/lib/gui/ipc/DaemonIpcClient.h @@ -8,8 +8,6 @@ #include -#include "common/Settings.h" - class QLocalSocket; namespace deskflow::gui::ipc { @@ -34,6 +32,7 @@ public: signals: void connected(); + void connectFailed(); private slots: void handleDisconnected(); @@ -46,6 +45,7 @@ private: private: QLocalSocket *m_socket; bool m_connected{false}; + bool m_connecting{false}; }; } // namespace deskflow::gui::ipc