Add state events to chunks

This commit is contained in:
Ganard 2020-01-28 18:59:21 +01:00
parent bf7c53ecab
commit a8f783bbfa
4 changed files with 44 additions and 13 deletions

View File

@ -16,12 +16,14 @@
package im.vector.matrix.android.internal.database.helper package im.vector.matrix.android.internal.database.helper
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.RoomMemberContent import im.vector.matrix.android.api.session.room.model.RoomMemberContent
import im.vector.matrix.android.internal.database.mapper.ContentMapper
import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntityFields
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity
@ -33,6 +35,7 @@ import im.vector.matrix.android.internal.extensions.assertIsManaged
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
import io.realm.Sort import io.realm.Sort
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
import timber.log.Timber
internal fun ChunkEntity.deleteOnCascade() { internal fun ChunkEntity.deleteOnCascade() {
assertIsManaged() assertIsManaged()
@ -40,7 +43,7 @@ internal fun ChunkEntity.deleteOnCascade() {
this.deleteFromRealm() this.deleteFromRealm()
} }
internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity, direction: PaginationDirection) { internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) {
assertIsManaged() assertIsManaged()
val eventsToMerge: List<TimelineEventEntity> val eventsToMerge: List<TimelineEventEntity>
if (direction == PaginationDirection.FORWARDS) { if (direction == PaginationDirection.FORWARDS) {
@ -52,6 +55,9 @@ internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity, direction: PaginationD
this.isLastBackward = chunkToMerge.isLastBackward this.isLastBackward = chunkToMerge.isLastBackward
eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING) eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
} }
chunkToMerge.stateEvents.forEach { stateEvent ->
addStateEvent(roomId, stateEvent, direction)
}
return eventsToMerge return eventsToMerge
.forEach { .forEach {
if (timelineEvents.find(it.eventId) == null) { if (timelineEvents.find(it.eventId) == null) {
@ -61,10 +67,29 @@ internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity, direction: PaginationD
} }
} }
internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity, direction: PaginationDirection) {
if (direction == PaginationDirection.FORWARDS) {
Timber.v("We don't keep chunk state events when paginating forward")
} else {
val stateKey = stateEvent.stateKey ?: return
val type = stateEvent.type
val pastStateEvent = stateEvents.where()
.equalTo(EventEntityFields.ROOM_ID, roomId)
.equalTo(EventEntityFields.STATE_KEY, stateKey)
.equalTo(CurrentStateEventEntityFields.TYPE, type)
.findFirst()
if (pastStateEvent != null) {
stateEvents.remove(pastStateEvent)
}
stateEvents.add(stateEvent)
}
}
internal fun ChunkEntity.addTimelineEvent(roomId: String, internal fun ChunkEntity.addTimelineEvent(roomId: String,
eventEntity: EventEntity, eventEntity: EventEntity,
direction: PaginationDirection, direction: PaginationDirection,
roomMemberEvent: Event?) { roomMemberEvent: EventEntity?) {
val eventId = eventEntity.eventId val eventId = eventEntity.eventId
if (timelineEvents.find(eventId) != null) { if (timelineEvents.find(eventId) != null) {
@ -104,10 +129,9 @@ internal fun ChunkEntity.addTimelineEvent(roomId: String,
this.readReceipts = readReceiptsSummaryEntity this.readReceipts = readReceiptsSummaryEntity
this.displayIndex = displayIndex this.displayIndex = displayIndex
if (roomMemberEvent != null) { if (roomMemberEvent != null) {
val roomMemberContent = roomMemberEvent.content.toModel<RoomMemberContent>() val roomMemberContent = ContentMapper.map(roomMemberEvent.content).toModel<RoomMemberContent>()
this.senderAvatar = roomMemberContent?.avatarUrl this.senderAvatar = roomMemberContent?.avatarUrl
this.senderName = roomMemberContent?.displayName this.senderName = roomMemberContent?.displayName
this.isUniqueDisplayName = false
this.senderMembershipEventId = roomMemberEvent.eventId this.senderMembershipEventId = roomMemberEvent.eventId
} }
} }

View File

@ -24,6 +24,7 @@ import io.realm.annotations.LinkingObjects
internal open class ChunkEntity(@Index var prevToken: String? = null, internal open class ChunkEntity(@Index var prevToken: String? = null,
@Index var nextToken: String? = null, @Index var nextToken: String? = null,
var stateEvents: RealmList<EventEntity> = RealmList(),
var timelineEvents: RealmList<TimelineEventEntity> = RealmList(), var timelineEvents: RealmList<TimelineEventEntity> = RealmList(),
@Index var isLastForward: Boolean = false, @Index var isLastForward: Boolean = false,
@Index var isLastBackward: Boolean = false @Index var isLastBackward: Boolean = false

View File

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.internal.database.helper.addOrUpdate import im.vector.matrix.android.internal.database.helper.addOrUpdate
import im.vector.matrix.android.internal.database.helper.addStateEvent
import im.vector.matrix.android.internal.database.helper.addTimelineEvent import im.vector.matrix.android.internal.database.helper.addTimelineEvent
import im.vector.matrix.android.internal.database.helper.deleteOnCascade import im.vector.matrix.android.internal.database.helper.deleteOnCascade
import im.vector.matrix.android.internal.database.helper.merge import im.vector.matrix.android.internal.database.helper.merge
@ -192,7 +193,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
currentChunk: ChunkEntity currentChunk: ChunkEntity
) { ) {
Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}") Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}")
val roomMemberEventsByUser = HashMap<String, Event?>() val roomMemberEventsByUser = HashMap<String, EventEntity?>()
val eventList = if (direction == PaginationDirection.FORWARDS) { val eventList = if (direction == PaginationDirection.FORWARDS) {
receivedChunk.events receivedChunk.events
} else { } else {
@ -200,8 +201,12 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
} }
val stateEvents = receivedChunk.stateEvents val stateEvents = receivedChunk.stateEvents
for (stateEvent in stateEvents) { for (stateEvent in stateEvents) {
val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED).let {
realm.copyToRealmOrUpdate(it)
}
currentChunk.addStateEvent(roomId, stateEventEntity, direction)
if (stateEvent.type == EventType.STATE_ROOM_MEMBER && stateEvent.stateKey != null && !stateEvent.isRedacted()) { if (stateEvent.type == EventType.STATE_ROOM_MEMBER && stateEvent.stateKey != null && !stateEvent.isRedacted()) {
roomMemberEventsByUser[stateEvent.stateKey] = stateEvent roomMemberEventsByUser[stateEvent.stateKey] = stateEventEntity
} }
} }
val eventIds = ArrayList<String>(eventList.size) val eventIds = ArrayList<String>(eventList.size)
@ -220,13 +225,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
eventEntities.add(0, eventEntity) eventEntities.add(0, eventEntity)
} }
if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null && !event.isRedacted()) { if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null && !event.isRedacted()) {
roomMemberEventsByUser[event.stateKey] = event roomMemberEventsByUser[event.stateKey] = eventEntity
} }
} }
for (eventEntity in eventEntities) { for (eventEntity in eventEntities) {
val senderId = eventEntity.sender ?: continue val senderId = eventEntity.sender ?: continue
val roomMemberEvent = roomMemberEventsByUser.getOrPut(senderId) { val roomMemberEvent = roomMemberEventsByUser.getOrPut(senderId) {
CurrentStateEventEntity.getOrNull(realm, roomId, senderId, EventType.STATE_ROOM_MEMBER)?.root?.asDomain() CurrentStateEventEntity.getOrNull(realm, roomId, senderId, EventType.STATE_ROOM_MEMBER)?.root
} }
currentChunk.addTimelineEvent(roomId, eventEntity, direction, roomMemberEvent) currentChunk.addTimelineEvent(roomId, eventEntity, direction, roomMemberEvent)
} }
@ -235,7 +240,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
val chunksToDelete = ArrayList<ChunkEntity>() val chunksToDelete = ArrayList<ChunkEntity>()
chunks.forEach { chunks.forEach {
if (it != currentChunk) { if (it != currentChunk) {
currentChunk.merge(it, direction) currentChunk.merge(roomId, it, direction)
chunksToDelete.add(it) chunksToDelete.add(it)
} }
} }

View File

@ -29,6 +29,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.mapper.toEntity import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.find
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
@ -210,7 +211,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
chunkEntity.isLastForward = true chunkEntity.isLastForward = true
val eventIds = ArrayList<String>(eventList.size) val eventIds = ArrayList<String>(eventList.size)
val roomMemberEventsByUser = HashMap<String, Event?>() val roomMemberEventsByUser = HashMap<String, EventEntity?>()
for (event in eventList) { for (event in eventList) {
if (event.eventId == null || event.senderId == null) { if (event.eventId == null || event.senderId == null) {
@ -226,12 +227,12 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
root = eventEntity root = eventEntity
} }
if (event.type == EventType.STATE_ROOM_MEMBER) { if (event.type == EventType.STATE_ROOM_MEMBER) {
roomMemberEventsByUser[event.stateKey] = event roomMemberEventsByUser[event.stateKey] = eventEntity
roomMemberEventHandler.handle(realm, roomEntity.roomId, event) roomMemberEventHandler.handle(realm, roomEntity.roomId, event)
} }
} }
val roomMemberEvent = roomMemberEventsByUser.getOrPut(event.senderId) { val roomMemberEvent = roomMemberEventsByUser.getOrPut(event.senderId) {
CurrentStateEventEntity.getOrNull(realm, roomId, event.senderId, EventType.STATE_ROOM_MEMBER)?.root?.asDomain() CurrentStateEventEntity.getOrNull(realm, roomId, event.senderId, EventType.STATE_ROOM_MEMBER)?.root
} }
chunkEntity.addTimelineEvent(roomId, eventEntity, PaginationDirection.FORWARDS, roomMemberEvent) chunkEntity.addTimelineEvent(roomId, eventEntity, PaginationDirection.FORWARDS, roomMemberEvent)
// Give info to crypto module // Give info to crypto module