From da911c6350c11ec55236e73935555b9df6604e1c Mon Sep 17 00:00:00 2001 From: Martchus Date: Thu, 31 Dec 2020 02:48:18 +0100 Subject: [PATCH] Refactor overall status compution * Allow configuring the information to consider for computing the overall status via SyncthingStatusComputionFlags * Add flag to allow considering the status of remote devices for https://github.com/Martchus/syncthingtray/issues/74 * Show only plain "idle" status when no flags are present for https://github.com/Martchus/syncthingtray/issues/76 * Set the default flags to keep the default behavior as-is --- cli/application.cpp | 29 +++++----- connector/syncthingconnection.cpp | 72 +++++++++++++++++++------ connector/syncthingconnection.h | 25 +++++++++ connector/syncthingconnectionsettings.h | 20 +++++++ connector/syncthingconnectionstatus.h | 20 ++++++- model/syncthingstatusselectionmodel.cpp | 1 + tray/gui/traywidget.cpp | 2 + widgets/misc/statusinfo.cpp | 4 ++ 8 files changed, 143 insertions(+), 30 deletions(-) diff --git a/cli/application.cpp b/cli/application.cpp index a72df3d..9dd8e0d 100644 --- a/cli/application.cpp +++ b/cli/application.cpp @@ -579,20 +579,25 @@ void Application::printStatus(const ArgumentOccurrence &) const auto &overallStats(m_connection.computeOverallDirStatistics()); const auto *statusString = "idle"; const auto *statusColor = "32"; - switch (m_connection.status()) { - case SyncthingStatus::Synchronizing: - statusString = "synchronizing"; - statusColor = "34"; - break; - case SyncthingStatus::Scanning: - statusString = "scanning"; - statusColor = "34"; - break; - case SyncthingStatus::OutOfSync: + if (m_connection.hasOutOfSyncDirs()) { statusString = "out-of-sync"; statusColor = "31"; - break; - default:; + } else { + switch (m_connection.status()) { + case SyncthingStatus::Synchronizing: + statusString = "synchronizing"; + statusColor = "34"; + break; + case SyncthingStatus::RemoteNotInSync: + statusString = "remote synchronizing"; + statusColor = "34"; + break; + case SyncthingStatus::Scanning: + statusString = "scanning"; + statusColor = "34"; + break; + default:; + } } if (!EscapeCodes::enabled) { printProperty("Status", statusString); diff --git a/connector/syncthingconnection.cpp b/connector/syncthingconnection.cpp index 0154b88..dff93c7 100644 --- a/connector/syncthingconnection.cpp +++ b/connector/syncthingconnection.cpp @@ -72,6 +72,7 @@ SyncthingConnection::SyncthingConnection(const QString &syncthingUrl, const QByt , m_syncthingUrl(syncthingUrl) , m_apiKey(apiKey) , m_status(SyncthingStatus::Disconnected) + , m_statusComputionFlags(SyncthingStatusComputionFlags::Default) , m_keepPolling(false) , m_abortingAllRequests(false) , m_abortingToReconnect(false) @@ -169,6 +170,8 @@ QString SyncthingConnection::statusText(SyncthingStatus status) return tr("connected, paused"); case SyncthingStatus::Synchronizing: return tr("connected, synchronizing"); + case SyncthingStatus::RemoteNotInSync: + return tr("connected, remote not in sync"); default: return tr("unknown"); } @@ -773,15 +776,29 @@ bool SyncthingConnection::applySettings(SyncthingConnectionSettings &connectionS setDevStatsPollInterval(connectionSettings.devStatsPollInterval); setErrorsPollInterval(connectionSettings.errorsPollInterval); setAutoReconnectInterval(connectionSettings.reconnectInterval); + setStatusComputionFlags(connectionSettings.statusComputionFlags); return reconnectRequired; } /*! - * \brief Sets the connection status. Ensures statusChanged() is emitted. + * \brief Sets the connection status. Ensures statusChanged() is emitted if the status has actually changed. * \param status Specifies the status; should be either SyncthingStatus::Disconnected, SyncthingStatus::Reconnecting, or * SyncthingStatus::Idle. There is no use in specifying other values such as SyncthingStatus::Synchronizing as - * these are determined automatically within the method. + * these are determined automatically within the method according to SyncthingConnection::statusComputionFlags(). + * + * The precedence of the "connected" states from highest to lowest is: + * 1. SyncthingStatus::Synchronizing + * 2. SyncthingStatus::RemoteSynchronizing + * 3. SyncthingStatus::Scanning + * 4. SyncthingStatus::Paused + * 5. SyncthingStatus::Idle + * + * \remarks + * - The "out-of-sync" status is (currently) *not* handled by this function. One needs to query this via + * the SyncthingConnection::hasOutOfSyncDirs() function. + * - Whether notifications are available is *not* handled by this function. One needs to query this via + * SyncthingConnection::hasUnreadNotifications(). */ void SyncthingConnection::setStatus(SyncthingStatus status) { @@ -802,30 +819,51 @@ void SyncthingConnection::setStatus(SyncthingStatus status) // reset reconnect tries m_autoReconnectTries = 0; + // skip if no further status information should be gathered + if (m_statusComputionFlags == SyncthingStatusComputionFlags::None) { + status = SyncthingStatus::Idle; + break; + } + // check whether at least one directory is scanning, preparing to synchronize or synchronizing // note: We don't distinguish between "preparing to sync" and "synchronizing" for computing the overall // status at the moment. - bool scanning = false; - bool synchronizing = false; - for (const SyncthingDir &dir : m_dirs) { - switch (dir.status) { - case SyncthingDirStatus::PreparingToSync: - case SyncthingDirStatus::Synchronizing: - synchronizing = true; - break; - case SyncthingDirStatus::WaitingToScan: - case SyncthingDirStatus::Scanning: - scanning = true; - break; - default:; + auto scanning = false, synchronizing = false, remoteSynchronizing = false; + if (m_statusComputionFlags & SyncthingStatusComputionFlags::Synchronizing + || m_statusComputionFlags & SyncthingStatusComputionFlags::Scanning) { + for (const SyncthingDir &dir : m_dirs) { + switch (dir.status) { + case SyncthingDirStatus::WaitingToSync: + case SyncthingDirStatus::PreparingToSync: + case SyncthingDirStatus::Synchronizing: + synchronizing = m_statusComputionFlags & SyncthingStatusComputionFlags::Synchronizing; + break; + case SyncthingDirStatus::WaitingToScan: + case SyncthingDirStatus::Scanning: + scanning = m_statusComputionFlags & SyncthingStatusComputionFlags::Scanning; + break; + default:; + } + if (synchronizing) { + break; // skip remaining dirs, "synchronizing" overrides "scanning" anyways + } } - if (synchronizing) { - break; // skip remaining dirs, "synchronizing" overrides "scanning" anyways + } + + // set the status to "remote synchronizing" if at least one remote device is still in progress + if (!synchronizing && (m_statusComputionFlags & SyncthingStatusComputionFlags::RemoteSynchronizing)) { + for (const SyncthingDev &dev : m_devs) { + if (dev.status == SyncthingDevStatus::Synchronizing) { + remoteSynchronizing = true; + break; + } } } if (synchronizing) { status = SyncthingStatus::Synchronizing; + } else if (remoteSynchronizing) { + status = SyncthingStatus::RemoteNotInSync; } else if (scanning) { status = SyncthingStatus::Scanning; } else { diff --git a/connector/syncthingconnection.h b/connector/syncthingconnection.h index 3757de1..f1e6f8c 100644 --- a/connector/syncthingconnection.h +++ b/connector/syncthingconnection.h @@ -30,6 +30,7 @@ class MiscTests; namespace Data { struct SyncthingConnectionSettings; +enum class SyncthingStatusComputionFlags : quint64; LIB_SYNCTHING_CONNECTOR_EXPORT QNetworkAccessManager &networkAccessManager(); @@ -54,6 +55,7 @@ class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnection : public QObject { Q_PROPERTY(QString user READ user) Q_PROPERTY(QString password READ password) Q_PROPERTY(Data::SyncthingStatus status READ status NOTIFY statusChanged) + Q_PROPERTY(Data::SyncthingStatusComputionFlags statusComputionFlags READ statusComputionFlags WRITE setStatusComputionFlags) Q_PROPERTY(QString statusText READ statusText NOTIFY statusChanged) Q_PROPERTY(bool connected READ isConnected NOTIFY statusChanged) Q_PROPERTY(bool hasUnreadNotifications READ hasUnreadNotifications) @@ -98,6 +100,8 @@ public: SyncthingStatus status() const; QString statusText() const; static QString statusText(SyncthingStatus status); + SyncthingStatusComputionFlags statusComputionFlags() const; + void setStatusComputionFlags(SyncthingStatusComputionFlags flags); bool isConnected() const; bool hasPendingRequests() const; bool hasPendingRequestsIncludingEvents() const; @@ -313,6 +317,8 @@ private: QString m_user; QString m_password; SyncthingStatus m_status; + SyncthingStatusComputionFlags m_statusComputionFlags; + bool m_keepPolling; bool m_abortingAllRequests; bool m_abortingToReconnect; @@ -618,6 +624,25 @@ inline void SyncthingConnection::setRecordFileChanges(bool recordFileChanges) m_recordFileChanges = recordFileChanges; } +/*! + * \brief Returns what information is considered to compute the overall status returned by status(). + */ +inline SyncthingStatusComputionFlags SyncthingConnection::statusComputionFlags() const +{ + return m_statusComputionFlags; +} + +/*! + * \brief Sets what information should be used to compute the overall status returned by status(). + */ +inline void SyncthingConnection::setStatusComputionFlags(SyncthingStatusComputionFlags flags) +{ + if (m_statusComputionFlags != flags) { + m_statusComputionFlags = flags; + recalculateStatus(); + } +} + /*! * \brief Returns the Syncthing home/configuration directory. */ diff --git a/connector/syncthingconnectionsettings.h b/connector/syncthingconnectionsettings.h index 2734fab..f90e44c 100644 --- a/connector/syncthingconnectionsettings.h +++ b/connector/syncthingconnectionsettings.h @@ -3,6 +3,8 @@ #include "./global.h" +#include + #include #include #include @@ -10,6 +12,21 @@ namespace Data { +/*! + * \brief The SyncthingStatusComputionFlags enum specifies what information is considered to compute the overall state. + * \remarks The enum is supposed to be used as flag-enum. + */ +enum class SyncthingStatusComputionFlags : quint64 { + None = 0, /**< no further information is considered leaving SyncthingStatus::Disconnected, SyncthingStatus::Reconnecting, + SyncthingStatus::BeingDestroyed and SyncthingStatus::Idle the only possible states */ + Scanning = (1 << 0), /**< the status SyncthingStatus::Scanning might be set (in addition) */ + Synchronizing = (1 << 1), /**< the status SyncthingStatus::Synchronizing might be set (in addition) */ + RemoteSynchronizing = (1 << 2), /**< the status SyncthingStatus::RemoteNotInSync might be set (in addition) */ + DevicePaused = (1 << 3), /**< the status SyncthingStatus::Paused might be set if there's at least one paused device (in addition) */ + Default = SyncthingStatusComputionFlags::Scanning | SyncthingStatusComputionFlags::Synchronizing | SyncthingStatusComputionFlags::DevicePaused, + /**< the default flags used all over the place */ +}; + struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnectionSettings { QString label; QString syncthingUrl; @@ -23,6 +40,7 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnectionSettings { int reconnectInterval = defaultReconnectInterval; QString httpsCertPath; QList expectedSslErrors; + SyncthingStatusComputionFlags statusComputionFlags = SyncthingStatusComputionFlags::Default; bool autoConnect = false; bool loadHttpsCert(); @@ -33,4 +51,6 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnectionSettings { }; } // namespace Data +CPP_UTILITIES_MARK_FLAG_ENUM_CLASS(Data, Data::SyncthingStatusComputionFlags) + #endif // SYNCTHINGCONNECTIONSETTINGS_H diff --git a/connector/syncthingconnectionstatus.h b/connector/syncthingconnectionstatus.h index 2959dcc..9c0cd4e 100644 --- a/connector/syncthingconnectionstatus.h +++ b/connector/syncthingconnectionstatus.h @@ -12,7 +12,25 @@ Q_NAMESPACE extern LIB_SYNCTHING_CONNECTOR_EXPORT const QMetaObject staticMetaObject; QT_ANNOTATE_CLASS(qt_qnamespace, "") /*end*/ -enum class SyncthingStatus { Disconnected, Reconnecting, Idle, Scanning, Paused, Synchronizing, OutOfSync, BeingDestroyed }; +/*! + * \brief The SyncthingStatus enum specifies the overall status of the connection to Syncthing via its REST-API. + * + * Scanning, paused and (remote) synchronizing are only computed if the SyncthingStatusComputionFlags are set for + * these. + * + * This is *not* a flag enum even though the "connected" states are not exclusive. That's because only one icon can be + * shown at the same time anyways. Checkout SyncthingConnection::setStatus() for the precedence. + */ +enum class SyncthingStatus { + Disconnected = 0, /**< disconnected, possibly currently connecting */ + Reconnecting = 1, /**< disconnected, currently re-connnecting */ + BeingDestroyed = 7, /**< status is unknown; the SyncthingConnnection object is being destroyed anyways */ + Idle = 2, /**< connected, no special status information available/determined */ + Scanning = 3, /**< connected, at least one directory is scanning */ + Paused = 4, /**< connected, at least one device is paused */ + Synchronizing = 5, /**< connected, at least one local directory is waiting to sync, preparing to sync or synchronizing */ + RemoteNotInSync = 8, /**< connected, at least one directory of a connected remote device is not in sync (still synchronizing, error, …) */ +}; #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) Q_ENUM_NS(SyncthingStatus) #endif diff --git a/model/syncthingstatusselectionmodel.cpp b/model/syncthingstatusselectionmodel.cpp index df65914..9c255dd 100644 --- a/model/syncthingstatusselectionmodel.cpp +++ b/model/syncthingstatusselectionmodel.cpp @@ -21,6 +21,7 @@ SyncthingStatusSelectionModel::SyncthingStatusSelectionModel(QObject *parent) itemFor(SyncthingStatus::Scanning), itemFor(SyncthingStatus::Paused), itemFor(SyncthingStatus::Synchronizing), + itemFor(SyncthingStatus::RemoteNotInSync), }); } diff --git a/tray/gui/traywidget.cpp b/tray/gui/traywidget.cpp index 1944a89..867ea8c 100644 --- a/tray/gui/traywidget.cpp +++ b/tray/gui/traywidget.cpp @@ -389,6 +389,7 @@ void TrayWidget::handleStatusChanged(SyncthingStatus status) case SyncthingStatus::Idle: case SyncthingStatus::Scanning: case SyncthingStatus::Synchronizing: + case SyncthingStatus::RemoteNotInSync: m_ui->statusPushButton->setText(tr("Pause")); m_ui->statusPushButton->setToolTip(tr("Syncthing is running, click to pause all devices")); m_ui->statusPushButton->setIcon(QIcon::fromTheme( @@ -609,6 +610,7 @@ void TrayWidget::changeStatus() case SyncthingStatus::Idle: case SyncthingStatus::Scanning: case SyncthingStatus::Synchronizing: + case SyncthingStatus::RemoteNotInSync: m_connection.pauseAllDevs(); break; case SyncthingStatus::Paused: diff --git a/widgets/misc/statusinfo.cpp b/widgets/misc/statusinfo.cpp index 1f91b46..cb118a1 100644 --- a/widgets/misc/statusinfo.cpp +++ b/widgets/misc/statusinfo.cpp @@ -85,6 +85,10 @@ void StatusInfo::updateConnectionStatus(const SyncthingConnection &connection, c m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Synchronization is ongoing"); m_statusIcon = &icons.sync; break; + case SyncthingStatus::RemoteNotInSync: + m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "At least one remote directory is not in sync"); + m_statusIcon = &icons.sync; + break; default: m_statusText = QCoreApplication::translate("QtGui::StatusInfo", "Status is unknown"); m_statusIcon = &icons.disconnected;