mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Clean some code about chunk and fix merging chunk
This commit is contained in:
parent
40f981e454
commit
bb0a70f3c0
@ -1,13 +1,41 @@
|
||||
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.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.query.fastContains
|
||||
import im.vector.matrix.android.internal.database.query.find
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||
|
||||
internal fun ChunkEntity.add(event: Event, stateIndex: Int, paginationDirection: PaginationDirection) {
|
||||
if (!this.isManaged) {
|
||||
|
||||
internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
|
||||
direction: PaginationDirection) {
|
||||
|
||||
val events = chunkEntity.events.map { it.asDomain() }
|
||||
addAll(events, direction)
|
||||
if (direction == PaginationDirection.FORWARDS) {
|
||||
nextToken = chunkEntity.nextToken
|
||||
} else {
|
||||
prevToken = chunkEntity.prevToken
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.addAll(events: List<Event>,
|
||||
direction: PaginationDirection,
|
||||
updateStateIndex: Boolean = true) {
|
||||
|
||||
events.forEach { event ->
|
||||
if (updateStateIndex && event.isStateEvent()) {
|
||||
updateStateIndex(direction)
|
||||
}
|
||||
addOrUpdate(event, direction)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||
direction: PaginationDirection) {
|
||||
if (!isManaged) {
|
||||
throw IllegalStateException("Chunk entity should be managed to use fast contains")
|
||||
}
|
||||
|
||||
@ -15,11 +43,14 @@ internal fun ChunkEntity.add(event: Event, stateIndex: Int, paginationDirection:
|
||||
return
|
||||
}
|
||||
|
||||
val eventEntity = event.asEntity()
|
||||
eventEntity.stateIndex = stateIndex
|
||||
|
||||
if (!this.events.fastContains(eventEntity)) {
|
||||
val position = if (paginationDirection == PaginationDirection.FORWARDS) 0 else this.events.size
|
||||
this.events.add(position, eventEntity)
|
||||
val currentStateIndex = stateIndex(direction)
|
||||
if (!events.fastContains(event.eventId)) {
|
||||
val eventEntity = event.asEntity()
|
||||
eventEntity.stateIndex = currentStateIndex
|
||||
val position = if (direction == PaginationDirection.FORWARDS) 0 else this.events.size
|
||||
events.add(position, eventEntity)
|
||||
} else {
|
||||
val eventEntity = events.find(event.eventId)
|
||||
eventEntity?.stateIndex = currentStateIndex
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package 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
|
||||
|
||||
|
||||
internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) {
|
||||
chunks.remove(chunkEntity)
|
||||
chunkEntity.events.deleteAllFromRealm()
|
||||
chunkEntity.deleteFromRealm()
|
||||
}
|
@ -13,16 +13,7 @@ internal object EventMapper {
|
||||
|
||||
fun map(event: Event): EventEntity {
|
||||
val eventEntity = EventEntity()
|
||||
eventEntity.eventId = event.eventId ?: ""
|
||||
eventEntity.content = adapter.toJson(event.content)
|
||||
val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent
|
||||
eventEntity.prevContent = adapter.toJson(resolvedPrevContent)
|
||||
eventEntity.stateKey = event.stateKey
|
||||
eventEntity.type = event.type
|
||||
eventEntity.sender = event.sender
|
||||
eventEntity.originServerTs = event.originServerTs
|
||||
eventEntity.redacts = event.redacts
|
||||
eventEntity.age = event.unsignedData?.age ?: event.originServerTs
|
||||
fill(eventEntity, with = event)
|
||||
return eventEntity
|
||||
}
|
||||
|
||||
@ -40,6 +31,20 @@ internal object EventMapper {
|
||||
redacts = eventEntity.redacts
|
||||
)
|
||||
}
|
||||
|
||||
fun fill(eventEntity: EventEntity, with: Event) {
|
||||
eventEntity.eventId = with.eventId ?: ""
|
||||
eventEntity.content = adapter.toJson(with.content)
|
||||
val resolvedPrevContent = with.prevContent ?: with.unsignedData?.prevContent
|
||||
eventEntity.prevContent = adapter.toJson(resolvedPrevContent)
|
||||
eventEntity.stateKey = with.stateKey
|
||||
eventEntity.type = with.type
|
||||
eventEntity.sender = with.sender
|
||||
eventEntity.originServerTs = with.originServerTs
|
||||
eventEntity.redacts = with.redacts
|
||||
eventEntity.age = with.unsignedData?.age ?: with.originServerTs
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun EventEntity.asDomain(): Event {
|
||||
@ -48,4 +53,8 @@ internal fun EventEntity.asDomain(): Event {
|
||||
|
||||
internal fun Event.asEntity(): EventEntity {
|
||||
return EventMapper.map(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun EventEntity.fillWith(event: Event) {
|
||||
EventMapper.fill(this, with = event)
|
||||
}
|
||||
|
@ -26,12 +26,11 @@ internal open class ChunkEntity(var prevToken: String? = null,
|
||||
}
|
||||
}
|
||||
|
||||
fun updateStateIndex(stateIndex: Int, direction: PaginationDirection){
|
||||
fun updateStateIndex(direction: PaginationDirection) {
|
||||
when (direction) {
|
||||
PaginationDirection.FORWARDS -> nextStateIndex = stateIndex
|
||||
PaginationDirection.BACKWARDS -> prevStateIndex = stateIndex
|
||||
PaginationDirection.FORWARDS -> nextStateIndex += 1
|
||||
PaginationDirection.BACKWARDS -> prevStateIndex -= 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -14,24 +14,15 @@ internal fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQue
|
||||
.equalTo("${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.Companion.findWithPrevToken(realm: Realm, roomId: String, prevToken: String?): ChunkEntity? {
|
||||
if (prevToken == null) {
|
||||
return null
|
||||
internal fun ChunkEntity.Companion.find(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): ChunkEntity? {
|
||||
val query = where(realm, roomId)
|
||||
if (prevToken != null) {
|
||||
query.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
|
||||
}
|
||||
return where(realm, roomId)
|
||||
.and()
|
||||
.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.Companion.findWithNextToken(realm: Realm, roomId: String, nextToken: String?): ChunkEntity? {
|
||||
if (nextToken == null) {
|
||||
return null
|
||||
if (nextToken != null) {
|
||||
query.equalTo(ChunkEntityFields.NEXT_TOKEN, nextToken)
|
||||
}
|
||||
return where(realm, roomId)
|
||||
.and()
|
||||
.equalTo(ChunkEntityFields.NEXT_TOKEN, nextToken)
|
||||
.findFirst()
|
||||
return query.findFirst()
|
||||
}
|
||||
|
||||
internal fun ChunkEntity.Companion.findLastLiveChunkFromRoom(realm: Realm, roomId: String): ChunkEntity? {
|
||||
|
@ -46,6 +46,10 @@ internal fun RealmQuery<EventEntity>.last(): EventEntity? {
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
internal fun RealmList<EventEntity>.fastContains(eventEntity: EventEntity): Boolean {
|
||||
return this.where().equalTo(EventEntityFields.EVENT_ID, eventEntity.eventId).findFirst() != null
|
||||
internal fun RealmList<EventEntity>.find(eventId: String): EventEntity? {
|
||||
return this.where().equalTo(EventEntityFields.EVENT_ID, eventId).findFirst()
|
||||
}
|
||||
|
||||
internal fun RealmList<EventEntity>.fastContains(eventId: String): Boolean {
|
||||
return this.find(eventId) != null
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ 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.findWithNextToken
|
||||
import im.vector.matrix.android.internal.database.query.last
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
@ -32,7 +32,7 @@ internal class RoomMemberExtractor(private val realm: Realm,
|
||||
}
|
||||
|
||||
// If the content is null, we try get the last state event coming from a state events chunk
|
||||
val stateChunkEntity = ChunkEntity.findWithNextToken(realm, roomId, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
val stateChunkEntity = ChunkEntity.find(realm, roomId, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
?: return null
|
||||
|
||||
return buildQuery(stateChunkEntity, event.sender)
|
||||
|
@ -13,11 +13,4 @@ internal enum class PaginationDirection(val value: String) {
|
||||
*/
|
||||
BACKWARDS("b");
|
||||
|
||||
val incrementStateIndex: Int by lazy {
|
||||
when (this) {
|
||||
FORWARDS -> 1
|
||||
BACKWARDS -> -1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -4,15 +4,14 @@ import arrow.core.Try
|
||||
import arrow.core.failure
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.helper.add
|
||||
import im.vector.matrix.android.internal.database.helper.addAll
|
||||
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
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.fastContains
|
||||
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.findWithNextToken
|
||||
import im.vector.matrix.android.internal.database.query.findWithPrevToken
|
||||
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
|
||||
@ -29,7 +28,8 @@ 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 stateEventsChunkHandler: StateEventsChunkHandler
|
||||
) {
|
||||
|
||||
fun execute(roomId: String,
|
||||
from: String?,
|
||||
@ -67,52 +67,33 @@ internal class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: throw IllegalStateException("You shouldn't use this method without a room")
|
||||
|
||||
val currentChunk = ChunkEntity.findWithPrevToken(realm, roomId, receivedChunk.nextToken)
|
||||
val currentChunk = ChunkEntity.find(realm, roomId, prevToken = receivedChunk.nextToken)
|
||||
?: realm.createObject()
|
||||
|
||||
currentChunk.prevToken = receivedChunk.prevToken
|
||||
currentChunk.addAll(receivedChunk.events, direction)
|
||||
|
||||
val prevChunk = ChunkEntity.findWithNextToken(realm, roomId, receivedChunk.prevToken)
|
||||
|
||||
val eventIds = receivedChunk.events.filter { it.eventId != null }.map { it.eventId!! }
|
||||
val chunksOverlapped = realm.copyFromRealm(ChunkEntity.findAllIncludingEvents(realm, eventIds))
|
||||
val hasOverlapped = chunksOverlapped.isNotEmpty()
|
||||
|
||||
var currentStateIndex = currentChunk.stateIndex(direction)
|
||||
val incrementStateIndex = direction.incrementStateIndex
|
||||
|
||||
receivedChunk.events.forEach { event ->
|
||||
if (EventType.isStateEvent(event.type)) {
|
||||
currentStateIndex += incrementStateIndex
|
||||
}
|
||||
currentChunk.add(event, currentStateIndex, direction)
|
||||
}
|
||||
// Now, handles chunk merge
|
||||
|
||||
val prevChunk = ChunkEntity.find(realm, roomId, nextToken = receivedChunk.prevToken)
|
||||
if (prevChunk != null) {
|
||||
currentChunk.events.addAll(prevChunk.events)
|
||||
roomEntity.chunks.remove(prevChunk)
|
||||
|
||||
} else if (hasOverlapped) {
|
||||
chunksOverlapped.forEach { overlapped ->
|
||||
overlapped.events.forEach { event ->
|
||||
if (!currentChunk.events.fastContains(event)) {
|
||||
currentChunk.events.add(event)
|
||||
currentChunk.merge(prevChunk, direction)
|
||||
roomEntity.deleteOnCascade(prevChunk)
|
||||
} else {
|
||||
val eventIds = receivedChunk.events.mapNotNull { it.eventId }
|
||||
ChunkEntity
|
||||
.findAllIncludingEvents(realm, eventIds)
|
||||
.filter { it != currentChunk }
|
||||
.forEach { overlapped ->
|
||||
currentChunk.merge(overlapped, direction)
|
||||
roomEntity.deleteOnCascade(overlapped)
|
||||
}
|
||||
if (EventType.isStateEvent(event.type)) {
|
||||
currentStateIndex += incrementStateIndex
|
||||
}
|
||||
}
|
||||
currentChunk.prevToken = overlapped.prevToken
|
||||
roomEntity.chunks.remove(overlapped)
|
||||
}
|
||||
}
|
||||
|
||||
if (!roomEntity.chunks.contains(currentChunk)) {
|
||||
roomEntity.chunks.add(currentChunk)
|
||||
}
|
||||
|
||||
currentChunk.updateStateIndex(currentStateIndex, direction)
|
||||
|
||||
// TODO : there is an issue with the pagination sending unwanted room member events
|
||||
val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, receivedChunk.stateEvents)
|
||||
if (!roomEntity.chunks.contains(stateEventsChunk)) {
|
||||
@ -122,4 +103,5 @@ internal class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
.map { receivedChunk }
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -11,9 +11,9 @@ import java.util.*
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
internal class TimelineBoundaryCallback(private val roomId: String,
|
||||
private val paginationRequest: PaginationRequest,
|
||||
private val monarchy: Monarchy,
|
||||
ioExecutor: Executor
|
||||
private val paginationRequest: PaginationRequest,
|
||||
private val monarchy: Monarchy,
|
||||
ioExecutor: Executor
|
||||
) : PagedList.BoundaryCallback<EnrichedEvent>() {
|
||||
|
||||
private val helper = PagingRequestHelper(ioExecutor)
|
||||
|
@ -4,7 +4,7 @@ import com.zhuinden.monarchy.Monarchy
|
||||
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.room.model.MyMembership
|
||||
import im.vector.matrix.android.internal.database.helper.add
|
||||
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.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
@ -151,14 +151,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
chunkEntity.isLast = true
|
||||
chunkEntity.nextToken = nextToken
|
||||
|
||||
var currentStateIndex = chunkEntity.nextStateIndex
|
||||
eventList.forEach { event ->
|
||||
if (event.isStateEvent()) {
|
||||
currentStateIndex += PaginationDirection.FORWARDS.incrementStateIndex
|
||||
}
|
||||
chunkEntity.add(event, currentStateIndex, PaginationDirection.FORWARDS)
|
||||
}
|
||||
chunkEntity.nextStateIndex = currentStateIndex
|
||||
chunkEntity.addAll(eventList, PaginationDirection.FORWARDS)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,9 @@ 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.add
|
||||
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.findWithNextToken
|
||||
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
|
||||
@ -12,7 +12,7 @@ import io.realm.kotlin.createObject
|
||||
internal class StateEventsChunkHandler {
|
||||
|
||||
fun handle(realm: Realm, roomId: String, stateEvents: List<Event>): ChunkEntity {
|
||||
val chunkEntity = ChunkEntity.findWithNextToken(realm, roomId, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
val chunkEntity = ChunkEntity.find(realm, roomId, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
?: realm.createObject<ChunkEntity>()
|
||||
.apply {
|
||||
prevToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
|
||||
@ -22,12 +22,7 @@ internal class StateEventsChunkHandler {
|
||||
}
|
||||
|
||||
// We always consider going forwards as data from server are the most recent
|
||||
val direction = PaginationDirection.FORWARDS
|
||||
val stateIndex = chunkEntity.stateIndex(direction) + direction.incrementStateIndex
|
||||
stateEvents.forEach { event ->
|
||||
chunkEntity.add(event, stateIndex, direction)
|
||||
}
|
||||
chunkEntity.updateStateIndex(stateIndex, direction)
|
||||
chunkEntity.addAll(stateEvents, direction = PaginationDirection.FORWARDS, updateStateIndex = false)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user