From 772ff300450304664e2ffe37cc0fa6feff50a0e9 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Tue, 22 Nov 2022 12:52:10 +0100 Subject: [PATCH] Fix some cases of rich reply rendering while/after fetching event Change-Id: Id940df5c838ac962f28f7b02bb7dfdb2967d8a28 --- .../timeline/reply/ReplyPreviewRetriever.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reply/ReplyPreviewRetriever.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reply/ReplyPreviewRetriever.kt index ccf0ca9413..f4227c3c36 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reply/ReplyPreviewRetriever.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reply/ReplyPreviewRetriever.kt @@ -90,6 +90,8 @@ class ReplyPreviewRetriever( private val lookedUpEvents = mutableMapOf() // Timestamps of allowed server requests for individual events, to not spam server with the same request private val serverRequests = mutableMapOf() + // eventToRetrieveId-specific locking + private val retrieveEventLocks = mutableMapOf() fun invalidateEventsFromSnapshot(snapshot: List) { val snapshotEvents = snapshot.associateBy { it.eventId } @@ -141,6 +143,9 @@ class ReplyPreviewRetriever( } }?.let { eventIdToRetrieve -> coroutineScope.launch(Dispatchers.IO) { + val retrieveEventLock = synchronized(retrieveEventLocks) { + retrieveEventLocks.getOrPut(eventIdToRetrieve) { eventIdToRetrieve } + } runCatching { // Don't spam the server too often if it doesn't know the event val mayAskServerForEvent = synchronized(serverRequests) { @@ -153,10 +158,13 @@ class ReplyPreviewRetriever( } } if (DEBUG) Timber.i("REPLY HANDLING AFTER ${System.currentTimeMillis() - now} for $eventId / $eventIdToRetrieve, may ask: $mayAskServerForEvent")// TODO remove - if (mayAskServerForEvent) { - session.getRoom(roomId)?.timelineService()?.getOrFetchAndPersistTimelineEventBlocking(eventIdToRetrieve) - } else { - session.getRoom(roomId)?.getTimelineEvent(eventIdToRetrieve) + // Synchronize, so that we await a pending server fetch if necessary + synchronized(retrieveEventLock) { + if (mayAskServerForEvent) { + session.getRoom(roomId)?.timelineService()?.getOrFetchAndPersistTimelineEventBlocking(eventIdToRetrieve) + } else { + session.getRoom(roomId)?.getTimelineEvent(eventIdToRetrieve) + } }?.apply { // We need to check encryption val repliedToEvent = root // TODO what if rendered event is not root, i.e. root.eventId != getLatestEventId()? (we currently just use the initial event in this case, better than nothing)