From a787c57c34eb98ebc10add29a8fc35c634845182 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 17 Jan 2025 10:42:20 +0100 Subject: [PATCH] QuaternionRoom::getSingleEvent() Also fixes the current FTBFS due to a part of this functionality sneaking into a previous commit. Otherwise, it's unused for now, will be used in subsequent commits. --- client/quaternionroom.cpp | 39 ++++++++++++++++++++++++++++++++++++++- client/quaternionroom.h | 23 ++++++++++++++++++++--- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/client/quaternionroom.cpp b/client/quaternionroom.cpp index 60174e0f..16167fe3 100644 --- a/client/quaternionroom.cpp +++ b/client/quaternionroom.cpp @@ -10,8 +10,10 @@ #include "logging_categories.h" -#include #include + +#include + #include #include @@ -88,6 +90,41 @@ bool QuaternionRoom::canRedact(const Quotient::EventId& eventId) const return false; } +void QuaternionRoom::onGettingSingleEvent(const QString& evtId) +{ + std::erase_if(singleEventRequests, [this, evtId](SingleEventRequest& r) { + if (!r.requestHandle.isFinished()) + r.requestHandle.abandon(); + std::ranges::for_each(r.eventIdsToRefresh, std::bind_front(&Room::updatedEvent, this)); + return r.eventId == evtId; + }); +} + +const RoomEvent* QuaternionRoom::getSingleEvent(const QString& eventId, const QString& originEventId) +{ + if (auto timelineIt = findInTimeline(eventId); timelineIt != historyEdge()) + return timelineIt->event(); + if (auto cachedIt = cachedEvents.find(eventId); cachedIt != cachedEvents.cend()) + return cachedIt->second.get(); + + auto requestIt = std::ranges::find(singleEventRequests, eventId, &SingleEventRequest::eventId); + if (requestIt == singleEventRequests.cend()) + requestIt = singleEventRequests.insert( + requestIt, + { eventId, connection() + ->callApi(id(), eventId) + .then([this](RoomEventPtr&& pEvt) { + const auto [it, cachedEventInserted] = + cachedEvents.insert_or_assign(pEvt->id(), std::move(pEvt)); + if (QUO_ALARM(!cachedEventInserted)) + emit updatedEvent(it->first); // At least notify clients... + onGettingSingleEvent(it->first); + }) }); + requestIt->eventIdsToRefresh.push_back(originEventId); + + return nullptr; +} + void QuaternionRoom::onAddNewTimelineEvents(timeline_iter_t from) { std::for_each(from, messageEvents().cend(), diff --git a/client/quaternionroom.h b/client/quaternionroom.h index bf805e80..b33f8994 100644 --- a/client/quaternionroom.h +++ b/client/quaternionroom.h @@ -8,6 +8,8 @@ #pragma once +#include + #include #include @@ -16,6 +18,8 @@ class QuaternionRoom: public Quotient::Room { Q_OBJECT public: + using RoomEvent = Quotient::RoomEvent; + QuaternionRoom(Quotient::Connection* connection, QString roomId, Quotient::JoinState joinState); @@ -46,7 +50,12 @@ class QuaternionRoom: public Quotient::Room //! is not found Q_INVOKABLE EventFuture ensureHistory(const QString& upToEventId, quint16 maxWaitSeconds = 20); - private: + //! \brief Obtain an arbitrary room event by its id that is available locally + //! + Q_INVOKABLE const Quotient::RoomEvent* getSingleEvent(const QString& eventId, + const QString& originEventId); + +private: using EventPromise = QPromise; using EventId = Quotient::EventId; @@ -57,13 +66,21 @@ class QuaternionRoom: public Quotient::Room }; std::vector historyRequests; - QSet highlights; + struct SingleEventRequest { + EventId eventId; + Quotient::JobHandle requestHandle; + std::vector eventIdsToRefresh{}; + }; + std::vector singleEventRequests; + std::unordered_map> cachedEvents; + + QSet highlights; QString m_cachedUserFilter; - int m_requestedEventsCount = 0; void onAddNewTimelineEvents(timeline_iter_t from) override; void onAddHistoricalTimelineEvents(rev_iter_t from) override; void checkForHighlights(const Quotient::TimelineItem& ti); void checkForRequestedEvents(const rev_iter_t& from); + void onGettingSingleEvent(const QString& evtId); };