syncthingtray/syncthingconnector/syncthingcompletion.h
Martchus 843f164df1 Avoid potentially losing events
I have observed that Syncthing Tray can get stuck thinking a remote device
still needs data. Likely the update got lost. The code contains certain
conditions in which folder completion events and requesting completion are
supressed. Those conditions are based on timestamps. That is not ideal as
the accuracy is only one second (so different timestamps might be
considered equal as they are rounded to be the same). Additionally, it
makes no sense to assume a timestamp upon receiving a response as the
information might be older than the time it was received.

This change avoids those conditions. It rather uses the event ID to
decide what event/reply is newer.

This change also uses quint64 instead of int for event IDs to avoid running
into an overflow (or rather conversion error) when deserializing the ID
which might be bigger than int. (Not sure how big the ID can become; this
is to be on the safe side.)
2023-04-15 16:18:23 +02:00

88 lines
2.5 KiB
C++

#ifndef DATA_SYNCTHING_COMPLETION_H
#define DATA_SYNCTHING_COMPLETION_H
#include "./global.h"
#include <c++utilities/chrono/datetime.h>
#include <QtGlobal>
namespace Data {
using SyncthingEventId = quint64;
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingCompletion {
CppUtilities::DateTime lastUpdate;
double percentage = 0;
quint64 globalBytes = 0;
struct Needed {
quint64 bytes = 0;
quint64 items = 0;
quint64 deletes = 0;
constexpr bool isNull() const;
constexpr bool operator==(const Needed &other) const;
constexpr bool operator!=(const Needed &other) const;
constexpr Needed &operator+=(const Needed &other);
constexpr Needed &operator-=(const Needed &other);
} needed;
SyncthingEventId requestedForEventId = 0;
constexpr SyncthingCompletion &operator+=(const SyncthingCompletion &other);
constexpr SyncthingCompletion &operator-=(const SyncthingCompletion &other);
void recomputePercentage();
};
constexpr bool SyncthingCompletion::Needed::isNull() const
{
return bytes == 0 && items == 0 && deletes == 0;
}
constexpr bool SyncthingCompletion::Needed::operator==(const SyncthingCompletion::Needed &other) const
{
return bytes == other.bytes && items == other.items && deletes == other.deletes;
}
constexpr bool SyncthingCompletion::Needed::operator!=(const SyncthingCompletion::Needed &other) const
{
return !(*this == other);
}
constexpr SyncthingCompletion::Needed &SyncthingCompletion::Needed::operator+=(const SyncthingCompletion::Needed &other)
{
bytes += other.bytes;
items += other.items;
deletes += other.deletes;
return *this;
}
constexpr SyncthingCompletion::Needed &SyncthingCompletion::Needed::operator-=(const SyncthingCompletion::Needed &other)
{
bytes -= other.bytes;
items -= other.items;
deletes -= other.deletes;
return *this;
}
constexpr SyncthingCompletion &SyncthingCompletion::operator+=(const SyncthingCompletion &other)
{
lastUpdate = std::max(lastUpdate, other.lastUpdate);
globalBytes += other.globalBytes;
needed += other.needed;
return *this;
}
constexpr SyncthingCompletion &SyncthingCompletion::operator-=(const SyncthingCompletion &other)
{
globalBytes -= other.globalBytes;
needed -= other.needed;
return *this;
}
inline void SyncthingCompletion::recomputePercentage()
{
percentage = (static_cast<double>(globalBytes - needed.bytes) / static_cast<double>(globalBytes)) * 100.0;
}
} // namespace Data
#endif // DATA_SYNCTHING_COMPLETION_H