From 1004bd19e36144a901b5431af3d1e347c6458416 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Sun, 12 Mar 2023 14:20:47 +0100 Subject: [PATCH] [TEST] Don't set main_or_null read receipt to old events Context: https://github.com/SchildiChat/SchildiChat-android-rageshakes/issues/951 If main RR updates after null RR, but to an older event than the null RR, we still want to keep the null one. Change-Id: Ib865965b6975536421b15146c863b9ea46f793b0 --- .../database/helper/ChunkEntityHelper.kt | 12 ++++++++++-- .../sync/handler/room/ReadReceiptHandler.kt | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt index aa1bb401ab..aa068bfede 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt @@ -146,8 +146,16 @@ private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventE } receiptDestinations.forEach { rootThreadEventId -> val readReceiptOfSender = ReadReceiptEntity.getOrCreate(realm, roomId = roomId, userId = senderId, threadId = rootThreadEventId) + val shouldSkipMon = if (rootThreadEventId == THREAD_ID_MAIN_OR_NULL) { + val previousReceiptsSummary = ReadReceiptsSummaryEntity.where(realm, eventId = readReceiptOfSender.eventId).findFirst() + val oldEventTs = previousReceiptsSummary?.let { EventEntity.where(realm, roomId, it.eventId).findFirst()?.originServerTs } + val newEventTs = EventEntity.where(realm, roomId, eventEntity.eventId).findFirst()?.originServerTs + oldEventTs != null && newEventTs != null && oldEventTs > newEventTs + } else { + false + } // If the synced RR is older, update - if (timestampOfEvent > readReceiptOfSender.originServerTs) { + if (timestampOfEvent > readReceiptOfSender.originServerTs && !shouldSkipMon) { val previousReceiptsSummary = ReadReceiptsSummaryEntity.where(realm, eventId = readReceiptOfSender.eventId).findFirst() rrDimber.i { "Handle outdated chunk RR $roomId / $senderId thread $rootThreadEventId(${eventEntity.rootThreadEventId}): event ${readReceiptOfSender.eventId} -> ${eventEntity.eventId}" } readReceiptOfSender.eventId = eventEntity.eventId @@ -155,7 +163,7 @@ private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventE previousReceiptsSummary?.readReceipts?.remove(readReceiptOfSender) readReceiptsSummaryEntity.readReceipts.add(readReceiptOfSender) } else { - rrDimber.i { "Handled chunk RR $roomId / $senderId thread $rootThreadEventId(${eventEntity.rootThreadEventId}): keep ${readReceiptOfSender.eventId} (not ${eventEntity.eventId})" } + rrDimber.i { "Handled chunk RR $roomId / $senderId thread $rootThreadEventId(${eventEntity.rootThreadEventId}): keep ${readReceiptOfSender.eventId} (not ${eventEntity.eventId}) || $shouldSkipMon" } } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt index 16c9ed8ef7..49f8e46f7d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/room/ReadReceiptHandler.kt @@ -24,6 +24,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.read.ReadService.Companion.THREAD_ID_MAIN import org.matrix.android.sdk.api.session.room.read.ReadService.Companion.THREAD_ID_MAIN_OR_NULL +import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity import org.matrix.android.sdk.internal.database.query.createUnmanaged @@ -164,15 +165,22 @@ internal class ReadReceiptHandler @Inject constructor( val syncedThreadId = paramsDict[THREAD_ID_KEY] as String? // SC: fight duplicate read receipts in main timeline - val receiptDestinations = if (syncedThreadId in listOf(null, ReadService.THREAD_ID_MAIN)) { - setOf(syncedThreadId, ReadService.THREAD_ID_MAIN_OR_NULL) + val receiptDestinations = if (syncedThreadId in listOf(null, THREAD_ID_MAIN)) { + setOf(syncedThreadId, THREAD_ID_MAIN_OR_NULL) } else { setOf(syncedThreadId) } receiptDestinations.forEach { threadId -> val receiptEntity = ReadReceiptEntity.getOrCreate(realm, roomId, userId, threadId) + val shouldSkipMon = if (threadId == THREAD_ID_MAIN_OR_NULL) { + val oldEventTs = EventEntity.where(realm, roomId, receiptEntity.eventId).findFirst()?.originServerTs + val newEventTs = EventEntity.where(realm, roomId, eventId).findFirst()?.originServerTs + oldEventTs != null && newEventTs != null && oldEventTs > newEventTs + } else { + false + } // ensure new ts is superior to the previous one - if (ts > receiptEntity.originServerTs) { + if (ts > receiptEntity.originServerTs && !shouldSkipMon) { rrDimber.i { "Handle outdated sync RR $roomId / $userId thread $threadId($syncedThreadId): event ${receiptEntity.eventId} -> $eventId" } ReadReceiptsSummaryEntity.where(realm, receiptEntity.eventId).findFirst()?.also { it.readReceipts.remove(receiptEntity) @@ -181,7 +189,7 @@ internal class ReadReceiptHandler @Inject constructor( receiptEntity.originServerTs = ts readReceiptsSummary.readReceipts.add(receiptEntity) } else { - rrDimber.i { "Handle keep sync RR $roomId / $userId thread $threadId($syncedThreadId): event ${receiptEntity.eventId} (not $eventId)" } + rrDimber.i { "Handle keep sync RR $roomId / $userId thread $threadId($syncedThreadId): event ${receiptEntity.eventId} (not $eventId) || $shouldSkipMon" } } } }