mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
State index : rework the algorithm to manage limited chunks and avoid using wrong state events (Int.Min overriding)
This commit is contained in:
parent
d250d2bd27
commit
bc1462486d
@ -6,6 +6,7 @@
|
||||
<w>merlins</w>
|
||||
<w>moshi</w>
|
||||
<w>synchronizer</w>
|
||||
<w>untimelined</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
@ -1,12 +1,15 @@
|
||||
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.EventType
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.fastContains
|
||||
import im.vector.matrix.android.internal.database.query.find
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
import io.realm.Sort
|
||||
|
||||
|
||||
internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
|
||||
@ -25,16 +28,16 @@ internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
|
||||
|
||||
internal fun ChunkEntity.addAll(events: List<Event>,
|
||||
direction: PaginationDirection,
|
||||
updateStateIndex: Boolean = true) {
|
||||
stateIndexOffset: Int = 0) {
|
||||
|
||||
events.forEach { event ->
|
||||
addOrUpdate(event, direction, updateStateIndex)
|
||||
addOrUpdate(event, direction, stateIndexOffset)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||
direction: PaginationDirection,
|
||||
updateStateIndex: Boolean = true) {
|
||||
stateIndexOffset: Int = 0) {
|
||||
if (!isManaged) {
|
||||
throw IllegalStateException("Chunk entity should be managed to use fast contains")
|
||||
}
|
||||
@ -43,11 +46,16 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||
return
|
||||
}
|
||||
|
||||
if (updateStateIndex && event.isStateEvent()) {
|
||||
updateStateIndex(direction)
|
||||
var currentStateIndex = lastStateIndex(direction, defaultValue = stateIndexOffset)
|
||||
if (direction == PaginationDirection.FORWARDS && event.isStateEvent()) {
|
||||
currentStateIndex += 1
|
||||
} else if (direction == PaginationDirection.BACKWARDS && events.isNotEmpty()) {
|
||||
val lastEventType = events.last()?.type ?: ""
|
||||
if (EventType.isStateEvent(lastEventType)) {
|
||||
currentStateIndex -= 1
|
||||
}
|
||||
}
|
||||
|
||||
val currentStateIndex = stateIndex(direction)
|
||||
if (!events.fastContains(event.eventId)) {
|
||||
val eventEntity = event.asEntity()
|
||||
eventEntity.stateIndex = currentStateIndex
|
||||
@ -57,4 +65,11 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||
val eventEntity = events.find(event.eventId)
|
||||
eventEntity?.stateIndex = currentStateIndex
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
|
||||
return when (direction) {
|
||||
PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex
|
||||
PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex
|
||||
} ?: defaultValue
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package im.vector.matrix.android.internal.database.helper
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
|
||||
@ -15,4 +17,18 @@ internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
|
||||
if (!chunks.contains(chunkEntity)) {
|
||||
chunks.add(chunkEntity)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RoomEntity.addStateEvents(stateEvents: List<Event>, stateIndex: Int = Int.MIN_VALUE) {
|
||||
if (!isManaged) {
|
||||
throw IllegalStateException("Chunk entity should be managed to use fast contains")
|
||||
}
|
||||
stateEvents.forEach { event ->
|
||||
if (event.eventId == null) {
|
||||
return@forEach
|
||||
}
|
||||
val eventEntity = event.asEntity()
|
||||
eventEntity.stateIndex = stateIndex
|
||||
untimelinedStateEvents.add(eventEntity)
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmResults
|
||||
@ -8,8 +7,6 @@ import io.realm.annotations.LinkingObjects
|
||||
|
||||
internal open class ChunkEntity(var prevToken: String? = null,
|
||||
var nextToken: String? = null,
|
||||
var prevStateIndex: Int = -1,
|
||||
var nextStateIndex: Int = 1,
|
||||
var isLast: Boolean = false,
|
||||
var events: RealmList<EventEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
@ -18,19 +15,4 @@ internal open class ChunkEntity(var prevToken: String? = null,
|
||||
val room: RealmResults<RoomEntity>? = null
|
||||
|
||||
companion object
|
||||
|
||||
fun stateIndex(direction: PaginationDirection): Int {
|
||||
return when (direction) {
|
||||
PaginationDirection.FORWARDS -> nextStateIndex
|
||||
PaginationDirection.BACKWARDS -> prevStateIndex
|
||||
}
|
||||
}
|
||||
|
||||
fun updateStateIndex(direction: PaginationDirection) {
|
||||
when (direction) {
|
||||
PaginationDirection.FORWARDS -> nextStateIndex += 1
|
||||
PaginationDirection.BACKWARDS -> prevStateIndex -= 1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -24,4 +24,7 @@ internal open class EventEntity(var eventId: String = "",
|
||||
@LinkingObjects("events")
|
||||
val chunk: RealmResults<ChunkEntity>? = null
|
||||
|
||||
@LinkingObjects("untimelinedStateEvents")
|
||||
val room: RealmResults<RoomEntity>? = null
|
||||
|
||||
}
|
@ -8,8 +8,9 @@ import io.realm.annotations.PrimaryKey
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
internal open class RoomEntity(@PrimaryKey var roomId: String = "",
|
||||
var chunks: RealmList<ChunkEntity> = RealmList(),
|
||||
var areAllMembersLoaded: Boolean = false
|
||||
var chunks: RealmList<ChunkEntity> = RealmList(),
|
||||
var untimelinedStateEvents: RealmList<EventEntity> = RealmList(),
|
||||
var areAllMembersLoaded: Boolean = false
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = MyMembership.NONE.name
|
||||
|
@ -1,6 +1,5 @@
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.DBConstants
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntityFields
|
||||
@ -34,7 +33,5 @@ internal fun ChunkEntity.Companion.findLastLiveChunkFromRoom(realm: Realm, roomI
|
||||
internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
||||
return realm.where<ChunkEntity>()
|
||||
.`in`(ChunkEntityFields.EVENTS.EVENT_ID, eventIds.toTypedArray())
|
||||
.notEqualTo(ChunkEntityFields.PREV_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
.notEqualTo(ChunkEntityFields.NEXT_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
.findAll()
|
||||
}
|
@ -18,7 +18,11 @@ internal fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQu
|
||||
internal fun EventEntity.Companion.where(realm: Realm, roomId: String? = null, type: String? = null): RealmQuery<EventEntity> {
|
||||
val query = realm.where<EventEntity>()
|
||||
if (roomId != null) {
|
||||
query.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||
query.beginGroup()
|
||||
.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||
.or()
|
||||
.equalTo("${EventEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||
.endGroup()
|
||||
}
|
||||
if (type != null) {
|
||||
query.equalTo(EventEntityFields.TYPE, type)
|
||||
@ -26,21 +30,28 @@ internal fun EventEntity.Companion.where(realm: Realm, roomId: String? = null, t
|
||||
return query
|
||||
}
|
||||
|
||||
internal fun RealmQuery<EventEntity>.findMostSuitableStateEvent(stateIndex: Int): EventEntity? {
|
||||
val sort: Sort = if (stateIndex < 0) {
|
||||
this.greaterThanOrEqualTo(EventEntityFields.STATE_INDEX, stateIndex)
|
||||
Sort.ASCENDING
|
||||
} else {
|
||||
this.lessThanOrEqualTo(EventEntityFields.STATE_INDEX, stateIndex)
|
||||
Sort.DESCENDING
|
||||
internal fun RealmQuery<EventEntity>.next(from: Int? = null, strict: Boolean = true): EventEntity? {
|
||||
if (from != null) {
|
||||
if (strict) {
|
||||
this.greaterThan(EventEntityFields.STATE_INDEX, from)
|
||||
} else {
|
||||
this.greaterThanOrEqualTo(EventEntityFields.STATE_INDEX, from)
|
||||
}
|
||||
}
|
||||
return this
|
||||
.sort(EventEntityFields.STATE_INDEX, sort)
|
||||
.sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
|
||||
internal fun RealmQuery<EventEntity>.last(): EventEntity? {
|
||||
internal fun RealmQuery<EventEntity>.last(since: Int? = null, strict: Boolean = false): EventEntity? {
|
||||
if (since != null) {
|
||||
if (strict) {
|
||||
this.lessThan(EventEntityFields.STATE_INDEX, since)
|
||||
} else {
|
||||
this.lessThanOrEqualTo(EventEntityFields.STATE_INDEX, since)
|
||||
}
|
||||
}
|
||||
return this
|
||||
.sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING)
|
||||
.findFirst()
|
||||
|
@ -25,11 +25,11 @@ class RoomModule : Module {
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
LoadRoomMembersRequest(get(), get(), get(), get())
|
||||
LoadRoomMembersRequest(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
PaginationRequest(get(), get(), get(), get())
|
||||
PaginationRequest(get(), get(), get())
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,12 +5,11 @@ import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
@ -20,8 +19,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
internal class LoadRoomMembersRequest(private val roomAPI: RoomAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val stateEventsChunkHandler: StateEventsChunkHandler) {
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) {
|
||||
|
||||
fun execute(roomId: String,
|
||||
streamToken: String?,
|
||||
@ -57,8 +55,7 @@ internal class LoadRoomMembersRequest(private val roomAPI: RoomAPI,
|
||||
val roomMembers = RoomMembers(realm, roomId).getLoaded()
|
||||
val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) }
|
||||
|
||||
val chunk = stateEventsChunkHandler.handle(realm, roomId, eventsToInsert)
|
||||
roomEntity.addOrUpdate(chunk)
|
||||
roomEntity.addStateEvents(eventsToInsert)
|
||||
roomEntity.areAllMembersLoaded = true
|
||||
}
|
||||
.map { response }
|
||||
|
@ -2,14 +2,12 @@ package im.vector.matrix.android.internal.session.room.members
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.DBConstants
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
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.query.find
|
||||
import im.vector.matrix.android.internal.database.query.findMostSuitableStateEvent
|
||||
import im.vector.matrix.android.internal.database.query.last
|
||||
import im.vector.matrix.android.internal.database.query.next
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
|
||||
@ -17,35 +15,23 @@ internal class RoomMemberExtractor(private val realm: Realm,
|
||||
private val roomId: String) {
|
||||
|
||||
fun extractFrom(event: EventEntity): RoomMember? {
|
||||
val stateIndex = event.stateIndex
|
||||
val chunkEntity = event.chunk?.firstOrNull()
|
||||
?: throw IllegalStateException("An event should be attached to a chunk")
|
||||
|
||||
// First of all, try to get the most suitable state event coming from a chunk
|
||||
val roomMember = buildQuery(chunkEntity, event.sender)
|
||||
.findMostSuitableStateEvent(stateIndex = stateIndex)
|
||||
?.asDomain()
|
||||
?.pickContent<RoomMember>(stateIndex)
|
||||
|
||||
if (roomMember != null) {
|
||||
return roomMember
|
||||
val sender = event.sender ?: return null
|
||||
// When stateIndex is negative, we try to get the next stateEvent prevContent()
|
||||
// If prevContent is null we fallback to the Int.MIN state events content()
|
||||
return if (event.stateIndex <= 0) {
|
||||
baseQuery(realm, roomId, sender).next(from = event.stateIndex)?.asDomain()?.prevContent()
|
||||
?: baseQuery(realm, roomId, sender).last(since = event.stateIndex)?.asDomain()?.content()
|
||||
} else {
|
||||
baseQuery(realm, roomId, sender).last(since = event.stateIndex)?.asDomain()?.content()
|
||||
}
|
||||
|
||||
// If the content is null, we try get the last state event coming from a state events chunk
|
||||
val stateChunkEntity = ChunkEntity.find(realm, roomId, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
?: return null
|
||||
|
||||
return buildQuery(stateChunkEntity, event.sender)
|
||||
.last()
|
||||
?.asDomain()
|
||||
?.content()
|
||||
}
|
||||
|
||||
private fun buildQuery(chunk: ChunkEntity,
|
||||
sender: String?): RealmQuery<EventEntity> {
|
||||
return chunk.events
|
||||
.where()
|
||||
.equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_MEMBER)
|
||||
private fun baseQuery(realm: Realm,
|
||||
roomId: String,
|
||||
sender: String): RealmQuery<EventEntity> {
|
||||
|
||||
return EventEntity
|
||||
.where(realm, roomId = roomId, type = EventType.STATE_ROOM_MEMBER)
|
||||
.equalTo(EventEntityFields.STATE_KEY, sender)
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
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.model.ChunkEntity
|
||||
@ -15,7 +16,6 @@ import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.legacy.util.FilterUtil
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
@ -26,8 +26,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
internal class GetContextOfEventRequest(private val roomAPI: RoomAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val stateEventsChunkHandler: StateEventsChunkHandler
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||
) {
|
||||
|
||||
fun execute(roomId: String,
|
||||
@ -91,9 +90,7 @@ internal class GetContextOfEventRequest(private val roomAPI: RoomAPI,
|
||||
}
|
||||
*/
|
||||
roomEntity.addOrUpdate(currentChunk)
|
||||
|
||||
val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, response.stateEvents)
|
||||
roomEntity.addOrUpdate(stateEventsChunk)
|
||||
roomEntity.addStateEvents(response.stateEvents)
|
||||
}
|
||||
.map { response }
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -15,8 +14,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
internal class GetEventRequest(private val roomAPI: RoomAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val stateEventsChunkHandler: StateEventsChunkHandler
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||
) {
|
||||
|
||||
fun execute(roomId: String,
|
||||
|
@ -7,6 +7,7 @@ import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
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.model.ChunkEntity
|
||||
@ -17,7 +18,6 @@ import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.legacy.util.FilterUtil
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||
@ -28,8 +28,7 @@ import kotlinx.coroutines.withContext
|
||||
|
||||
internal class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val stateEventsChunkHandler: StateEventsChunkHandler
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||
) {
|
||||
|
||||
fun execute(roomId: String,
|
||||
@ -92,10 +91,8 @@ internal class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
}
|
||||
|
||||
roomEntity.addOrUpdate(currentChunk)
|
||||
|
||||
// TODO : there is an issue with the pagination sending unwanted room member events
|
||||
val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, receivedChunk.stateEvents)
|
||||
roomEntity.addOrUpdate(stateEventsChunk)
|
||||
roomEntity.addStateEvents(receivedChunk.stateEvents)
|
||||
}
|
||||
.map { receivedChunk }
|
||||
}
|
||||
|
@ -6,10 +6,11 @@ import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
||||
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
@ -23,7 +24,6 @@ import io.realm.kotlin.createObject
|
||||
|
||||
|
||||
internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
private val stateEventsChunkHandler: StateEventsChunkHandler,
|
||||
private val readReceiptHandler: ReadReceiptHandler) {
|
||||
|
||||
sealed class HandlingStrategy {
|
||||
@ -56,7 +56,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
roomSync: RoomSync): RoomEntity {
|
||||
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: RoomEntity(roomId)
|
||||
?: realm.createObject(roomId)
|
||||
|
||||
if (roomEntity.membership == MyMembership.INVITED) {
|
||||
roomEntity.chunks.deleteAllFromRealm()
|
||||
@ -64,13 +64,27 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
|
||||
roomEntity.membership = MyMembership.JOINED
|
||||
|
||||
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||
val isInitialSync = lastChunk == null
|
||||
val lastStateIndex = lastChunk?.lastStateIndex(PaginationDirection.FORWARDS) ?: 0
|
||||
val numberOfStateEvents = roomSync.state?.events?.size ?: 0
|
||||
val stateIndexOffset = lastStateIndex + numberOfStateEvents
|
||||
|
||||
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
||||
val chunkEntity = stateEventsChunkHandler.handle(realm, roomId, roomSync.state.events)
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset
|
||||
roomEntity.addStateEvents(roomSync.state.events, stateIndex = untimelinedStateIndex)
|
||||
}
|
||||
|
||||
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
||||
val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.timeline.events, roomSync.timeline.prevToken, isLimited = roomSync.timeline.limited)
|
||||
val timelineStateOffset = if (isInitialSync || roomSync.timeline.limited.not()) 0 else stateIndexOffset
|
||||
val chunkEntity = handleTimelineEvents(
|
||||
realm,
|
||||
roomId,
|
||||
roomSync.timeline.events,
|
||||
roomSync.timeline.prevToken,
|
||||
roomSync.timeline.limited,
|
||||
timelineStateOffset
|
||||
)
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
}
|
||||
|
||||
@ -111,22 +125,19 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
roomId: String,
|
||||
eventList: List<Event>,
|
||||
prevToken: String? = null,
|
||||
nextToken: String? = null,
|
||||
isLimited: Boolean = true): ChunkEntity {
|
||||
isLimited: Boolean = true,
|
||||
stateIndexOffset: Int = 0): ChunkEntity {
|
||||
|
||||
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||
val chunkEntity = if (!isLimited) {
|
||||
val chunkEntity = if (!isLimited && lastChunk != null) {
|
||||
lastChunk
|
||||
} else {
|
||||
val eventIds = eventList.filter { it.eventId != null }.map { it.eventId!! }
|
||||
ChunkEntity.findAllIncludingEvents(realm, eventIds).firstOrNull()
|
||||
} ?: realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken }
|
||||
realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken }
|
||||
}
|
||||
|
||||
lastChunk?.isLast = false
|
||||
chunkEntity.isLast = true
|
||||
chunkEntity.nextToken = nextToken
|
||||
|
||||
chunkEntity.addAll(eventList, PaginationDirection.FORWARDS)
|
||||
chunkEntity.addAll(eventList, PaginationDirection.FORWARDS, stateIndexOffset)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
package im.vector.matrix.android.internal.session.sync
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.database.DBConstants
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.query.find
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
|
||||
internal class StateEventsChunkHandler {
|
||||
|
||||
fun handle(realm: Realm, roomId: String, stateEvents: List<Event>): ChunkEntity {
|
||||
val chunkEntity = ChunkEntity.find(realm, roomId, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
?: realm.createObject<ChunkEntity>()
|
||||
.apply {
|
||||
prevToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
|
||||
nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
|
||||
nextStateIndex = Int.MIN_VALUE
|
||||
prevStateIndex = Int.MIN_VALUE
|
||||
}
|
||||
|
||||
// We always consider going forwards as data from server are the most recent
|
||||
chunkEntity.addAll(stateEvents, direction = PaginationDirection.FORWARDS, updateStateIndex = false)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -17,16 +17,12 @@ internal class SyncModule : Module {
|
||||
retrofit.create(SyncAPI::class.java)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
StateEventsChunkHandler()
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
ReadReceiptHandler()
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomSyncHandler(get(), get(), get())
|
||||
RoomSyncHandler(get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
Loading…
Reference in New Issue
Block a user