From 9182f2ce4ef59c833da531dbb11653b8703cef6a Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 12 Jul 2019 13:59:37 +0200 Subject: [PATCH] RoomMembers/User : get a better and faster handling (still need to fix one small issue) --- .../database/helper/ChunkEntityHelper.kt | 3 +- .../database/helper/RoomEntityHelper.kt | 24 -------- .../database/model/TimelineEventEntity.kt | 2 - .../parsing/GetRoomMembersResponseHandler.kt | 59 ------------------- .../internal/network/parsing/JsonReader.kt | 40 ------------- .../room/membership/LoadRoomMembersTask.kt | 13 ++-- .../room/timeline/TokenChunkEventPersistor.kt | 24 +++----- .../internal/session/sync/RoomSyncHandler.kt | 25 +++----- 8 files changed, 24 insertions(+), 166 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/GetRoomMembersResponseHandler.kt delete mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/JsonReader.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt index b0b88631..3bda568d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.database.helper -import androidx.annotation.VisibleForTesting 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.send.SendState @@ -133,7 +132,7 @@ internal fun ChunkEntity.add(roomId: String, } } - val localId = TimelineEventEntity.nextId(realm) + val localId = TimelineEventEntity.nextId(realm) val eventEntity = TimelineEventEntity(localId).also { it.root = event.toEntity(roomId).apply { this.stateIndex = currentStateIndex diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt index 05a8fd2d..948af2af 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.database.helper -import com.squareup.moshi.JsonReader import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.internal.database.mapper.toEntity @@ -25,10 +24,7 @@ import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.query.fastContains import im.vector.matrix.android.internal.extensions.assertIsManaged -import im.vector.matrix.android.internal.network.parsing.GetRoomMembersResponseHandler import im.vector.matrix.android.internal.session.room.membership.RoomMembers -import okhttp3.ResponseBody -import okio.Okio internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) { chunks.remove(chunkEntity) @@ -57,26 +53,6 @@ internal fun RoomEntity.addStateEvent(stateEvent: Event, untimelinedStateEvents.add(entity) } } - -internal fun RoomEntity.addStateEvents(stateEvents: List, - stateIndex: Int = Int.MIN_VALUE, - filterDuplicates: Boolean = false, - isUnlinked: Boolean = false) { - stateEvents.forEach { event -> - addStateEvent(event, stateIndex, filterDuplicates, isUnlinked) - } -} - -internal fun RoomEntity.addStateEvents(response: ResponseBody, - stateIndex: Int = Int.MIN_VALUE, - isUnlinked: Boolean = false) { - val manualParser = GetRoomMembersResponseHandler() - val bufferedSource = Okio.buffer(Okio.source(response.byteStream())) - val inputReader = JsonReader.of(bufferedSource) - manualParser.handle(inputReader, this, stateIndex, isUnlinked) -} - - internal fun RoomEntity.addSendingEvent(event: Event) { assertIsManaged() val senderId = event.senderId ?: return diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt index c811ece1..a1e58c90 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt @@ -20,8 +20,6 @@ import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.Index import io.realm.annotations.LinkingObjects -import io.realm.annotations.PrimaryKey -import java.util.* internal open class TimelineEventEntity(var localId: Long = 0, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/GetRoomMembersResponseHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/GetRoomMembersResponseHandler.kt deleted file mode 100644 index 05433513..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/GetRoomMembersResponseHandler.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.network.parsing - -import com.squareup.moshi.JsonReader -import im.vector.matrix.android.api.session.events.model.EventType -import im.vector.matrix.android.api.session.room.send.SendState -import im.vector.matrix.android.internal.database.model.EventEntity -import im.vector.matrix.android.internal.database.model.RoomEntity - -internal class GetRoomMembersResponseHandler { - - companion object { - private val NAMES = JsonReader.Options.of("event_id", "content", "prev_content", "origin_server_ts", "sender", "state_key") - } - - internal fun handle(reader: JsonReader, roomEntity: RoomEntity, stateIndex: Int = Int.MIN_VALUE, isUnlinked: Boolean = false) { - reader.readObject { - reader.nextName() - val eventEntity = EventEntity().apply { - this.roomId = roomEntity.roomId - this.stateIndex = stateIndex - this.isUnlinked = isUnlinked - this.sendState = SendState.SYNCED - this.type = EventType.STATE_ROOM_MEMBER - } - reader.readArray { - reader.readObject { - when - (reader.selectName(NAMES)) { - 0 -> eventEntity.eventId = reader.nextString() - 1 -> eventEntity.content = reader.readJsonValue()?.toString() - 2 -> eventEntity.prevContent = reader.readJsonValue()?.toString() - 3 -> eventEntity.originServerTs = reader.nextLong() - 4 -> eventEntity.sender = reader.nextString() - 5 -> eventEntity.stateKey = reader.nextString() - else -> reader.skipNameAndValue() - } - } - roomEntity.untimelinedStateEvents.add(eventEntity) - } - } - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/JsonReader.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/JsonReader.kt deleted file mode 100644 index 7d7afa7f..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/parsing/JsonReader.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.network.parsing - -import com.squareup.moshi.JsonReader - -fun JsonReader.skipNameAndValue() { - skipName() - skipValue() -} - -inline fun JsonReader.readObject(body: () -> Unit) { - beginObject() - while (hasNext()) { - body() - } - endObject() -} - -inline fun JsonReader.readArray(body: () -> Unit) { - beginArray() - while (hasNext()) { - body() - } - endArray() -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt index a059404e..3364a8e6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt @@ -17,15 +17,12 @@ package im.vector.matrix.android.internal.session.room.membership import arrow.core.Try +import com.squareup.moshi.JsonReader import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.Membership -import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.internal.database.helper.addStateEvent -import im.vector.matrix.android.internal.database.helper.addStateEvents import im.vector.matrix.android.internal.database.helper.updateSenderData import im.vector.matrix.android.internal.database.model.RoomEntity -import im.vector.matrix.android.internal.database.model.UserEntity 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 @@ -37,6 +34,7 @@ import im.vector.matrix.android.internal.util.tryTransactionSync import io.realm.Realm import io.realm.kotlin.createObject import okhttp3.ResponseBody +import okio.Okio import javax.inject.Inject internal interface LoadRoomMembersTask : Task { @@ -71,16 +69,15 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP .tryTransactionSync { realm -> // We ignore all the already known members val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) + - val userEntities = ArrayList(response.roomMemberEvents.size) for (roomMemberEvent in response.roomMemberEvents) { roomEntity.addStateEvent(roomMemberEvent) UserEntityFactory.create(roomMemberEvent)?.also { - userEntities.add(it) + realm.insertOrUpdate(it) } } - realm.insertOrUpdate(userEntities) roomEntity.chunks.flatMap { it.timelineEvents }.forEach { it.updateSenderData() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt index dda776d2..e9a34699 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -18,16 +18,9 @@ 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.addAll -import im.vector.matrix.android.internal.database.helper.addOrUpdate -import im.vector.matrix.android.internal.database.helper.addStateEvent -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.isUnlinked -import im.vector.matrix.android.internal.database.helper.merge +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 -import im.vector.matrix.android.internal.database.model.UserEntity 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 @@ -120,7 +113,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy Timber.v("Start persisting ${receivedChunk.events.size} events in $roomId towards $direction") val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) val nextToken: String? val prevToken: String? @@ -149,18 +142,19 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy } else { nextChunk?.apply { this.prevToken = prevToken } } - ?: ChunkEntity.create(realm, prevToken, nextToken) + ?: ChunkEntity.create(realm, prevToken, nextToken) if (receivedChunk.events.isEmpty() && receivedChunk.end == receivedChunk.start) { Timber.v("Reach end of $roomId") currentChunk.isLastBackward = true } else { Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}") - val userEntities = ArrayList(receivedChunk.events.size + receivedChunk.stateEvents.size) + val eventIds = ArrayList(receivedChunk.events.size) for (event in receivedChunk.events) { - currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked()) + event.eventId?.also { eventIds.add(it) } + currentChunk.add(roomId, event, direction, isUnlinked = currentChunk.isUnlinked()) UserEntityFactory.create(event)?.also { - userEntities.add(it) + realm.insertOrUpdate(it) } } // Then we merge chunks if needed @@ -181,10 +175,10 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy for (stateEvent in receivedChunk.stateEvents) { roomEntity.addStateEvent(stateEvent, isUnlinked = currentChunk.isUnlinked()) UserEntityFactory.create(stateEvent)?.also { - userEntities.add(it) + realm.insertOrUpdate(it) } } - realm.insertOrUpdate(userEntities) + currentChunk.updateSenderDataFor(eventIds) } } .map { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt index 4a14dce3..a50e7ca8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt @@ -22,15 +22,9 @@ 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.events.model.toModel import im.vector.matrix.android.api.session.room.model.Membership -import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent import im.vector.matrix.android.internal.crypto.CryptoManager -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.addOrUpdate -import im.vector.matrix.android.internal.database.helper.addStateEvent -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.helper.* 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.UserEntity @@ -123,7 +117,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch Timber.v("Handle join sync for room $roomId") val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) if (roomEntity.membership == Membership.INVITE) { roomEntity.chunks.deleteAllFromRealm() @@ -138,17 +132,15 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch // State event if (roomSync.state != null && roomSync.state.events.isNotEmpty()) { - val userEntities = ArrayList(roomSync.state.events.size) val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset roomSync.state.events.forEach { event -> roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex) // Give info to crypto module cryptoManager.onStateEvent(roomId, event) UserEntityFactory.create(event)?.also { - userEntities.add(it) + realm.insertOrUpdate(it) } } - realm.insertOrUpdate(userEntities) } if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) { @@ -181,7 +173,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch InvitedRoomSync): RoomEntity { Timber.v("Handle invited sync for room $roomId") val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) roomEntity.membership = Membership.INVITE if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) { val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events) @@ -195,7 +187,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch roomId: String, roomSync: RoomSync): RoomEntity { val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) roomEntity.membership = Membership.LEAVE roomEntity.chunks.deleteAllFromRealm() @@ -219,8 +211,9 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch lastChunk?.isLastForward = false chunkEntity.isLastForward = true - val userEntities = ArrayList(eventList.size) + val eventIds = ArrayList(eventList.size) for (event in eventList) { + event.eventId?.also { eventIds.add(it) } chunkEntity.add(roomEntity.roomId, event, PaginationDirection.FORWARDS, stateIndexOffset) // Give info to crypto module cryptoManager.onLiveEvent(roomEntity.roomId, event) @@ -235,10 +228,10 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch } } UserEntityFactory.create(event)?.also { - userEntities.add(it) + realm.insertOrUpdate(it) } } - realm.insertOrUpdate(userEntities) + chunkEntity.updateSenderDataFor(eventIds) return chunkEntity }