Compute the sync state for remote devices
See https://github.com/Martchus/syncthingtray/issues/62
This commit is contained in:
parent
6921f9aa89
commit
bafdb22c47
|
@ -10,6 +10,7 @@ set(META_PUBLIC_QT_MODULES Core Network)
|
|||
|
||||
# add project files
|
||||
set(HEADER_FILES
|
||||
syncthingcompletion.h
|
||||
syncthingdir.h
|
||||
syncthingdev.h
|
||||
syncthingconnection.h
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
#ifndef DATA_SYNCTHING_COMPLETION_H
|
||||
#define DATA_SYNCTHING_COMPLETION_H
|
||||
|
||||
#include "./global.h"
|
||||
|
||||
#include <c++utilities/chrono/datetime.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace Data {
|
||||
|
||||
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;
|
||||
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) / globalBytes) * 100.0;
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
||||
#endif // DATA_SYNCTHING_COMPLETION_H
|
|
@ -75,7 +75,7 @@ SyncthingConnection::SyncthingConnection(const QString &syncthingUrl, const QByt
|
|||
, m_keepPolling(false)
|
||||
, m_abortingAllRequests(false)
|
||||
, m_abortingToReconnect(false)
|
||||
, m_requestCompletion(false)
|
||||
, m_requestCompletion(true)
|
||||
, m_lastEventId(0)
|
||||
, m_lastDiskEventId(0)
|
||||
, m_autoReconnectTries(0)
|
||||
|
|
|
@ -268,11 +268,13 @@ private Q_SLOTS:
|
|||
void readItemStarted(CppUtilities::DateTime eventTime, const QJsonObject &eventData);
|
||||
void readItemFinished(CppUtilities::DateTime eventTime, const QJsonObject &eventData);
|
||||
void readFolderErrors(CppUtilities::DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index);
|
||||
void readFolderCompletion(CppUtilities::DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index);
|
||||
void readFolderCompletion(CppUtilities::DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index, const QString &devId);
|
||||
void readFolderCompletion(
|
||||
CppUtilities::DateTime eventTime, const QJsonObject &eventData, const QString &dirId, SyncthingDir *dirInfo, int dirIndex);
|
||||
void readFolderCompletion(CppUtilities::DateTime eventTime, const QJsonObject &eventData, const QString &devId, SyncthingDev *devInfo,
|
||||
int devIndex, const QString &dirId, SyncthingDir *dirInfo, int dirIndex);
|
||||
void readLocalFolderCompletion(CppUtilities::DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index);
|
||||
void readRemoteFolderCompletion(
|
||||
CppUtilities::DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index, const QString &devId);
|
||||
void readRemoteFolderCompletion(CppUtilities::DateTime eventTime, const QJsonObject &eventData, const QString &devId, SyncthingDev *devInfo,
|
||||
int devIndex, const QString &dirId, SyncthingDir *dirInfo, int dirIndex);
|
||||
void readRemoteIndexUpdated(CppUtilities::DateTime eventTime, const QJsonObject &eventData);
|
||||
void readPostConfig();
|
||||
void readRescan();
|
||||
|
|
|
@ -1112,10 +1112,11 @@ void SyncthingConnection::readCompletion()
|
|||
switch (reply->error()) {
|
||||
case QNetworkReply::NoError: {
|
||||
// determine relevant dev/dir
|
||||
int index;
|
||||
auto *const dir = findDirInfo(dirId, index);
|
||||
// discard status for unknown dirs
|
||||
if (!dir) {
|
||||
int devIndex, dirIndex;
|
||||
auto *const devInfo = findDevInfo(devId, devIndex);
|
||||
auto *const dirInfo = findDirInfo(dirId, dirIndex);
|
||||
// discard status if the related dev and dir are unknown
|
||||
if (!devInfo && !dirInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1129,7 +1130,7 @@ void SyncthingConnection::readCompletion()
|
|||
}
|
||||
|
||||
// update the relevant completion info
|
||||
readRemoteFolderCompletion(DateTime::gmtNow(), replyDoc.object(), *dir, index, devId);
|
||||
readRemoteFolderCompletion(DateTime::gmtNow(), replyDoc.object(), devId, devInfo, devIndex, dirId, dirInfo, dirIndex);
|
||||
|
||||
concludeConnection();
|
||||
break;
|
||||
|
@ -1723,6 +1724,10 @@ void SyncthingConnection::readDirEvent(DateTime eventTime, const QString &eventT
|
|||
return eventData.value(QLatin1String("id")).toString();
|
||||
}());
|
||||
if (dirId.isEmpty()) {
|
||||
// handle events which don't necessarily require a corresponding dir info
|
||||
if (eventType == eventType == QLatin1String("FolderCompletion")) {
|
||||
readFolderCompletion(eventTime, eventData, dirId, nullptr, -1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1745,7 +1750,7 @@ void SyncthingConnection::readDirEvent(DateTime eventTime, const QString &eventT
|
|||
} else if (eventType == QLatin1String("FolderSummary")) {
|
||||
readDirSummary(eventTime, eventData.value(QLatin1String("summary")).toObject(), *dirInfo, index);
|
||||
} else if (eventType == QLatin1String("FolderCompletion") && dirInfo->lastStatisticsUpdate < eventTime) {
|
||||
readFolderCompletion(eventTime, eventData, *dirInfo, index);
|
||||
readFolderCompletion(eventTime, eventData, dirId, dirInfo, index);
|
||||
} else if (eventType == QLatin1String("FolderScanProgress")) {
|
||||
const double current = eventData.value(QLatin1String("current")).toDouble(0);
|
||||
const double total = eventData.value(QLatin1String("total")).toDouble(0);
|
||||
|
@ -1800,7 +1805,7 @@ void SyncthingConnection::readDeviceEvent(DateTime eventTime, const QString &eve
|
|||
SyncthingDevStatus status = devInfo->status;
|
||||
bool paused = devInfo->paused;
|
||||
if (eventType == QLatin1String("DeviceConnected")) {
|
||||
status = SyncthingDevStatus::Idle; // TODO: figure out when dev is actually syncing
|
||||
devInfo->setConnectedStateAccordingToCompletion();
|
||||
} else if (eventType == QLatin1String("DeviceDisconnected")) {
|
||||
status = SyncthingDevStatus::Disconnected;
|
||||
} else if (eventType == QLatin1String("DevicePaused")) {
|
||||
|
@ -1929,21 +1934,25 @@ void SyncthingConnection::readFolderErrors(DateTime eventTime, const QJsonObject
|
|||
/*!
|
||||
* \brief Reads results of requestEvents().
|
||||
*/
|
||||
void SyncthingConnection::readFolderCompletion(DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index)
|
||||
void SyncthingConnection::readFolderCompletion(
|
||||
DateTime eventTime, const QJsonObject &eventData, const QString &dirId, SyncthingDir *dirInfo, int dirIndex)
|
||||
{
|
||||
readFolderCompletion(eventTime, eventData, dirInfo, index, eventData.value(QLatin1String("device")).toString());
|
||||
const auto devId = eventData.value(QLatin1String("device")).toString();
|
||||
int devIndex;
|
||||
auto *const devInfo = findDevInfo(devId, devIndex);
|
||||
readFolderCompletion(eventTime, eventData, devId, devInfo, devIndex, dirId, dirInfo, dirIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reads results of requestEvents().
|
||||
*/
|
||||
void SyncthingConnection::readFolderCompletion(
|
||||
DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index, const QString &devId)
|
||||
void SyncthingConnection::readFolderCompletion(DateTime eventTime, const QJsonObject &eventData, const QString &devId, SyncthingDev *devInfo,
|
||||
int devIndex, const QString &dirId, SyncthingDir *dirInfo, int dirIndex)
|
||||
{
|
||||
if (devId.isEmpty() || devId == myId()) {
|
||||
readLocalFolderCompletion(eventTime, eventData, dirInfo, index);
|
||||
} else {
|
||||
readRemoteFolderCompletion(eventTime, eventData, dirInfo, index, devId);
|
||||
if (devInfo && !devId.isEmpty() && devId != myId()) {
|
||||
readRemoteFolderCompletion(eventTime, eventData, devId, devInfo, devIndex, dirId, dirInfo, dirIndex);
|
||||
} else if (dirInfo) {
|
||||
readLocalFolderCompletion(eventTime, eventData, *dirInfo, dirIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1975,27 +1984,44 @@ void SyncthingConnection::readLocalFolderCompletion(DateTime eventTime, const QJ
|
|||
/*!
|
||||
* \brief Reads results of requestEvents().
|
||||
*/
|
||||
void SyncthingConnection::readRemoteFolderCompletion(
|
||||
DateTime eventTime, const QJsonObject &eventData, SyncthingDir &dirInfo, int index, const QString &devId)
|
||||
void SyncthingConnection::readRemoteFolderCompletion(DateTime eventTime, const QJsonObject &eventData, const QString &devId, SyncthingDev *devInfo,
|
||||
int devIndex, const QString &dirId, SyncthingDir *dirInfo, int dirIndex)
|
||||
{
|
||||
auto &completion = dirInfo.completionByDevice[devId];
|
||||
// make new completion
|
||||
auto completion = SyncthingCompletion();
|
||||
auto &needed(completion.needed);
|
||||
const auto previouslyUpdated = !completion.lastUpdate.isNull();
|
||||
const auto previouslyNeeded = !needed.isNull();
|
||||
const auto previousGlobalBytes = completion.globalBytes;
|
||||
completion.lastUpdate = eventTime;
|
||||
completion.percentage = eventData.value(QLatin1String("completion")).toDouble();
|
||||
completion.globalBytes = jsonValueToInt(eventData.value(QLatin1String("globalBytes")));
|
||||
needed.bytes = jsonValueToInt(eventData.value(QLatin1String("needBytes")), needed.bytes);
|
||||
needed.items = jsonValueToInt(eventData.value(QLatin1String("needItems")), needed.items);
|
||||
needed.deletes = jsonValueToInt(eventData.value(QLatin1String("needDeletes")), needed.deletes);
|
||||
emit dirStatusChanged(dirInfo, index);
|
||||
if (needed.isNull() && previouslyUpdated && (previouslyNeeded || previousGlobalBytes != completion.globalBytes)) {
|
||||
int devIndex;
|
||||
if (const auto *const devInfo = findDevInfo(devId, devIndex)) {
|
||||
emit dirCompleted(DateTime::gmtNow(), dirInfo, index, devInfo);
|
||||
|
||||
// update dir info
|
||||
if (dirInfo) {
|
||||
auto &previousCompletion = dirInfo->completionByDevice[devId];
|
||||
const auto previouslyUpdated = !previousCompletion.lastUpdate.isNull();
|
||||
const auto previouslyNeeded = !previousCompletion.needed.isNull();
|
||||
const auto previousGlobalBytes = previousCompletion.globalBytes;
|
||||
previousCompletion = completion;
|
||||
emit dirStatusChanged(*dirInfo, dirIndex);
|
||||
if (devInfo && needed.isNull() && previouslyUpdated && (previouslyNeeded || previousGlobalBytes != completion.globalBytes)) {
|
||||
emit dirCompleted(DateTime::gmtNow(), *dirInfo, dirIndex, devInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// update dev info
|
||||
if (devInfo) {
|
||||
auto &previousCompletion = devInfo->completionByDir[dirId];
|
||||
devInfo->overallCompletion -= previousCompletion;
|
||||
devInfo->overallCompletion += completion;
|
||||
devInfo->overallCompletion.recomputePercentage();
|
||||
previousCompletion = completion;
|
||||
if (devInfo->isConnected()) {
|
||||
devInfo->setConnectedStateAccordingToCompletion();
|
||||
}
|
||||
emit devStatusChanged(*devInfo, devIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -2011,22 +2037,25 @@ void SyncthingConnection::readRemoteIndexUpdated(DateTime eventTime, const QJson
|
|||
// find dev/dir
|
||||
const auto devId(eventData.value(QLatin1String("device")).toString());
|
||||
const auto dirId(eventData.value(QLatin1String("folder")).toString());
|
||||
if (dirId.isEmpty()) {
|
||||
if (devId.isEmpty() || dirId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int index;
|
||||
auto *const dirInfo = findDirInfo(dirId, index);
|
||||
if (!dirInfo) {
|
||||
int devIndex, dirIndex;
|
||||
auto *const devInfo = findDevInfo(devId, devIndex);
|
||||
auto *const dirInfo = findDirInfo(dirId, dirIndex);
|
||||
|
||||
// discard if the related dev and dir are unknown
|
||||
if (!devInfo && !dirInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore event if we don't share the directory with the device
|
||||
if (!dirInfo->deviceIds.contains(devId)) {
|
||||
// ignore event if we don't know the device and if we don't share the directory with the device
|
||||
if (!devInfo && !dirInfo->deviceIds.contains(devId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// request completion again if out-of-date
|
||||
const auto &completion = dirInfo->completionByDevice[devId];
|
||||
const auto &completion = dirInfo ? dirInfo->completionByDevice[devId] : devInfo->completionByDir[dirId];
|
||||
if (completion.lastUpdate < eventTime) {
|
||||
requestCompletion(devId, dirId);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef DATA_SYNCTHINGDEV_H
|
||||
#define DATA_SYNCTHINGDEV_H
|
||||
|
||||
#include "./global.h"
|
||||
#include "./syncthingcompletion.h"
|
||||
|
||||
#include <c++utilities/chrono/datetime.h>
|
||||
|
||||
|
@ -19,9 +19,10 @@ enum class SyncthingDevStatus { Unknown, Disconnected, OwnDevice, Idle, Synchron
|
|||
QString statusString(SyncthingDevStatus status);
|
||||
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDev {
|
||||
SyncthingDev(const QString &id = QString(), const QString &name = QString());
|
||||
explicit SyncthingDev(const QString &id = QString(), const QString &name = QString());
|
||||
QString statusString() const;
|
||||
bool isConnected() const;
|
||||
void setConnectedStateAccordingToCompletion();
|
||||
const QString displayName() const;
|
||||
|
||||
QString id;
|
||||
|
@ -30,16 +31,16 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDev {
|
|||
QString compression;
|
||||
QString certName;
|
||||
SyncthingDevStatus status = SyncthingDevStatus::Unknown;
|
||||
int progressPercentage = 0;
|
||||
int progressRate = 0;
|
||||
bool introducer = false;
|
||||
bool paused = false;
|
||||
std::uint64_t totalIncomingTraffic = 0;
|
||||
std::uint64_t totalOutgoingTraffic = 0;
|
||||
QString connectionAddress;
|
||||
QString connectionType;
|
||||
QString clientVersion;
|
||||
CppUtilities::DateTime lastSeen;
|
||||
std::unordered_map<QString, SyncthingCompletion> completionByDir;
|
||||
SyncthingCompletion overallCompletion;
|
||||
bool introducer = false;
|
||||
bool paused = false;
|
||||
};
|
||||
|
||||
inline SyncthingDev::SyncthingDev(const QString &id, const QString &name)
|
||||
|
@ -54,12 +55,18 @@ inline bool SyncthingDev::isConnected() const
|
|||
case SyncthingDevStatus::Unknown:
|
||||
case SyncthingDevStatus::Disconnected:
|
||||
case SyncthingDevStatus::OwnDevice:
|
||||
case SyncthingDevStatus::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SyncthingDev::setConnectedStateAccordingToCompletion()
|
||||
{
|
||||
status = overallCompletion.needed.isNull() ? SyncthingDevStatus::Idle : SyncthingDevStatus::Synchronizing;
|
||||
}
|
||||
|
||||
inline const QString SyncthingDev::displayName() const
|
||||
{
|
||||
return name.isEmpty() ? id : name;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef DATA_SYNCTHINGDIR_H
|
||||
#define DATA_SYNCTHINGDIR_H
|
||||
|
||||
#include "./global.h"
|
||||
#include "./syncthingcompletion.h"
|
||||
|
||||
#include <c++utilities/chrono/datetime.h>
|
||||
|
||||
|
@ -23,7 +23,7 @@ enum class SyncthingDirType { Unknown, SendReceive, SendOnly, ReceiveOnly };
|
|||
LIB_SYNCTHING_CONNECTOR_EXPORT QString dirTypeString(SyncthingDirType dirType);
|
||||
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItemError {
|
||||
SyncthingItemError(const QString &message = QString(), const QString &path = QString())
|
||||
explicit SyncthingItemError(const QString &message = QString(), const QString &path = QString())
|
||||
: message(message)
|
||||
, path(path)
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingFileChange {
|
|||
};
|
||||
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItemDownloadProgress {
|
||||
SyncthingItemDownloadProgress(
|
||||
explicit SyncthingItemDownloadProgress(
|
||||
const QString &containingDirPath = QString(), const QString &relativeItemPath = QString(), const QJsonObject &values = QJsonObject());
|
||||
QString relativePath;
|
||||
QFileInfo fileInfo;
|
||||
|
@ -66,35 +66,6 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItemDownloadProgress {
|
|||
static constexpr unsigned int syncthingBlockSize = 128 * 1024;
|
||||
};
|
||||
|
||||
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;
|
||||
} needed;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingStatistics {
|
||||
Q_GADGET
|
||||
Q_PROPERTY(quint64 bytes MEMBER bytes)
|
||||
|
@ -132,7 +103,7 @@ constexpr bool SyncthingStatistics::operator!=(const SyncthingStatistics &other)
|
|||
}
|
||||
|
||||
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingDir {
|
||||
SyncthingDir(const QString &id = QString(), const QString &label = QString(), const QString &path = QString());
|
||||
explicit SyncthingDir(const QString &id = QString(), const QString &label = QString(), const QString &path = QString());
|
||||
bool assignStatus(const QString &statusStr, CppUtilities::DateTime time);
|
||||
bool assignStatus(SyncthingDirStatus newStatus, CppUtilities::DateTime time);
|
||||
bool assignDirType(const QString &dirType);
|
||||
|
@ -231,8 +202,8 @@ struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingOverallDirStatistics {
|
|||
Q_PROPERTY(SyncthingStatistics needed MEMBER needed)
|
||||
|
||||
public:
|
||||
SyncthingOverallDirStatistics();
|
||||
SyncthingOverallDirStatistics(const std::vector<SyncthingDir> &directories);
|
||||
explicit SyncthingOverallDirStatistics();
|
||||
explicit SyncthingOverallDirStatistics(const std::vector<SyncthingDir> &directories);
|
||||
|
||||
SyncthingStatistics local;
|
||||
SyncthingStatistics global;
|
||||
|
|
Loading…
Reference in New Issue