BayernMessenger/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt

110 lines
5.1 KiB
Kotlin
Raw Normal View History

2019-01-18 10:12:08 +00:00
/*
*
* * Copyright 2019 New Vector Ltd
* *
* * 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
* *
* * 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.
*
*/
package im.vector.matrix.android.internal.session.room.timeline
import arrow.core.Try
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.helper.*
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
2018-11-29 17:35:24 +00:00
import im.vector.matrix.android.internal.database.query.create
import im.vector.matrix.android.internal.database.query.find
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.util.tryTransactionSync
internal class TokenChunkEventPersistor(private val monarchy: Monarchy) {
fun insertInDb(receivedChunk: TokenChunkEvent,
roomId: String,
direction: PaginationDirection): Try<Boolean> {
if (receivedChunk.events.isEmpty() && receivedChunk.stateEvents.isEmpty()) {
return Try.just(false)
}
return monarchy
.tryTransactionSync { realm ->
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
?: throw IllegalStateException("You shouldn't use this method without a room")
2018-11-29 17:35:24 +00:00
val nextToken: String?
val prevToken: String?
if (direction == PaginationDirection.FORWARDS) {
nextToken = receivedChunk.end
prevToken = receivedChunk.start
} else {
nextToken = receivedChunk.start
prevToken = receivedChunk.end
}
2018-11-29 17:35:24 +00:00
val prevChunk = ChunkEntity.find(realm, roomId, nextToken = prevToken)
val nextChunk = ChunkEntity.find(realm, roomId, prevToken = nextToken)
// The current chunk is the one we will keep all along the merge process.
2018-11-29 17:35:24 +00:00
// We try to look for a chunk next to the token,
// otherwise we create a whole new one
2018-11-29 17:35:24 +00:00
var currentChunk = if (direction == PaginationDirection.FORWARDS) {
prevChunk?.apply { this.nextToken = nextToken }
?: ChunkEntity.create(realm, prevToken, nextToken)
2018-11-29 17:35:24 +00:00
} else {
nextChunk?.apply { this.prevToken = prevToken }
?: ChunkEntity.create(realm, prevToken, nextToken)
}
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
2018-11-29 17:35:24 +00:00
// Then we merge chunks if needed
if (currentChunk != prevChunk && prevChunk != null) {
currentChunk = handleMerge(roomEntity, direction, currentChunk, prevChunk)
} else if (currentChunk != nextChunk && nextChunk != null) {
currentChunk = handleMerge(roomEntity, direction, currentChunk, nextChunk)
} else {
val newEventIds = receivedChunk.events.mapNotNull { it.eventId }
ChunkEntity
.findAllIncludingEvents(realm, newEventIds)
.filter { it != currentChunk }
.forEach { overlapped ->
currentChunk = handleMerge(roomEntity, direction, currentChunk, overlapped)
}
}
roomEntity.addOrUpdate(currentChunk)
roomEntity.addStateEvents(receivedChunk.stateEvents, isUnlinked = currentChunk.isUnlinked())
}
.map { true }
}
2018-11-29 17:35:24 +00:00
private fun handleMerge(roomEntity: RoomEntity,
direction: PaginationDirection,
currentChunk: ChunkEntity,
otherChunk: ChunkEntity): ChunkEntity {
// We always merge the bottom chunk into top chunk, so we are always merging backwards
return if (direction == PaginationDirection.BACKWARDS) {
2019-01-07 18:38:49 +00:00
currentChunk.merge(roomEntity.roomId, otherChunk, PaginationDirection.BACKWARDS)
2018-11-29 17:35:24 +00:00
roomEntity.deleteOnCascade(otherChunk)
currentChunk
} else {
2019-01-07 18:38:49 +00:00
otherChunk.merge(roomEntity.roomId, currentChunk, PaginationDirection.BACKWARDS)
2018-11-29 17:35:24 +00:00
roomEntity.deleteOnCascade(currentChunk)
otherChunk
}
}
}