package im.vector.matrix.android.internal.events.sync import im.vector.matrix.android.api.events.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 import im.vector.matrix.android.internal.database.query.getChunkIncludingEvents import im.vector.matrix.android.internal.database.query.getForId import im.vector.matrix.android.internal.database.query.getLastChunkFromRoom import im.vector.matrix.android.internal.events.sync.data.InvitedRoomSync import im.vector.matrix.android.internal.events.sync.data.RoomSync import io.realm.Realm import io.realm.RealmConfiguration class RoomSyncHandler(private val realmConfiguration: RealmConfiguration) { sealed class HandlingStrategy { data class JOINED(val data: Map) : HandlingStrategy() data class INVITED(val data: Map) : HandlingStrategy() data class LEFT(val data: Map) : HandlingStrategy() } fun handleRoomSync(handlingStrategy: HandlingStrategy) { val realm = Realm.getInstance(realmConfiguration) realm.executeTransaction { realmInstance -> val roomEntities = when (handlingStrategy) { is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) } is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedRoom(realm, it.key, it.value) } is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) } } realmInstance.insertOrUpdate(roomEntities) } realm.close() } // PRIVATE METHODS ***************************************************************************** private fun handleJoinedRoom(realm: Realm, roomId: String, roomSync: RoomSync): RoomEntity { val roomEntity = RoomEntity.getForId(realm, roomId) ?: RoomEntity(roomId) if (roomEntity.membership == RoomEntity.Membership.INVITED) { roomEntity.chunks.deleteAllFromRealm() } roomEntity.membership = RoomEntity.Membership.JOINED if (roomSync.state != null && roomSync.state.events.isNotEmpty()) { val chunkEntity = eventListToChunk(realm, roomId, roomSync.state.events) if (!roomEntity.chunks.contains(chunkEntity)) { roomEntity.chunks.add(chunkEntity) } } if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) { val chunkEntity = eventListToChunk(realm, roomId, roomSync.timeline.events, roomSync.timeline.prevToken, isLimited = roomSync.timeline.limited) if (!roomEntity.chunks.contains(chunkEntity)) { roomEntity.chunks.add(chunkEntity) } } return roomEntity } private fun handleInvitedRoom(realm: Realm, roomId: String, roomSync: InvitedRoomSync): RoomEntity { val roomEntity = RoomEntity() roomEntity.roomId = roomId roomEntity.membership = RoomEntity.Membership.INVITED if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) { val chunkEntity = eventListToChunk(realm, roomId, roomSync.inviteState.events) if (!roomEntity.chunks.contains(chunkEntity)) { roomEntity.chunks.add(chunkEntity) } } return roomEntity } // TODO : handle it private fun handleLeftRoom(roomId: String, roomSync: RoomSync): RoomEntity { return RoomEntity().apply { this.roomId = roomId this.membership = RoomEntity.Membership.LEFT } } private fun eventListToChunk(realm: Realm, roomId: String, eventList: List, prevToken: String? = null, nextToken: String? = null, isLimited: Boolean = true): ChunkEntity { val chunkEntity = if (!isLimited) { ChunkEntity.getLastChunkFromRoom(realm, roomId) } else { val eventIds = eventList.filter { it.eventId != null }.map { it.eventId!! } ChunkEntity.getChunkIncludingEvents(realm, eventIds) } ?: ChunkEntity().apply { this.prevToken = prevToken } chunkEntity.nextToken = nextToken chunkEntity.isLimited = isLimited eventList.forEach { event -> val eventEntity = event.asEntity().let { realm.copyToRealmOrUpdate(it) } if (!chunkEntity.events.contains(eventEntity)) { chunkEntity.events.add(eventEntity) } } return chunkEntity } }