2019-01-18 10:12:08 +00:00
|
|
|
/*
|
2019-01-25 13:04:59 +00:00
|
|
|
* Copyright 2019 New Vector Ltd
|
2019-01-18 10:12:08 +00:00
|
|
|
*
|
2019-01-25 13:04:59 +00:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2019-01-18 10:12:08 +00:00
|
|
|
*
|
2019-01-25 13:04:59 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2019-01-18 10:12:08 +00:00
|
|
|
*/
|
|
|
|
|
2018-10-17 16:21:09 +00:00
|
|
|
package im.vector.matrix.android.internal.session.sync
|
2018-10-11 18:01:08 +00:00
|
|
|
|
2018-10-18 09:16:02 +00:00
|
|
|
import com.zhuinden.monarchy.Monarchy
|
2018-10-17 16:21:09 +00:00
|
|
|
import im.vector.matrix.android.api.session.events.model.Event
|
2018-10-24 16:11:01 +00:00
|
|
|
import im.vector.matrix.android.api.session.events.model.EventType
|
2018-12-18 11:13:46 +00:00
|
|
|
import im.vector.matrix.android.api.session.events.model.toModel
|
2018-10-23 16:25:28 +00:00
|
|
|
import im.vector.matrix.android.api.session.room.model.MyMembership
|
2019-01-29 13:16:22 +00:00
|
|
|
import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent
|
2018-11-15 17:32:39 +00:00
|
|
|
import im.vector.matrix.android.internal.database.helper.addAll
|
2018-11-15 18:00:15 +00:00
|
|
|
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
2018-11-22 10:20:50 +00:00
|
|
|
import im.vector.matrix.android.internal.database.helper.addStateEvents
|
|
|
|
import im.vector.matrix.android.internal.database.helper.lastStateIndex
|
2018-10-12 17:26:22 +00:00
|
|
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
|
|
|
import im.vector.matrix.android.internal.database.model.RoomEntity
|
2018-10-23 16:25:28 +00:00
|
|
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
2018-10-22 13:17:50 +00:00
|
|
|
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
2018-10-18 16:38:11 +00:00
|
|
|
import im.vector.matrix.android.internal.database.query.where
|
2018-11-13 18:17:59 +00:00
|
|
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
2019-01-25 17:04:08 +00:00
|
|
|
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
|
|
|
|
import im.vector.matrix.android.internal.session.sync.model.RoomSync
|
2019-01-29 13:16:22 +00:00
|
|
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncAccountData
|
2019-01-25 17:04:08 +00:00
|
|
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncEphemeral
|
|
|
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
|
|
|
import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications
|
|
|
|
import im.vector.matrix.android.internal.session.sync.model.RoomsSyncResponse
|
2018-10-15 17:42:13 +00:00
|
|
|
import io.realm.Realm
|
2018-10-26 10:31:47 +00:00
|
|
|
import io.realm.kotlin.createObject
|
2018-10-11 18:01:08 +00:00
|
|
|
|
2018-10-24 16:11:01 +00:00
|
|
|
internal class RoomSyncHandler(private val monarchy: Monarchy,
|
2019-01-29 13:16:22 +00:00
|
|
|
private val readReceiptHandler: ReadReceiptHandler,
|
|
|
|
private val roomTagHandler: RoomTagHandler) {
|
2018-10-11 18:01:08 +00:00
|
|
|
|
2018-10-15 17:42:13 +00:00
|
|
|
sealed class HandlingStrategy {
|
|
|
|
data class JOINED(val data: Map<String, RoomSync>) : HandlingStrategy()
|
|
|
|
data class INVITED(val data: Map<String, InvitedRoomSync>) : HandlingStrategy()
|
|
|
|
data class LEFT(val data: Map<String, RoomSync>) : HandlingStrategy()
|
|
|
|
}
|
2018-10-11 18:01:08 +00:00
|
|
|
|
2018-10-30 17:22:29 +00:00
|
|
|
fun handle(roomsSyncResponse: RoomsSyncResponse) {
|
|
|
|
monarchy.runTransactionSync { realm ->
|
2018-11-05 13:31:45 +00:00
|
|
|
handleRoomSync(realm, RoomSyncHandler.HandlingStrategy.JOINED(roomsSyncResponse.join))
|
|
|
|
handleRoomSync(realm, RoomSyncHandler.HandlingStrategy.INVITED(roomsSyncResponse.invite))
|
|
|
|
handleRoomSync(realm, RoomSyncHandler.HandlingStrategy.LEFT(roomsSyncResponse.leave))
|
2018-10-30 17:22:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PRIVATE METHODS *****************************************************************************
|
|
|
|
|
2018-11-05 13:31:45 +00:00
|
|
|
private fun handleRoomSync(realm: Realm, handlingStrategy: HandlingStrategy) {
|
|
|
|
val rooms = when (handlingStrategy) {
|
2019-01-25 17:04:08 +00:00
|
|
|
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) }
|
2018-11-05 13:31:45 +00:00
|
|
|
is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedRoom(realm, it.key, it.value) }
|
2019-01-25 17:04:08 +00:00
|
|
|
is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) }
|
2018-10-12 17:26:22 +00:00
|
|
|
}
|
2018-11-05 13:31:45 +00:00
|
|
|
realm.insertOrUpdate(rooms)
|
2018-10-24 16:11:01 +00:00
|
|
|
}
|
2018-10-15 17:42:13 +00:00
|
|
|
|
|
|
|
private fun handleJoinedRoom(realm: Realm,
|
|
|
|
roomId: String,
|
|
|
|
roomSync: RoomSync): RoomEntity {
|
|
|
|
|
2018-10-26 10:31:47 +00:00
|
|
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
2019-01-25 17:04:08 +00:00
|
|
|
?: realm.createObject(roomId)
|
2018-10-15 17:42:13 +00:00
|
|
|
|
2018-10-23 16:25:28 +00:00
|
|
|
if (roomEntity.membership == MyMembership.INVITED) {
|
2018-10-15 17:42:13 +00:00
|
|
|
roomEntity.chunks.deleteAllFromRealm()
|
2018-10-12 17:26:22 +00:00
|
|
|
}
|
2018-10-15 17:42:13 +00:00
|
|
|
|
2018-10-23 16:25:28 +00:00
|
|
|
roomEntity.membership = MyMembership.JOINED
|
|
|
|
|
2018-11-22 10:20:50 +00:00
|
|
|
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
|
|
|
|
|
2018-10-15 17:42:13 +00:00
|
|
|
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
2018-11-22 10:20:50 +00:00
|
|
|
val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset
|
2019-02-26 13:50:53 +00:00
|
|
|
roomEntity.addStateEvents(roomSync.state.events, filterDuplicates = true, stateIndex = untimelinedStateIndex)
|
2018-10-15 17:42:13 +00:00
|
|
|
}
|
2018-11-13 18:17:59 +00:00
|
|
|
|
2018-10-15 17:42:13 +00:00
|
|
|
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
2018-11-22 10:20:50 +00:00
|
|
|
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
|
|
|
|
)
|
2018-11-15 18:00:15 +00:00
|
|
|
roomEntity.addOrUpdate(chunkEntity)
|
2018-10-12 17:26:22 +00:00
|
|
|
}
|
2018-11-05 13:31:45 +00:00
|
|
|
|
2018-10-29 13:57:36 +00:00
|
|
|
if (roomSync.summary != null) {
|
|
|
|
handleRoomSummary(realm, roomId, roomSync.summary)
|
|
|
|
}
|
2018-11-05 13:31:45 +00:00
|
|
|
|
2019-01-25 17:04:08 +00:00
|
|
|
if (roomSync.unreadNotifications != null) {
|
|
|
|
handleUnreadNotifications(realm, roomId, roomSync.unreadNotifications)
|
|
|
|
}
|
|
|
|
|
2018-11-05 13:31:45 +00:00
|
|
|
if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) {
|
|
|
|
handleEphemeral(realm, roomId, roomSync.ephemeral)
|
|
|
|
}
|
2019-01-25 17:04:08 +00:00
|
|
|
|
2019-01-29 13:16:22 +00:00
|
|
|
if (roomSync.accountData != null && roomSync.accountData.events.isNullOrEmpty().not()) {
|
|
|
|
handleRoomAccountDataEvents(realm, roomId, roomSync.accountData)
|
|
|
|
}
|
|
|
|
|
2018-10-15 17:42:13 +00:00
|
|
|
return roomEntity
|
|
|
|
}
|
2018-10-12 17:26:22 +00:00
|
|
|
|
2018-10-15 17:42:13 +00:00
|
|
|
private fun handleInvitedRoom(realm: Realm,
|
|
|
|
roomId: String,
|
|
|
|
roomSync:
|
|
|
|
InvitedRoomSync): RoomEntity {
|
|
|
|
val roomEntity = RoomEntity()
|
|
|
|
roomEntity.roomId = roomId
|
2018-10-23 16:25:28 +00:00
|
|
|
roomEntity.membership = MyMembership.INVITED
|
2018-10-15 17:42:13 +00:00
|
|
|
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
2018-10-26 10:31:47 +00:00
|
|
|
val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.inviteState.events)
|
2018-11-15 18:00:15 +00:00
|
|
|
roomEntity.addOrUpdate(chunkEntity)
|
2018-10-12 17:26:22 +00:00
|
|
|
}
|
|
|
|
return roomEntity
|
|
|
|
}
|
2018-10-11 18:01:08 +00:00
|
|
|
|
2018-10-15 17:42:13 +00:00
|
|
|
// TODO : handle it
|
|
|
|
private fun handleLeftRoom(roomId: String,
|
|
|
|
roomSync: RoomSync): RoomEntity {
|
|
|
|
return RoomEntity().apply {
|
|
|
|
this.roomId = roomId
|
2018-10-23 16:25:28 +00:00
|
|
|
this.membership = MyMembership.LEFT
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-26 10:31:47 +00:00
|
|
|
private fun handleTimelineEvents(realm: Realm,
|
|
|
|
roomId: String,
|
|
|
|
eventList: List<Event>,
|
|
|
|
prevToken: String? = null,
|
2018-11-22 10:20:50 +00:00
|
|
|
isLimited: Boolean = true,
|
|
|
|
stateIndexOffset: Int = 0): ChunkEntity {
|
2018-11-13 09:50:53 +00:00
|
|
|
|
|
|
|
val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
2018-11-22 10:20:50 +00:00
|
|
|
val chunkEntity = if (!isLimited && lastChunk != null) {
|
2018-11-13 09:50:53 +00:00
|
|
|
lastChunk
|
2018-10-15 17:42:13 +00:00
|
|
|
} else {
|
2018-11-22 10:20:50 +00:00
|
|
|
realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken }
|
|
|
|
}
|
2018-10-15 17:42:13 +00:00
|
|
|
|
2018-11-13 09:50:53 +00:00
|
|
|
lastChunk?.isLast = false
|
|
|
|
chunkEntity.isLast = true
|
2019-01-03 16:10:02 +00:00
|
|
|
chunkEntity.addAll(roomId, eventList, PaginationDirection.FORWARDS, stateIndexOffset)
|
2018-10-13 09:18:49 +00:00
|
|
|
return chunkEntity
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:00:15 +00:00
|
|
|
private fun handleRoomSummary(realm: Realm,
|
|
|
|
roomId: String,
|
|
|
|
roomSummary: RoomSyncSummary) {
|
|
|
|
|
|
|
|
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
2019-01-25 17:04:08 +00:00
|
|
|
?: RoomSummaryEntity(roomId)
|
2018-11-15 18:00:15 +00:00
|
|
|
|
|
|
|
if (roomSummary.heroes.isNotEmpty()) {
|
|
|
|
roomSummaryEntity.heroes.clear()
|
|
|
|
roomSummaryEntity.heroes.addAll(roomSummary.heroes)
|
|
|
|
}
|
|
|
|
if (roomSummary.invitedMembersCount != null) {
|
|
|
|
roomSummaryEntity.invitedMembersCount = roomSummary.invitedMembersCount
|
|
|
|
}
|
|
|
|
if (roomSummary.joinedMembersCount != null) {
|
|
|
|
roomSummaryEntity.joinedMembersCount = roomSummary.joinedMembersCount
|
|
|
|
}
|
|
|
|
realm.insertOrUpdate(roomSummaryEntity)
|
|
|
|
}
|
|
|
|
|
2018-10-24 16:11:01 +00:00
|
|
|
private fun handleEphemeral(realm: Realm,
|
|
|
|
roomId: String,
|
2018-11-05 13:31:45 +00:00
|
|
|
ephemeral: RoomSyncEphemeral) {
|
2018-10-24 16:11:01 +00:00
|
|
|
ephemeral.events
|
|
|
|
.filter { it.type == EventType.RECEIPT }
|
2018-12-18 11:13:46 +00:00
|
|
|
.map { it.content.toModel<ReadReceiptContent>() }
|
2018-10-24 16:11:01 +00:00
|
|
|
.flatMap { readReceiptHandler.handle(realm, roomId, it) }
|
|
|
|
}
|
2019-01-25 17:04:08 +00:00
|
|
|
|
|
|
|
private fun handleUnreadNotifications(realm: Realm, roomId: String, unreadNotifications: RoomSyncUnreadNotifications) {
|
|
|
|
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
|
|
|
?: RoomSummaryEntity(roomId)
|
|
|
|
|
|
|
|
if (unreadNotifications.highlightCount != null) {
|
|
|
|
roomSummaryEntity.highlightCount = unreadNotifications.highlightCount
|
|
|
|
}
|
|
|
|
if (unreadNotifications.notificationCount != null) {
|
|
|
|
roomSummaryEntity.notificationCount = unreadNotifications.notificationCount
|
|
|
|
}
|
|
|
|
realm.insertOrUpdate(roomSummaryEntity)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-29 13:16:22 +00:00
|
|
|
private fun handleRoomAccountDataEvents(realm: Realm, roomId: String, accountData: RoomSyncAccountData) {
|
|
|
|
accountData.events
|
|
|
|
.filter { it.type == EventType.TAG }
|
|
|
|
.map { it.content.toModel<RoomTagContent>() }
|
|
|
|
.forEach { roomTagHandler.handle(realm, roomId, it) }
|
|
|
|
}
|
|
|
|
|
2018-10-11 18:01:08 +00:00
|
|
|
}
|