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
This commit is contained in:
Martchus 2020-12-31 02:48:18 +01:00
parent 392eb70b12
commit da911c6350
8 changed files with 143 additions and 30 deletions

View File

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

View File

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

View File

@ -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.
*/

View File

@ -3,6 +3,8 @@
#include "./global.h"
#include <c++utilities/misc/flagenumclass.h>
#include <QByteArray>
#include <QList>
#include <QSslError>
@ -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<QSslError> 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

View File

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

View File

@ -21,6 +21,7 @@ SyncthingStatusSelectionModel::SyncthingStatusSelectionModel(QObject *parent)
itemFor(SyncthingStatus::Scanning),
itemFor(SyncthingStatus::Paused),
itemFor(SyncthingStatus::Synchronizing),
itemFor(SyncthingStatus::RemoteNotInSync),
});
}

View File

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

View File

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