syncthingtray/syncthingconnector/syncthingconnection.h

1063 lines
40 KiB
C
Raw Normal View History

2016-08-25 00:45:32 +02:00
#ifndef SYNCTHINGCONNECTION_H
#define SYNCTHINGCONNECTION_H
#include "./syncthingconnectionenums.h"
2020-03-17 18:56:59 +01:00
#include "./syncthingconnectionstatus.h"
#include "./syncthingdev.h"
2017-05-01 03:34:43 +02:00
#include "./syncthingdir.h"
#include "./utils.h"
2016-08-30 20:01:07 +02:00
#include <c++utilities/misc/flagenumclass.h>
#include <QByteArray>
#include <QDateTime>
2017-05-01 03:34:43 +02:00
#include <QJsonObject>
2016-09-01 16:34:30 +02:00
#include <QList>
#include <QNetworkRequest>
2017-05-01 03:34:43 +02:00
#include <QObject>
2016-09-01 16:34:30 +02:00
#include <QSslError>
2016-10-07 15:11:25 +02:00
#include <QTimer>
2016-08-25 00:45:32 +02:00
#include <cstdint>
2016-08-25 00:45:32 +02:00
#include <functional>
#include <limits>
2017-05-01 03:34:43 +02:00
#include <vector>
2016-08-25 00:45:32 +02:00
QT_FORWARD_DECLARE_CLASS(QNetworkAccessManager)
QT_FORWARD_DECLARE_CLASS(QNetworkReply)
QT_FORWARD_DECLARE_CLASS(QUrlQuery)
QT_FORWARD_DECLARE_CLASS(QJsonObject)
QT_FORWARD_DECLARE_CLASS(QJsonArray)
QT_FORWARD_DECLARE_CLASS(QJsonParseError)
2016-08-25 00:45:32 +02:00
2017-07-02 21:47:59 +02:00
class ConnectionTests;
class MiscTests;
2017-07-02 21:47:59 +02:00
2016-08-25 00:45:32 +02:00
namespace Data {
struct SyncthingConnectionSettings;
LIB_SYNCTHING_CONNECTOR_EXPORT QNetworkAccessManager &networkAccessManager();
2016-08-25 00:45:32 +02:00
2017-05-01 03:34:43 +02:00
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingLogEntry {
SyncthingLogEntry(const QString &when = QString(), const QString &message = QString())
: when(when)
, message(message)
{
}
2016-08-25 00:45:32 +02:00
QString when;
QString message;
};
enum class SyncthingItemType {
Unknown, /**< the type is unknown */
File, /**< the item is a regular file */
Directory, /**< the item is a directory */
Symlink, /**< the item is a symlink (pointing to a file or directory) */
Error, /**< the item represents an error message (e.g. the API query ran into an error); used by SyncthingFileModel */
Loading, /**< the item represents a loading indication; used by SyncthingFileModel */
};
2024-04-01 18:57:18 +02:00
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingItem {
/// \brief The name of the filesystem item or error/loading message in case of those item types.
2024-04-01 18:57:18 +02:00
QString name;
/// \brief The modification time. Only populated with a meaningful value for files and directories.
2024-04-07 23:29:23 +02:00
CppUtilities::DateTime modificationTime = CppUtilities::DateTime();
/// \brief The file size. Only populated with a meaningful value for files.
2024-04-01 18:57:18 +02:00
std::size_t size = std::size_t();
/// \brief The type of the item.
2024-04-01 18:57:18 +02:00
SyncthingItemType type = SyncthingItemType::Unknown;
/// \brief The child items, if populated as indicated by childrenPopulated.
2024-04-07 23:29:23 +02:00
std::vector<std::unique_ptr<SyncthingItem>> children;
/// \brief The parent item; not populated by default but might be set as needed (take care in case the pointer gets invalidated).
SyncthingItem *parent = nullptr;
/// \brief The path of the item; not populated by default but might be set as needed.
QString path;
/// \brief The index of the item within its parent.
2024-04-01 18:57:18 +02:00
std::size_t index = std::size_t();
/// \brief The level of nesting, does *not* include levels of the prefix.
int level = 0;
/// \brief Whether children are populated (depends on the requested level).
bool childrenPopulated = false;
/// \brief Whether the item is "checked"; not set by default but might be set to flag an item for some mass-action.
bool checked = false;
bool isFilesystemItem() const;
2024-04-01 18:57:18 +02:00
};
/// \brief Returns whether the item is actually a filesystem item.
inline bool SyncthingItem::isFilesystemItem() const
{
switch (type) {
case Data::SyncthingItemType::File:
case Data::SyncthingItemType::Directory:
case Data::SyncthingItemType::Symlink:
return true;
default:
return false;
}
}
2024-05-04 23:00:13 +02:00
struct LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingIgnores {
QStringList ignore;
QStringList expanded;
};
2017-05-01 03:34:43 +02:00
class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnection : public QObject {
2017-07-02 21:47:59 +02:00
friend ConnectionTests;
friend MiscTests;
2017-07-02 21:47:59 +02:00
2016-08-25 00:45:32 +02:00
Q_OBJECT
Q_PROPERTY(QString syncthingUrl READ syncthingUrl WRITE setSyncthingUrl)
Q_PROPERTY(QByteArray apiKey READ apiKey WRITE setApiKey)
2017-09-08 16:47:44 +02:00
Q_PROPERTY(bool isLocal READ isLocal)
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(Data::SyncthingConnectionLoggingFlags loggingFlags READ loggingFlags WRITE setLoggingFlags)
Q_PROPERTY(QString statusText READ statusText NOTIFY statusChanged)
Q_PROPERTY(bool connected READ isConnected NOTIFY statusChanged)
Q_PROPERTY(bool connecting READ isConnecting NOTIFY statusChanged)
Q_PROPERTY(bool aborted READ isAborted NOTIFY statusChanged)
2016-10-04 23:42:17 +02:00
Q_PROPERTY(bool hasUnreadNotifications READ hasUnreadNotifications)
Q_PROPERTY(bool hasOutOfSyncDirs READ hasOutOfSyncDirs)
2018-01-24 21:46:18 +01:00
Q_PROPERTY(bool requestingCompletionEnabled READ isRequestingCompletionEnabled WRITE setRequestingCompletionEnabled)
Q_PROPERTY(int autoReconnectInterval READ autoReconnectInterval WRITE setAutoReconnectInterval)
Q_PROPERTY(unsigned int autoReconnectTries READ autoReconnectTries)
2016-09-25 20:54:09 +02:00
Q_PROPERTY(int trafficPollInterval READ trafficPollInterval WRITE setTrafficPollInterval)
Q_PROPERTY(int devStatsPollInterval READ devStatsPollInterval WRITE setDevStatsPollInterval)
Q_PROPERTY(bool recordFileChanges READ recordFileChanges WRITE setRecordFileChanges)
Q_PROPERTY(int requestTimeout READ requestTimeout WRITE setRequestTimeout)
2023-11-06 15:06:40 +01:00
Q_PROPERTY(int longPollingTimeout READ longPollingTimeout WRITE setLongPollingTimeout)
2016-08-25 00:45:32 +02:00
Q_PROPERTY(QString myId READ myId NOTIFY myIdChanged)
Q_PROPERTY(QString tilde READ tilde NOTIFY tildeChanged)
Q_PROPERTY(QString pathSeparator READ pathSeparator NOTIFY tildeChanged)
Q_PROPERTY(QString configDir READ configDir NOTIFY configDirChanged)
2021-03-20 22:39:40 +01:00
Q_PROPERTY(quint64 totalIncomingTraffic READ totalIncomingTraffic NOTIFY trafficChanged)
Q_PROPERTY(quint64 totalOutgoingTraffic READ totalOutgoingTraffic NOTIFY trafficChanged)
2016-09-25 20:54:09 +02:00
Q_PROPERTY(double totalIncomingRate READ totalIncomingRate NOTIFY trafficChanged)
Q_PROPERTY(double totalOutgoingRate READ totalOutgoingRate NOTIFY trafficChanged)
2018-07-30 23:00:22 +02:00
Q_PROPERTY(QString lastSyncedFile READ lastSyncedFile)
2018-07-30 23:00:40 +02:00
Q_PROPERTY(QString syncthingVersion READ syncthingVersion)
2019-06-10 22:48:26 +02:00
Q_PROPERTY(CppUtilities::DateTime lastSyncTime READ lastSyncTime)
Q_PROPERTY(QList<QSslError> expectedSslErrors READ expectedSslErrors)
Q_PROPERTY(std::vector<const SyncthingDev *> connectedDevices READ connectedDevices)
Q_PROPERTY(QStringList directoryIds READ directoryIds)
Q_PROPERTY(QStringList deviceIds READ deviceIds)
2018-04-01 22:34:59 +02:00
Q_PROPERTY(QJsonObject rawConfig READ rawConfig NOTIFY newConfig)
Q_PROPERTY(bool useDeprecatedRoutes READ isUsingDeprecatedRoutes WRITE setUseDeprecatedRoutes)
Q_PROPERTY(bool pausingOnMeteredConnection READ isPausingOnMeteredConnection WRITE setPausingOnMeteredConnection)
2016-08-25 00:45:32 +02:00
public:
explicit SyncthingConnection(const QString &syncthingUrl = QStringLiteral("http://localhost:8080"), const QByteArray &apiKey = QByteArray(),
SyncthingConnectionLoggingFlags loggingFlags = SyncthingConnectionLoggingFlags::FromEnvironment, QObject *parent = nullptr);
2018-10-10 21:26:46 +02:00
~SyncthingConnection() override;
2016-08-25 00:45:32 +02:00
struct QueryResult {
QNetworkReply *reply = nullptr;
QMetaObject::Connection connection;
};
// getter/setter for
2016-08-25 00:45:32 +02:00
const QString &syncthingUrl() const;
void setSyncthingUrl(const QString &url);
2017-09-08 16:47:44 +02:00
bool isLocal() const;
2016-08-25 00:45:32 +02:00
const QByteArray &apiKey() const;
void setApiKey(const QByteArray &apiKey);
const QString &user() const;
const QString &password() const;
void setCredentials(const QString &user, const QString &password);
bool isUsingDeprecatedRoutes() const;
void setUseDeprecatedRoutes(bool useLegacyRoutes);
// getter for the status of the connection to Syncthing and of Syncthing itself
2016-08-25 00:45:32 +02:00
SyncthingStatus status() const;
QString statusText() const;
static QString statusText(SyncthingStatus status);
SyncthingStatusComputionFlags statusComputionFlags() const;
void setStatusComputionFlags(SyncthingStatusComputionFlags flags);
SyncthingConnectionLoggingFlags loggingFlags() const;
void setLoggingFlags(SyncthingConnectionLoggingFlags flags);
2016-08-25 00:45:32 +02:00
bool isConnected() const;
bool isAborted() const;
bool isConnecting() const;
bool hasPendingRequests() const;
bool hasPendingRequestsIncludingEvents() const;
2016-10-04 23:42:17 +02:00
bool hasUnreadNotifications() const;
bool hasOutOfSyncDirs() const;
// getter/setter to configure connection behavior
2018-01-24 21:46:18 +01:00
bool isRequestingCompletionEnabled() const;
void setRequestingCompletionEnabled(bool requestingCompletionEnabled);
2016-09-25 20:54:09 +02:00
int trafficPollInterval() const;
void setTrafficPollInterval(int trafficPollInterval);
int devStatsPollInterval() const;
void setDevStatsPollInterval(int devStatsPollInterval);
2017-01-12 22:38:36 +01:00
int errorsPollInterval() const;
void setErrorsPollInterval(int errorsPollInterval);
int autoReconnectInterval() const;
unsigned int autoReconnectTries() const;
void setAutoReconnectInterval(int interval);
void disablePolling();
bool recordFileChanges() const;
void setRecordFileChanges(bool recordFileChanges);
int requestTimeout() const;
void setRequestTimeout(int requestTimeout);
2023-11-06 15:06:40 +01:00
int longPollingTimeout() const;
void setLongPollingTimeout(int longPollingTimeout);
bool isPausingOnMeteredConnection() const;
void setPausingOnMeteredConnection(bool pausingOnMeteredConnection);
// getter for information retrieved from Syncthing
2016-08-25 00:45:32 +02:00
const QString &configDir() const;
const QString &myId() const;
const QString &tilde() const;
const QString &pathSeparator() const;
2019-03-13 19:12:23 +01:00
std::uint64_t totalIncomingTraffic() const;
std::uint64_t totalOutgoingTraffic() const;
2016-08-30 20:01:07 +02:00
double totalIncomingRate() const;
double totalOutgoingRate() const;
2019-03-13 19:12:23 +01:00
static constexpr std::uint64_t unknownTraffic = std::numeric_limits<std::uint64_t>::max();
2016-08-25 00:45:32 +02:00
const std::vector<SyncthingDir> &dirInfo() const;
const std::vector<SyncthingDev> &devInfo() const;
2018-07-30 23:00:22 +02:00
SyncthingOverallDirStatistics computeOverallDirStatistics() const;
const QString &lastSyncedFile() const;
2019-06-10 22:48:26 +02:00
CppUtilities::DateTime lastSyncTime() const;
CppUtilities::DateTime startTime() const;
CppUtilities::TimeSpan uptime() const;
2018-07-30 23:00:40 +02:00
const QString &syncthingVersion() const;
2017-02-22 18:16:41 +01:00
QStringList directoryIds() const;
QStringList deviceIds() const;
2018-01-25 00:03:31 +01:00
QString deviceNameOrId(const QString &deviceId) const;
std::vector<const SyncthingDev *> connectedDevices() const;
2018-04-01 20:21:51 +02:00
const QJsonObject &rawConfig() const;
SyncthingDir *findDirInfo(const QString &dirId, int &row);
SyncthingDir *findDirInfoConsideringLabels(const QString &dirIdOrLabel, int &row);
const SyncthingDir *findDirInfo(const QString &dirId, int &row) const;
SyncthingDir *findDirInfo(QLatin1String key, const QJsonObject &object, int *row = nullptr);
SyncthingDir *findDirInfoByPath(const QString &path, QString &relativePath, int &row);
SyncthingDev *findDevInfo(const QString &devId, int &row);
const SyncthingDev *findDevInfo(const QString &devId, int &row) const;
SyncthingDev *findDevInfoByName(const QString &devName, int &row);
const QList<QSslError> &expectedSslErrors() const;
2016-08-25 00:45:32 +02:00
public Q_SLOTS:
bool loadSelfSignedCertificate(const QUrl &url = QUrl());
void clearSelfSignedCertificate();
bool applySettings(Data::SyncthingConnectionSettings &connectionSettings);
// methods to initiate/close connection
2016-08-25 00:45:32 +02:00
void connect();
void connect(Data::SyncthingConnectionSettings &connectionSettings);
void connectLater(int milliSeconds);
2016-08-25 00:45:32 +02:00
void disconnect();
void reconnect();
void reconnect(Data::SyncthingConnectionSettings &connectionSettings);
void reconnectLater(int milliSeconds);
void abortAllRequests();
// methods to trigger certain actions (resume, rescan, restart, ...)
bool pauseDevice(const QStringList &devIds);
bool pauseAllDevs();
bool resumeDevice(const QStringList &devIds);
bool resumeAllDevs();
bool pauseDirectories(const QStringList &dirIds);
bool pauseAllDirs();
bool resumeDirectories(const QStringList &dirIds);
bool resumeAllDirs();
2017-02-20 17:52:10 +01:00
void rescan(const QString &dirId, const QString &relpath = QString());
2016-08-25 00:45:32 +02:00
void rescanAllDirs();
2016-09-03 19:39:43 +02:00
void restart();
2016-10-02 22:16:43 +02:00
void shutdown();
2016-09-27 21:20:17 +02:00
void considerAllNotificationsRead();
2016-08-25 00:45:32 +02:00
// methods to GET or POST information from/to Syncthing
void requestConfig();
void requestStatus();
void requestConfigAndStatus();
void requestEvents();
void requestErrors();
void requestConnections();
void requestClearingErrors();
void requestDirStatistics();
void requestDirStatus(const QString &dirId);
void requestDirPullErrors(const QString &dirId, int page = 0, int perPage = 0);
void requestCompletion(const QString &devId, const QString &dirId);
void requestDeviceStatistics();
2018-07-30 23:00:40 +02:00
void requestVersion();
void requestDiskEvents(int limit = 25);
void requestQrCode(const QString &text);
void requestLog();
void requestOverride(const QString &dirId);
void requestRevert(const QString &dirId);
void postConfigFromJsonObject(const QJsonObject &rawConfig);
void postConfigFromByteArray(const QByteArray &rawConfig);
2024-04-01 18:57:18 +02:00
public:
// methods to GET or POST information from/to Syncthing (non-slots)
QueryResult browse(const QString &dirId, const QString &prefix, int level,
2024-04-07 23:29:23 +02:00
std::function<void(std::vector<std::unique_ptr<SyncthingItem>> &&, QString &&)> &&callback);
QueryResult ignores(const QString &dirId, std::function<void(SyncthingIgnores &&, QString &&)> &&callback);
QueryResult setIgnores(const QString &dirId, const SyncthingIgnores &ignores, std::function<void(QString &&)> &&callback);
2024-04-01 18:57:18 +02:00
2016-08-25 00:45:32 +02:00
Q_SIGNALS:
2018-04-01 22:34:59 +02:00
void newConfig(const QJsonObject &rawConfig);
2016-08-25 00:45:32 +02:00
void newDirs(const std::vector<SyncthingDir> &dirs);
void newDevices(const std::vector<SyncthingDev> &devs);
void newConfigApplied();
2016-08-25 00:45:32 +02:00
void newEvents(const QJsonArray &events);
void allEventsProcessed();
void dirStatusChanged(const Data::SyncthingDir &dir, int index);
void devStatusChanged(const Data::SyncthingDev &dev, int index);
void fileChanged(const Data::SyncthingDir &dir, int index, const Data::SyncthingFileChange &fileChange);
2016-09-21 21:09:12 +02:00
void downloadProgressChanged();
2019-02-17 23:45:53 +01:00
void dirStatisticsChanged();
void dirCompleted(CppUtilities::DateTime when, const Data::SyncthingDir &dir, int index, const Data::SyncthingDev *remoteDev = nullptr);
2019-06-10 22:48:26 +02:00
void newNotification(CppUtilities::DateTime when, const QString &message);
void newDevAvailable(CppUtilities::DateTime when, const QString &devId, const QString &address);
void newDirAvailable(
CppUtilities::DateTime when, const QString &devId, const Data::SyncthingDev *dev, const QString &dirId, const QString &dirLabel);
void error(const QString &errorMessage, Data::SyncthingErrorCategory category, int networkError,
const QNetworkRequest &request = QNetworkRequest(), const QByteArray &response = QByteArray());
void statusChanged(Data::SyncthingStatus newStatus);
2016-08-25 00:45:32 +02:00
void configDirChanged(const QString &newConfigDir);
void myIdChanged(const QString &myNewId);
void tildeChanged(const QString &tilde);
2019-03-13 19:12:23 +01:00
void trafficChanged(std::uint64_t totalIncomingTraffic, std::uint64_t totalOutgoingTraffic);
2018-04-01 22:34:59 +02:00
void newConfigTriggered();
2016-10-02 21:59:28 +02:00
void rescanTriggered(const QString &dirId);
void devicePauseTriggered(const QStringList &devIds);
void deviceResumeTriggered(const QStringList &devIds);
2017-02-22 18:16:41 +01:00
void directoryPauseTriggered(const QStringList &dirIds);
void directoryResumeTriggered(const QStringList &dirIds);
2016-10-02 21:59:28 +02:00
void restartTriggered();
2016-10-02 22:16:43 +02:00
void shutdownTriggered();
void logAvailable(const std::vector<SyncthingLogEntry> &logEntries);
void qrCodeAvailable(const QString &text, const QByteArray &qrCodeData);
void overrideTriggered(const QString &dirId);
void revertTriggered(const QString &dirId);
2016-08-29 20:51:30 +02:00
2016-08-25 00:45:32 +02:00
private Q_SLOTS:
// handler to evaluate results from request...() methods
2016-08-25 00:45:32 +02:00
void readConfig();
void readDirs(const QJsonArray &dirs);
void readDevs(const QJsonArray &devs);
void readStatus();
void concludeReadingConfigAndStatus();
void concludeConnection();
2016-08-26 16:43:53 +02:00
void readConnections();
2016-09-01 16:34:30 +02:00
void readDirStatistics();
void readDeviceStatistics();
void readErrors();
void readClearingErrors();
2016-08-25 00:45:32 +02:00
void readEvents();
2023-04-15 22:05:06 +02:00
bool readEventsFromJsonArray(const QJsonArray &events, quint64 &idVariable);
2016-08-26 16:43:53 +02:00
void readStartingEvent(const QJsonObject &eventData);
void readStatusChangedEvent(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData);
void readDownloadProgressEvent(const QJsonObject &eventData);
void readDirEvent(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QString &eventType, const QJsonObject &eventData);
void readDeviceEvent(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QString &eventType, const QJsonObject &eventData);
void readItemStarted(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData);
void readItemFinished(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData);
void readFolderErrors(
SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData, Data::SyncthingDir &dirInfo, int index);
void readFolderCompletion(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData, const QString &dirId,
Data::SyncthingDir *dirInfo, int dirIndex);
void readFolderCompletion(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData, const QString &devId,
Data::SyncthingDev *devInfo, int devIndex, const QString &dirId, Data::SyncthingDir *dirInfo, int dirIndex);
void readLocalFolderCompletion(
SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData, Data::SyncthingDir &dirInfo, int index);
void readRemoteFolderCompletion(CppUtilities::DateTime eventTime, const QJsonObject &eventData, const QString &devId, Data::SyncthingDev *devInfo,
int devIndex, const QString &dirId, Data::SyncthingDir *dirInfo, int dirIndex);
void readRemoteFolderCompletion(const Data::SyncthingCompletion &completion, const QString &devId, Data::SyncthingDev *devInfo, int devIndex,
const QString &dirId, Data::SyncthingDir *dirInfo, int dirIndex);
void readRemoteIndexUpdated(SyncthingEventId eventId, const QJsonObject &eventData);
2018-04-01 22:34:59 +02:00
void readPostConfig();
2016-08-25 00:45:32 +02:00
void readRescan();
2017-02-22 18:16:41 +01:00
void readDevPauseResume();
void readDirPauseResume();
2016-09-03 19:39:43 +02:00
void readRestart();
2016-10-02 22:16:43 +02:00
void readShutdown();
void readDirStatus();
void readDirPullErrors();
void readDirSummary(
SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &summary, Data::SyncthingDir &dirInfo, int index);
2019-06-10 22:48:26 +02:00
void readDirRejected(CppUtilities::DateTime eventTime, const QString &dirId, const QJsonObject &eventData);
void readDevRejected(CppUtilities::DateTime eventTime, const QString &devId, const QJsonObject &eventData);
2018-01-24 21:46:18 +01:00
void readCompletion();
2018-07-30 23:00:40 +02:00
void readVersion();
void readDiskEvents();
2019-06-10 22:48:26 +02:00
void readChangeEvent(CppUtilities::DateTime eventTime, const QString &eventType, const QJsonObject &eventData);
void readLog();
void readQrCode();
void readOverride();
void readRevert();
2016-08-25 00:45:32 +02:00
// internal helper methods
void continueConnecting();
void continueReconnecting();
void autoReconnect();
void setStatus(Data::SyncthingStatus status);
2019-06-10 22:48:26 +02:00
void emitNotification(CppUtilities::DateTime when, const QString &message);
void emitError(const QString &message, const QJsonParseError &jsonError, QNetworkReply *reply, const QByteArray &response = QByteArray());
void emitError(const QString &message, Data::SyncthingErrorCategory category, QNetworkReply *reply);
void emitError(const QString &message, QNetworkReply *reply);
void emitMyIdChanged(const QString &newId);
void emitTildeChanged(const QString &newTilde, const QString &newPathSeparator);
2019-02-17 23:45:53 +01:00
void emitDirStatisticsChanged();
void handleFatalConnectionError();
void handleAdditionalRequestCanceled();
void handleSslErrors(const QList<QSslError> &errors);
void handleRedirection(const QUrl &url);
void handleMeteredConnection();
void recalculateStatus();
2016-08-25 00:45:32 +02:00
private:
2024-04-01 18:57:18 +02:00
// handler to evaluate results from request...() methods
2024-04-07 23:29:23 +02:00
void readBrowse(const QString &dirId, int levels, std::function<void(std::vector<std::unique_ptr<SyncthingItem>> &&, QString &&)> &&callback);
2024-05-04 23:00:13 +02:00
void readIgnores(const QString &dirId, std::function<void(SyncthingIgnores &&, QString &&)> &&callback);
2024-05-04 23:12:53 +02:00
void readSetIgnores(const QString &dirId, std::function<void(QString &&)> &&callback);
2024-04-01 18:57:18 +02:00
// internal helper methods
struct Reply {
QNetworkReply *reply;
QByteArray response;
};
2023-11-06 15:06:40 +01:00
QNetworkRequest prepareRequest(const QString &path, const QUrlQuery &query, bool rest = true, bool longPolling = false);
QNetworkReply *requestData(const QString &path, const QUrlQuery &query, bool rest = true, bool longPolling = false);
2016-08-25 00:45:32 +02:00
QNetworkReply *postData(const QString &path, const QUrlQuery &query, const QByteArray &data = QByteArray());
QNetworkReply *sendData(const QByteArray &verb, const QString &path, const QUrlQuery &query, const QByteArray &data = QByteArray());
Reply prepareReply(bool readData = true, bool handleAborting = true);
Reply prepareReply(QNetworkReply *&expectedReply, bool readData = true, bool handleAborting = true);
Reply prepareReply(QList<QNetworkReply *> &expectedReplies, bool readData = true, bool handleAborting = true);
Reply handleReply(QNetworkReply *reply, bool readData, bool handleAborting);
bool pauseResumeDevice(const QStringList &devIds, bool paused, bool dueToMetered = false);
bool pauseResumeDirectory(const QStringList &dirIds, bool paused);
2016-11-01 17:06:31 +01:00
SyncthingDir *addDirInfo(std::vector<SyncthingDir> &dirs, const QString &dirId);
SyncthingDev *addDevInfo(std::vector<SyncthingDev> &devs, const QString &devId);
2021-05-27 18:16:56 +02:00
CppUtilities::DateTime parseTimeStamp(const QJsonValue &jsonValue, const QString &context,
CppUtilities::DateTime defaultValue = CppUtilities::DateTime(), bool greaterThanEpoch = false);
QString configPath() const;
QByteArray changeConfigVerb() const;
QString folderErrorsPath() const;
2016-08-25 00:45:32 +02:00
QString m_syncthingUrl;
QByteArray m_apiKey;
QString m_user;
QString m_password;
SyncthingStatus m_status;
SyncthingStatusComputionFlags m_statusComputionFlags;
SyncthingConnectionLoggingFlags m_loggingFlags;
SyncthingConnectionLoggingFlags m_loggingFlagsHandler;
2016-08-25 00:45:32 +02:00
bool m_keepPolling;
bool m_abortingAllRequests;
bool m_connectionAborted;
bool m_abortingToReconnect;
2018-01-24 21:46:18 +01:00
bool m_requestCompletion;
SyncthingEventId m_lastEventId;
SyncthingEventId m_lastDiskEventId;
QTimer m_trafficPollTimer;
QTimer m_devStatsPollTimer;
2017-01-12 22:38:36 +01:00
QTimer m_errorsPollTimer;
QTimer m_autoReconnectTimer;
unsigned int m_autoReconnectTries;
int m_requestTimeout;
2023-11-06 15:06:40 +01:00
int m_longPollingTimeout;
2016-08-25 00:45:32 +02:00
QString m_configDir;
QString m_myId;
QString m_tilde;
QString m_pathSeparator;
2019-03-13 19:12:23 +01:00
std::uint64_t m_totalIncomingTraffic;
std::uint64_t m_totalOutgoingTraffic;
2016-08-30 20:01:07 +02:00
double m_totalIncomingRate;
double m_totalOutgoingRate;
2016-08-25 00:45:32 +02:00
QNetworkReply *m_configReply;
QNetworkReply *m_statusReply;
2016-08-26 16:43:53 +02:00
QNetworkReply *m_connectionsReply;
QNetworkReply *m_errorsReply;
QNetworkReply *m_dirStatsReply;
QNetworkReply *m_devStatsReply;
2016-08-25 00:45:32 +02:00
QNetworkReply *m_eventsReply;
2018-07-30 23:00:40 +02:00
QNetworkReply *m_versionReply;
QNetworkReply *m_diskEventsReply;
QNetworkReply *m_logReply;
QList<QNetworkReply *> m_otherReplies;
2016-08-25 00:45:32 +02:00
bool m_unreadNotifications;
2016-08-26 16:43:53 +02:00
bool m_hasConfig;
bool m_hasStatus;
bool m_hasEvents;
bool m_hasDiskEvents;
2016-08-25 00:45:32 +02:00
std::vector<SyncthingDir> m_dirs;
std::vector<SyncthingDev> m_devs;
QStringList m_devsPausedDueToMeteredConnection;
SyncthingEventId m_lastConnectionsUpdateEvent;
CppUtilities::DateTime m_lastConnectionsUpdateTime;
SyncthingEventId m_lastFileEvent = 0;
2019-06-10 22:48:26 +02:00
CppUtilities::DateTime m_lastFileTime;
CppUtilities::DateTime m_lastErrorTime;
CppUtilities::DateTime m_startTime;
2016-09-01 16:34:30 +02:00
QString m_lastFileName;
2018-07-30 23:00:40 +02:00
QString m_syncthingVersion;
2016-09-01 16:34:30 +02:00
bool m_lastFileDeleted;
QString m_certificatePath;
QString m_dynamicallyDeterminedCertificatePath;
QDateTime m_certificateLastModified;
2016-09-03 20:14:52 +02:00
QList<QSslError> m_expectedSslErrors;
QSslCertificate m_certFromLastSslError;
2017-02-22 18:16:41 +01:00
QJsonObject m_rawConfig;
2019-02-17 23:45:53 +01:00
bool m_dirStatsAltered;
bool m_recordFileChanges;
bool m_useDeprecatedRoutes;
bool m_pausingOnMeteredConnection;
#ifdef SYNCTHINGCONNECTION_SUPPORT_METERED
bool m_handlingMeteredConnectionInitialized;
#endif
2016-08-25 00:45:32 +02:00
};
/*!
* \brief Returns the URL used to connect to Syncthing.
*/
inline const QString &SyncthingConnection::syncthingUrl() const
{
return m_syncthingUrl;
}
/*!
* \brief Sets the URL used to connect to Syncthing.
*/
inline void SyncthingConnection::setSyncthingUrl(const QString &url)
{
m_syncthingUrl = url;
}
/*!
* \brief Returns the API key used to connect to Syncthing.
*/
inline const QByteArray &SyncthingConnection::apiKey() const
{
return m_apiKey;
}
/*!
* \brief Sets the API key used to connect to Syncthing.
*/
inline void SyncthingConnection::setApiKey(const QByteArray &apiKey)
{
m_apiKey = apiKey;
}
/*!
* \brief Returns the user name which has been set using setCredentials().
*/
inline const QString &SyncthingConnection::user() const
{
return m_user;
}
/*!
* \brief Returns the password which has been set using setCredentials().
*/
inline const QString &SyncthingConnection::password() const
{
return m_password;
}
/*!
* \brief Provides credentials used for HTTP authentication.
*/
inline void SyncthingConnection::setCredentials(const QString &user, const QString &password)
{
m_user = user;
m_password = password;
}
/*!
* \brief Returns whether deprecated routes should still be used in order to support older versions of Syncthing.
* \remarks
* - This is still enabled by default but may cease to work once those deprecated routes have been removed by
* Syncthing itself.
* - Disabling this will require Syncthing 1.12.0 or newer.
*/
inline bool SyncthingConnection::isUsingDeprecatedRoutes() const
{
return m_useDeprecatedRoutes;
}
/*!
* \brief Returns whether deprecated routes should still be used in order to support older versions of Syncthing.
* \sa See isUsingLegacyRoutes() for details.
*/
inline void SyncthingConnection::setUseDeprecatedRoutes(bool useDeprecatedRoutes)
{
m_useDeprecatedRoutes = useDeprecatedRoutes;
}
/*!
* \brief Returns the string representation of the current status().
*/
inline QString SyncthingConnection::statusText() const
{
return statusText(m_status);
2016-08-25 00:45:32 +02:00
}
/*!
* \brief Returns the (pre-computed) connection status.
* \sa See SyncthingConnection::setStatus() and SyncthingStatus for details how it is computed.
2016-08-25 00:45:32 +02:00
*/
inline SyncthingStatus SyncthingConnection::status() const
{
return m_status;
}
/*!
* \brief Returns whether the connection to Syncthing has been established.
*
* If true, all information like dirInfo() and devInfo() has been populated and will be updated if it changes.
2016-08-25 00:45:32 +02:00
*/
inline bool SyncthingConnection::isConnected() const
{
return m_status != SyncthingStatus::Disconnected && m_status != SyncthingStatus::Reconnecting;
2016-08-25 00:45:32 +02:00
}
/*!
* \brief Returns whether the connection has been aborted, either by invoking disconnect(), abortAllRequests() or
* by an error.
*/
inline bool SyncthingConnection::isAborted() const
{
return m_connectionAborted;
}
/*!
* \brief Returns whether the connection is currently being established (and has not been established yet).
*/
inline bool SyncthingConnection::isConnecting() const
{
return !isConnected() && !isAborted() && hasPendingRequests();
}
/*!
* \brief Returns whether the SyncthingConnector instance is waiting for Syncthing to respond to a request.
* \remarks
* - Requests for (disk) events are excluded because those are long polling requests and therefore always pending.
* Instead, we take only into account whether those requests have been at least concluded once (since the last
* reconnect).
* - Only requests which contribute to the overall state and population of myId(), tilde(), dirInfo(), devInfo(),
* traffic statistics, ... are considered. So requests for QR code, logs, clearing errors, rescan, ... are not
* taken into account.
* - This function will also return true as long as the method abortAllRequests() is executed.
*/
inline bool SyncthingConnection::hasPendingRequests() const
{
return m_abortingAllRequests || m_configReply || m_statusReply || (m_eventsReply && !m_hasEvents) || (m_diskEventsReply && !m_hasDiskEvents)
|| m_connectionsReply || m_dirStatsReply || m_devStatsReply || m_errorsReply || m_versionReply || !m_otherReplies.isEmpty();
}
2016-10-04 23:42:17 +02:00
/*!
* \brief Returns whether there are unread notifications available.
* \remarks This flag is set to true when new notifications become available. It can be unset again by calling considerAllNotificationsRead().
*/
inline bool SyncthingConnection::hasUnreadNotifications() const
{
return m_unreadNotifications;
}
2018-01-24 21:46:18 +01:00
/*!
* \brief Returns whether completion for all directories of all devices should be requested automatically.
* \remarks Completion can be requested manually using requestCompletion().
*/
inline bool SyncthingConnection::isRequestingCompletionEnabled() const
{
return m_requestCompletion;
}
/*!
* \brief Sets whether completion for all directories of all devices should be requested automatically.
* \remarks Completion can be requested manually using requestCompletion().
*/
inline void SyncthingConnection::setRequestingCompletionEnabled(bool requestingCompletionEnabled)
{
m_requestCompletion = requestingCompletionEnabled;
}
/*!
* \brief Internally called to emit the notification with the specified \a message.
* \remarks Ensures the unread notifications flag is set.
*/
inline void SyncthingConnection::emitNotification(CppUtilities::DateTime when, const QString &message)
{
m_unreadNotifications = true;
emit newNotification(when, message);
}
/*!
* \brief Considers all notifications as read; hence might trigger a status update.
*/
inline void SyncthingConnection::considerAllNotificationsRead()
{
m_unreadNotifications = false;
requestClearingErrors();
}
2016-09-25 20:54:09 +02:00
/*!
* \brief Returns the interval for polling traffic status (which can not be received via event API) in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. Zero means polling is disabled.
2016-09-25 20:54:09 +02:00
*/
inline int SyncthingConnection::trafficPollInterval() const
{
return m_trafficPollTimer.interval();
2016-09-25 20:54:09 +02:00
}
/*!
* \brief Sets the interval for polling traffic status (which can not be received via event API) in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. Zero means polling is disabled.
2016-09-25 20:54:09 +02:00
*/
inline void SyncthingConnection::setTrafficPollInterval(int trafficPollInterval)
{
2017-05-01 03:34:43 +02:00
if (!trafficPollInterval) {
m_trafficPollTimer.stop();
}
m_trafficPollTimer.setInterval(trafficPollInterval);
2016-09-25 20:54:09 +02:00
}
/*!
* \brief Returns the interval for polling device statistics (which can not be received via event API) in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. Zero means polling is disabled.
2016-09-25 20:54:09 +02:00
*/
inline int SyncthingConnection::devStatsPollInterval() const
{
return m_devStatsPollTimer.interval();
2016-09-25 20:54:09 +02:00
}
/*!
* \brief Sets the interval for polling device statistics (which can not be received via event API) in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. Zero means polling is disabled.
2016-09-25 20:54:09 +02:00
*/
inline void SyncthingConnection::setDevStatsPollInterval(int devStatsPollInterval)
{
2017-05-01 03:34:43 +02:00
if (!devStatsPollInterval) {
m_devStatsPollTimer.stop();
}
m_devStatsPollTimer.setInterval(devStatsPollInterval);
2016-09-25 20:54:09 +02:00
}
2017-01-12 22:38:36 +01:00
/*!
* \brief Returns the interval for polling Syncthing errors (which can not be received via event API) in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. Zero means polling is disabled.
2017-01-12 22:38:36 +01:00
*/
inline int SyncthingConnection::errorsPollInterval() const
{
return m_errorsPollTimer.interval();
}
/*!
* \brief Sets the interval for polling Syncthing errors (which can not be received via event API) in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. Zero means polling is disabled.
2017-01-12 22:38:36 +01:00
*/
inline void SyncthingConnection::setErrorsPollInterval(int errorPollInterval)
{
2017-05-01 03:34:43 +02:00
if (!errorPollInterval) {
2017-01-12 22:38:36 +01:00
m_errorsPollTimer.stop();
}
m_errorsPollTimer.setInterval(errorPollInterval);
}
2016-10-07 15:11:25 +02:00
/*!
* \brief Returns the reconnect interval in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. A value of 0 indicates that auto-reconnect is disabled.
2016-10-07 15:11:25 +02:00
*/
inline int SyncthingConnection::autoReconnectInterval() const
{
return m_autoReconnectTimer.interval();
}
/*!
* \brief Returns the current number of auto-reconnect tries.
*/
inline unsigned int SyncthingConnection::autoReconnectTries() const
2016-10-07 15:11:25 +02:00
{
return m_autoReconnectTries;
2016-10-07 15:11:25 +02:00
}
/*!
* \brief Sets the reconnect interval in milliseconds.
* \remarks For default value see SyncthingConnectionSettings. A value of 0 indicates that auto-reconnect is disabled.
2016-10-07 15:11:25 +02:00
*/
inline void SyncthingConnection::setAutoReconnectInterval(int interval)
2016-10-07 15:11:25 +02:00
{
2017-05-01 03:34:43 +02:00
if (!interval) {
m_autoReconnectTimer.stop();
2016-10-07 15:11:25 +02:00
}
m_autoReconnectTimer.setInterval(interval);
2016-10-07 15:11:25 +02:00
}
/*!
* \brief Returns whether file changes are recorded for each directory so SyncthingDir::recentChanges is being populated.
* \remarks The fileChanged() signal is unaffected.
*/
inline bool SyncthingConnection::recordFileChanges() const
{
return m_recordFileChanges;
}
/*!
* \brief Returns whether file changes are recorded for each directory so SyncthingDir::recentChanges is being populated.
* \remarks The fileChanged() signal is unaffected.
*/
inline void SyncthingConnection::setRecordFileChanges(bool recordFileChanges)
{
m_recordFileChanges = recordFileChanges;
}
/*!
* \brief Returns the transfer timeout for requests in milliseconds.
* \sa QNetworkRequest::transferTimeout()
*/
inline int SyncthingConnection::requestTimeout() const
{
return m_requestTimeout;
}
/*!
* \brief Sets the transfer timeout for requests in milliseconds.
* \remarks Existing requests are not affected. Only effective when compiled against Qt 5.15 or higher.
* \sa QNetworkRequest::setTransferTimeout()
*/
inline void SyncthingConnection::setRequestTimeout(int requestTimeout)
{
m_requestTimeout = requestTimeout;
}
2023-11-06 15:06:40 +01:00
/*!
* \brief Returns the transfer timeout for long polling requests (event APIs) in milliseconds.
* \sa QNetworkRequest::transferTimeout()
*/
inline int SyncthingConnection::longPollingTimeout() const
{
return m_longPollingTimeout;
}
/*!
* \brief Sets the transfer timeout for long polling requests (event APIs) in milliseconds.
* \remarks Existing requests are not affected. Only effective when compiled against Qt 5.15 or higher.
* \sa QNetworkRequest::setTransferTimeout()
*/
inline void SyncthingConnection::setLongPollingTimeout(int longPollingTimeout)
{
m_longPollingTimeout = longPollingTimeout;
}
/*!
* \brief Returns whether to pause all devices on metered connections.
*/
inline bool SyncthingConnection::isPausingOnMeteredConnection() const
{
return m_pausingOnMeteredConnection;
}
/*!
* \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 currently active logging flags.
*/
inline SyncthingConnectionLoggingFlags SyncthingConnection::loggingFlags() const
{
return m_loggingFlags;
}
2016-08-25 00:45:32 +02:00
/*!
* \brief Returns the Syncthing home/configuration directory.
*/
inline const QString &SyncthingConnection::configDir() const
{
return m_configDir;
}
/*!
* \brief Returns the ID of the own Syncthing device.
*/
inline const QString &SyncthingConnection::myId() const
{
return m_myId;
}
/*!
* \brief Returns the substitution for "~" of the Syncthing instance.
*/
inline const QString &SyncthingConnection::tilde() const
{
return m_tilde;
}
/*!
* \brief Returns the path separator of the Syncthing instance.
*/
inline const QString &SyncthingConnection::pathSeparator() const
{
return m_pathSeparator;
}
2016-08-29 20:51:30 +02:00
/*!
2016-08-30 20:01:07 +02:00
* \brief Returns the total incoming traffic in byte.
2016-08-29 20:51:30 +02:00
*/
2019-03-13 19:12:23 +01:00
inline std::uint64_t SyncthingConnection::totalIncomingTraffic() const
2016-08-29 20:51:30 +02:00
{
return m_totalIncomingTraffic;
}
/*!
2016-08-30 20:01:07 +02:00
* \brief Returns the total outgoing traffic in byte.
2016-08-29 20:51:30 +02:00
*/
2019-03-13 19:12:23 +01:00
inline std::uint64_t SyncthingConnection::totalOutgoingTraffic() const
2016-08-29 20:51:30 +02:00
{
return m_totalOutgoingTraffic;
}
2016-08-30 20:01:07 +02:00
/*!
* \brief Returns the total incoming transfer rate in kbit/s.
*/
inline double SyncthingConnection::totalIncomingRate() const
{
return m_totalIncomingRate;
}
/*!
* \brief Returns the total outgoing transfer rate in kbit/s.
*/
inline double SyncthingConnection::totalOutgoingRate() const
{
return m_totalOutgoingRate;
}
2016-08-25 00:45:32 +02:00
/*!
2016-09-27 21:20:17 +02:00
* \brief Returns all available directory information.
2016-08-25 00:45:32 +02:00
* \remarks The returned object container object is persistent. However, the contained
* info objects are invalidated when the newConfig() signal is emitted.
*/
inline const std::vector<SyncthingDir> &SyncthingConnection::dirInfo() const
{
return m_dirs;
}
/*!
2016-09-27 21:20:17 +02:00
* \brief Returns all available device information.
2016-08-25 00:45:32 +02:00
* \remarks The returned object container object is persistent. However, the contained
* info objects are invalidated when the newConfig() signal is emitted.
*/
inline const std::vector<SyncthingDev> &SyncthingConnection::devInfo() const
{
return m_devs;
}
2018-07-30 23:00:22 +02:00
/*!
* \brief Computes overall directory statistics based on the currently available directory information.
*/
inline SyncthingOverallDirStatistics SyncthingConnection::computeOverallDirStatistics() const
{
return SyncthingOverallDirStatistics(dirInfo());
}
/*!
* \brief Returns the name of the file which has been synced most recently.
*/
inline const QString &SyncthingConnection::lastSyncedFile() const
{
return m_lastFileName;
}
/*!
* \brief Returns the time of the most recent sync.
*/
2019-06-10 22:48:26 +02:00
inline CppUtilities::DateTime SyncthingConnection::lastSyncTime() const
2018-07-30 23:00:22 +02:00
{
return m_lastFileTime;
}
/*!
* \brief Returns when Syncthing has been started.
*/
2019-06-10 22:48:26 +02:00
inline CppUtilities::DateTime SyncthingConnection::startTime() const
2018-07-30 23:00:22 +02:00
{
return m_startTime;
}
/*!
* \brief Returns how long Syncthing has been running.
*/
2019-06-10 22:48:26 +02:00
inline CppUtilities::TimeSpan SyncthingConnection::uptime() const
2018-07-30 23:00:22 +02:00
{
return m_startTime.isNull() ? CppUtilities::TimeSpan() : CppUtilities::DateTime::now() - m_startTime;
2018-07-30 23:00:22 +02:00
}
2018-07-30 23:00:40 +02:00
/*!
* \brief Returns the Syncthing version.
*/
inline const QString &SyncthingConnection::syncthingVersion() const
{
return m_syncthingVersion;
}
2016-09-01 16:34:30 +02:00
/*!
2016-10-02 21:59:28 +02:00
* \brief Returns a list of all expected certificate errors. This is meant to allow self-signed certificates.
* \remarks This list is updated via loadSelfSignedCertificate().
2016-09-01 16:34:30 +02:00
*/
inline const QList<QSslError> &SyncthingConnection::expectedSslErrors() const
2016-09-01 16:34:30 +02:00
{
2016-09-03 20:14:52 +02:00
return m_expectedSslErrors;
2016-09-01 16:34:30 +02:00
}
2018-04-01 20:21:51 +02:00
/*!
* \brief Returns the raw Syncthing configuration.
* \remarks The referenced object is updated when newConfig() is emitted.
*/
inline const QJsonObject &SyncthingConnection::rawConfig() const
{
return m_rawConfig;
}
/*!
* \brief Returns the directory info object for the directory with the specified ID.
* \returns Returns a pointer to the object or nullptr if not found.
* \remarks The returned object becomes invalid when the newDirs() signal is emitted or the connection is destroyed.
*/
inline const SyncthingDir *SyncthingConnection::findDirInfo(const QString &dirId, int &row) const
{
return const_cast<SyncthingConnection *>(this)->findDirInfo(dirId, row);
}
/*!
* \brief Returns the device info object for the device with the specified ID.
* \returns Returns a pointer to the object or nullptr if not found.
* \remarks The returned object becomes invalid when the newConfig() signal is emitted or the connection is destroyed.
*/
inline const SyncthingDev *SyncthingConnection::findDevInfo(const QString &devId, int &row) const
{
return const_cast<SyncthingConnection *>(this)->findDevInfo(devId, row);
}
2018-03-24 17:06:16 +01:00
} // namespace Data
2016-08-25 00:45:32 +02:00
Q_DECLARE_METATYPE(Data::SyncthingLogEntry)
2016-08-25 00:45:32 +02:00
#endif // SYNCTHINGCONNECTION_H