From c6a5b40a1da5c56bf33f5bcb99d69417f65bd544 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 15 Apr 2023 22:05:06 +0200 Subject: [PATCH] Re-connect when event ID is decreasing --- syncthingconnector/syncthingconnection.cpp | 4 +-- syncthingconnector/syncthingconnection.h | 2 +- .../syncthingconnection_requests.cpp | 32 +++++++++++++++---- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/syncthingconnector/syncthingconnection.cpp b/syncthingconnector/syncthingconnection.cpp index 04756ac..7909f39 100644 --- a/syncthingconnector/syncthingconnection.cpp +++ b/syncthingconnector/syncthingconnection.cpp @@ -966,8 +966,8 @@ void SyncthingConnection::setStatus(SyncthingStatus status) void SyncthingConnection::emitError(const QString &message, const QJsonParseError &jsonError, QNetworkReply *reply, const QByteArray &response) { if (loggingFlags() & SyncthingConnectionLoggingFlags::ApiReplies) { - cerr << Phrases::Error << "JSON parsing error: " << message.toLocal8Bit().data() << jsonError.errorString().toLocal8Bit().data() - << " (at offset " << jsonError.offset << ')' << endl; + std::cerr << Phrases::Error << "JSON parsing error: " << message.toLocal8Bit().data() << jsonError.errorString().toLocal8Bit().data() + << " (at offset " << jsonError.offset << ')' << Phrases::End; } emit error(message % jsonError.errorString() % QChar(' ') % QChar('(') % tr("at offset %1").arg(jsonError.offset) % QChar(')'), SyncthingErrorCategory::Parsing, QNetworkReply::NoError, reply->request(), response); diff --git a/syncthingconnector/syncthingconnection.h b/syncthingconnector/syncthingconnection.h index 6f5d496..dccad2c 100644 --- a/syncthingconnector/syncthingconnection.h +++ b/syncthingconnector/syncthingconnection.h @@ -295,7 +295,7 @@ private Q_SLOTS: void readErrors(); void readClearingErrors(); void readEvents(); - void readEventsFromJsonArray(const QJsonArray &events, quint64 &idVariable); + bool readEventsFromJsonArray(const QJsonArray &events, quint64 &idVariable); void readStartingEvent(const QJsonObject &eventData); void readStatusChangedEvent(SyncthingEventId eventId, CppUtilities::DateTime eventTime, const QJsonObject &eventData); void readDownloadProgressEvent(const QJsonObject &eventData); diff --git a/syncthingconnector/syncthingconnection_requests.cpp b/syncthingconnector/syncthingconnection_requests.cpp index e6ade8c..e7f9c00 100644 --- a/syncthingconnector/syncthingconnection_requests.cpp +++ b/syncthingconnector/syncthingconnection_requests.cpp @@ -1717,9 +1717,11 @@ void SyncthingConnection::readEvents() } m_hasEvents = true; - const auto replyArray(replyDoc.array()); + const auto replyArray = replyDoc.array(); emit newEvents(replyArray); - readEventsFromJsonArray(replyArray, m_lastEventId); + if (!readEventsFromJsonArray(replyArray, m_lastEventId)) { + return; + } if (!replyArray.isEmpty() && (loggingFlags() & SyncthingConnectionLoggingFlags::Events)) { const auto log = replyDoc.toJson(QJsonDocument::Indented); @@ -1750,8 +1752,9 @@ void SyncthingConnection::readEvents() /*! * \brief Reads results of requestEvents(). */ -void SyncthingConnection::readEventsFromJsonArray(const QJsonArray &events, quint64 &idVariable) +bool SyncthingConnection::readEventsFromJsonArray(const QJsonArray &events, quint64 &idVariable) { + const auto lastId = idVariable; for (const auto &eventVal : events) { const auto event = eventVal.toObject(); const auto eventTime = parseTimeStamp(event.value(QLatin1String("time")), QStringLiteral("event time")); @@ -1760,7 +1763,19 @@ void SyncthingConnection::readEventsFromJsonArray(const QJsonArray &events, quin const auto eventIdValue = event.value(QLatin1String("id")); const auto eventId = static_cast(std::max(eventIdValue.toDouble(), 0.0)); if (eventIdValue.isDouble()) { - idVariable = eventId; + if (eventId < lastId) { + // re-connect if the event ID decreases as this indicates something weird on the other end happened + // note: The Syncthing docs say "A unique ID for this event on the events API. It always increases by 1: the + // first event generated has id 1, the next has id 2 etc.". + if (loggingFlags() & SyncthingConnectionLoggingFlags::ApiCalls) { + std::cerr << Phrases::Info << "Re-connecting as event ID is decreasing (" << eventId << " < " << lastId << ')' << Phrases::End; + } + reconnect(); + return false; + } + if (eventId > idVariable) { + idVariable = eventId; + } } if (eventType == QLatin1String("Starting")) { readStartingEvent(eventData); @@ -1785,6 +1800,7 @@ void SyncthingConnection::readEventsFromJsonArray(const QJsonArray &events, quin } } emitDirStatisticsChanged(); + return true; } /*! @@ -2293,15 +2309,17 @@ void SyncthingConnection::readDiskEvents() switch (reply->error()) { case QNetworkReply::NoError: { auto jsonError = QJsonParseError(); - const auto replyDoc(QJsonDocument::fromJson(response, &jsonError)); + const auto replyDoc = QJsonDocument::fromJson(response, &jsonError); if (jsonError.error != QJsonParseError::NoError) { emitError(tr("Unable to parse disk events: "), jsonError, reply, response); return; } - const auto replyArray = replyDoc.array(); m_hasDiskEvents = true; - readEventsFromJsonArray(replyArray, m_lastDiskEventId); + const auto replyArray = replyDoc.array(); + if (!readEventsFromJsonArray(replyArray, m_lastDiskEventId)) { + return; + } if (!replyArray.isEmpty() && (loggingFlags() & SyncthingConnectionLoggingFlags::Events)) { const auto log = replyDoc.toJson(QJsonDocument::Indented);