Realm-kotlin : continue migrating session db

This commit is contained in:
ganfra 2022-10-06 19:28:09 +02:00
parent 5d73118c8c
commit 6edea43ab4
30 changed files with 383 additions and 401 deletions

View File

@ -16,9 +16,8 @@
package org.matrix.android.sdk.internal.database.helper
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.createObject
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
@ -32,14 +31,13 @@ import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.model.cleanUp
import org.matrix.android.sdk.internal.database.query.find
import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.extensions.realm
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import timber.log.Timber
@ -63,6 +61,7 @@ internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity,
}
internal fun ChunkEntity.addTimelineEvent(
realm: MutableRealm,
roomId: String,
eventEntity: EventEntity,
direction: PaginationDirection,
@ -79,32 +78,33 @@ internal fun ChunkEntity.addTimelineEvent(
// Update RR for the sender of a new message with a dummy one
val readReceiptsSummaryEntity = if (!ownedByThreadChunk) handleReadReceipts(realm, roomId, eventEntity, senderId) else null
val timelineEventEntity = realm.createObject<TimelineEventEntity>().apply {
this.localId = localId
this.root = eventEntity
this.eventId = eventId
this.roomId = roomId
this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst()
?.also { it.cleanUp(eventEntity.sender) }
this.readReceipts = readReceiptsSummaryEntity
this.displayIndex = displayIndex
this.ownedByThreadChunk = ownedByThreadChunk
val roomMemberContent = roomMemberContentsByUser?.get(senderId)
this.senderAvatar = roomMemberContent?.avatarUrl
this.senderName = roomMemberContent?.displayName
isUniqueDisplayName = if (roomMemberContent?.displayName != null) {
computeIsUnique(realm, roomId, isLastForward, roomMemberContent, roomMemberContentsByUser)
} else {
true
}
}
// numberOfTimelineEvents++
val timelineEventEntity = realm.copyToRealm(
TimelineEventEntity().apply {
this.localId = localId
this.root = eventEntity
this.eventId = eventId
this.roomId = roomId
this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).first().find()
?.also { realm.cleanUp(it, eventEntity.sender) }
this.readReceipts = readReceiptsSummaryEntity
this.displayIndex = displayIndex
this.ownedByThreadChunk = ownedByThreadChunk
val roomMemberContent = roomMemberContentsByUser?.get(senderId)
this.senderAvatar = roomMemberContent?.avatarUrl
this.senderName = roomMemberContent?.displayName
isUniqueDisplayName = if (roomMemberContent?.displayName != null) {
computeIsUnique(realm, roomId, isLastForward, roomMemberContent, roomMemberContentsByUser)
} else {
true
}
}
)
timelineEvents.add(timelineEventEntity)
return timelineEventEntity
}
internal fun computeIsUnique(
realm: Realm,
realm: TypedRealm,
roomId: String,
isLastForward: Boolean,
senderRoomMemberContent: RoomMemberContent,
@ -116,8 +116,8 @@ internal fun computeIsUnique(
return if (isLastForward) {
val isLiveUnique = RoomMemberSummaryEntity
.where(realm, roomId)
.equalTo(RoomMemberSummaryEntityFields.DISPLAY_NAME, senderRoomMemberContent.displayName)
.findAll()
.query("displayName == $0", senderRoomMemberContent.displayName)
.find()
.none {
!roomMemberContentsByUser.containsKey(it.userId)
}
@ -127,18 +127,19 @@ internal fun computeIsUnique(
}
}
private fun handleReadReceipts(realm: Realm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity {
val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).findFirst()
?: realm.createObject<ReadReceiptsSummaryEntity>(eventEntity.eventId).apply {
private fun handleReadReceipts(realm: MutableRealm, roomId: String, eventEntity: EventEntity, senderId: String): ReadReceiptsSummaryEntity {
val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(realm, eventEntity.eventId).find()
?: realm.copyToRealm(ReadReceiptsSummaryEntity().apply {
this.eventId = eventEntity.eventId
this.roomId = roomId
}
})
val originServerTs = eventEntity.originServerTs
if (originServerTs != null) {
val timestampOfEvent = originServerTs.toDouble()
val readReceiptOfSender = ReadReceiptEntity.getOrCreate(realm, roomId = roomId, userId = senderId)
// If the synced RR is older, update
if (timestampOfEvent > readReceiptOfSender.originServerTs) {
val previousReceiptsSummary = ReadReceiptsSummaryEntity.where(realm, eventId = readReceiptOfSender.eventId).findFirst()
val previousReceiptsSummary = ReadReceiptsSummaryEntity.where(realm, eventId = readReceiptOfSender.eventId).find()
readReceiptOfSender.eventId = eventEntity.eventId
readReceiptOfSender.originServerTs = timestampOfEvent
previousReceiptsSummary?.readReceipts?.remove(readReceiptOfSender)

View File

@ -20,6 +20,8 @@ import com.squareup.moshi.JsonDataException
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.Sort
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import org.matrix.android.sdk.api.session.events.model.UnsignedData
import org.matrix.android.sdk.api.session.events.model.isRedacted
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
@ -48,13 +50,13 @@ private typealias Summary = Pair<Int, TimelineEventEntity>?
*/
internal fun Map<String, EventEntity>.updateThreadSummaryIfNeeded(
roomId: String,
realm: Realm,
realm: MutableRealm,
currentUserId: String,
chunkEntity: ChunkEntity? = null,
shouldUpdateNotifications: Boolean = true
) {
for ((rootThreadEventId, eventEntity) in this) {
eventEntity.threadSummaryInThread(eventEntity.realm, rootThreadEventId, chunkEntity)?.let { threadSummary ->
eventEntity.threadSummaryInThread(realm, rootThreadEventId, chunkEntity)?.let { threadSummary ->
val inThreadMessages = threadSummary.first
val latestEventInThread = threadSummary.second
@ -105,7 +107,7 @@ internal fun EventEntity.markEventAsRoot(
* @param chunkEntity the chunk entity
* @return A ThreadSummary containing the counted threads and the latest event message
*/
internal fun EventEntity.threadSummaryInThread(realm: Realm, rootThreadEventId: String, chunkEntity: ChunkEntity?): Summary {
internal fun EventEntity.threadSummaryInThread(realm: TypedRealm, rootThreadEventId: String, chunkEntity: ChunkEntity?): Summary {
val inThreadMessages = countInThreadMessages(
realm = realm,
roomId = roomId,
@ -141,12 +143,12 @@ internal fun EventEntity.threadSummaryInThread(realm: Realm, rootThreadEventId:
* Counts the number of thread replies in the main timeline thread summary,
* with respect to redactions.
*/
internal fun countInThreadMessages(realm: Realm, roomId: String, rootThreadEventId: String): Int =
internal fun countInThreadMessages(realm: TypedRealm, roomId: String, rootThreadEventId: String): Int =
TimelineEventEntity
.whereRoomId(realm, roomId = roomId)
.equalTo(TimelineEventEntityFields.ROOT.ROOT_THREAD_EVENT_ID, rootThreadEventId)
.distinct(TimelineEventEntityFields.ROOT.EVENT_ID)
.findAll()
.query("root.rootThreadEventId == $0", rootThreadEventId)
.distinct("root.eventId")
.find()
.filterNot { timelineEvent ->
timelineEvent.root
?.unsignedData

View File

@ -16,10 +16,10 @@
package org.matrix.android.sdk.internal.database.helper
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.Sort
import io.realm.kotlin.createObject
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.Sort
import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
@ -38,27 +38,28 @@ import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.cleanUp
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntityFields
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.extensions.realm
import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
import org.matrix.android.sdk.internal.session.room.timeline.TimelineEventDecryptor
import timber.log.Timber
import java.util.UUID
internal fun ThreadSummaryEntity.updateThreadSummary(
realm: TypedRealm,
rootThreadEventEntity: EventEntity,
numberOfThreads: Int?,
latestThreadEventEntity: EventEntity?,
isUserParticipating: Boolean,
roomMemberContentsByUser: HashMap<String, RoomMemberContent?>
) {
updateThreadSummaryRootEvent(rootThreadEventEntity, roomMemberContentsByUser)
updateThreadSummaryLatestEvent(latestThreadEventEntity, roomMemberContentsByUser)
updateThreadSummaryRootEvent(realm, rootThreadEventEntity, roomMemberContentsByUser)
updateThreadSummaryLatestEvent(realm, latestThreadEventEntity, roomMemberContentsByUser)
this.isUserParticipating = isUserParticipating
numberOfThreads?.let {
// Update number of threads only when there is an actual value
@ -70,6 +71,7 @@ internal fun ThreadSummaryEntity.updateThreadSummary(
* Updates the root thread event properties.
*/
internal fun ThreadSummaryEntity.updateThreadSummaryRootEvent(
realm: TypedRealm,
rootThreadEventEntity: EventEntity,
roomMemberContentsByUser: HashMap<String, RoomMemberContent?>
) {
@ -89,6 +91,7 @@ internal fun ThreadSummaryEntity.updateThreadSummaryRootEvent(
* Updates the latest thread event properties.
*/
internal fun ThreadSummaryEntity.updateThreadSummaryLatestEvent(
realm: TypedRealm,
latestThreadEventEntity: EventEntity?,
roomMemberContentsByUser: HashMap<String, RoomMemberContent?>
) {
@ -104,19 +107,19 @@ internal fun ThreadSummaryEntity.updateThreadSummaryLatestEvent(
}
}
private fun EventEntity.toTimelineEventEntity(roomMemberContentsByUser: HashMap<String, RoomMemberContent?>): TimelineEventEntity {
private fun EventEntity.toTimelineEventEntity(realm: MutableRealm, roomMemberContentsByUser: HashMap<String, RoomMemberContent?>): TimelineEventEntity {
val roomId = roomId
val eventId = eventId
val localId = TimelineEventEntity.nextId(realm)
val senderId = sender ?: ""
val timelineEventEntity = realm.createObject<TimelineEventEntity>().apply {
val timelineEventEntity = TimelineEventEntity().apply {
this.localId = localId
this.root = this@toTimelineEventEntity
this.eventId = eventId
this.roomId = roomId
this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst()
?.also { it.cleanUp(sender) }
this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).first().find()
?.also { realm.cleanUp(it, sender) }
this.ownedByThreadChunk = true // To skip it from the original event flow
val roomMemberContent = roomMemberContentsByUser[senderId]
this.senderAvatar = roomMemberContent?.avatarUrl
@ -132,7 +135,7 @@ private fun EventEntity.toTimelineEventEntity(roomMemberContentsByUser: HashMap<
internal fun ThreadSummaryEntity.Companion.createOrUpdate(
threadSummaryType: ThreadSummaryUpdateType,
realm: Realm,
realm: MutableRealm,
roomId: String,
threadEventEntity: EventEntity? = null,
rootThreadEvent: Event? = null,
@ -173,6 +176,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate(
val isUserParticipating = rootThreadEvent.unsignedData.relations.latestThread.isUserParticipating == true || rootThreadEvent.senderId == userId
roomMemberContentsByUser.addSenderState(realm, roomId, rootThreadEvent.senderId)
threadSummary.updateThreadSummary(
realm = realm,
rootThreadEventEntity = rootThreadEventEntity,
numberOfThreads = numberOfThreads,
latestThreadEventEntity = latestThreadEventEntity,
@ -190,7 +194,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate(
if (threadSummary != null) {
// ThreadSummary exists so lets add the latest event
Timber.i("###THREADS ThreadSummaryHelper ADD root eventId:$rootThreadEventId exists, lets update latest thread event.")
threadSummary.updateThreadSummaryLatestEvent(threadEventEntity, roomMemberContentsByUser)
threadSummary.updateThreadSummaryLatestEvent(realm, threadEventEntity, roomMemberContentsByUser)
threadSummary.numberOfThreads++
if (threadEventEntity.sender == userId) {
threadSummary.isUserParticipating = true
@ -202,6 +206,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate(
// Root thread event entity exists so lets create a new record
ThreadSummaryEntity.getOrCreate(realm, roomId, rootThreadEventEntity.eventId).let {
it.updateThreadSummary(
realm = realm,
rootThreadEventEntity = rootThreadEventEntity,
numberOfThreads = 1,
latestThreadEventEntity = threadEventEntity,
@ -259,7 +264,7 @@ private fun requestDecryption(eventDecryptor: TimelineEventDecryptor?, event: Ev
/**
* If we don't have any new state on this user, get it from db.
*/
private fun HashMap<String, RoomMemberContent?>.addSenderState(realm: Realm, roomId: String, senderId: String) {
private fun HashMap<String, RoomMemberContent?>.addSenderState(realm: TypedRealm, roomId: String, senderId: String) {
getOrPut(senderId) {
CurrentStateEventEntity
.getOrNull(realm, roomId, senderId, EventType.STATE_ROOM_MEMBER)
@ -271,7 +276,7 @@ private fun HashMap<String, RoomMemberContent?>.addSenderState(realm: Realm, roo
/**
* Create an EventEntity for the root thread event or get an existing one.
*/
private fun createEventEntity(realm: Realm, roomId: String, event: Event, currentTimeMillis: Long): EventEntity {
private fun createEventEntity(realm: MutableRealm, roomId: String, event: Event, currentTimeMillis: Long): EventEntity {
val ageLocalTs = currentTimeMillis - (event.unsignedData?.age ?: 0)
return event.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION)
}
@ -281,7 +286,7 @@ private fun createEventEntity(realm: Realm, roomId: String, event: Event, curren
* state
*/
private fun createLatestEventEntity(
realm: Realm,
realm: MutableRealm,
roomId: String,
rootThreadEvent: Event,
roomMemberContentsByUser: HashMap<String, RoomMemberContent?>,
@ -308,7 +313,7 @@ private fun getLatestEvent(rootThreadEvent: Event): Event? {
* @param realm the realm instance
* @param roomId The id of the room
*/
internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: Realm, roomId: String): RealmQuery<ThreadSummaryEntity> =
internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: TypedRealm, roomId: String): RealmQuery<ThreadSummaryEntity> =
ThreadSummaryEntity
.where(realm, roomId = roomId)
.sort(ThreadSummaryEntityFields.LATEST_THREAD_EVENT_ENTITY.ORIGIN_SERVER_TS, Sort.DESCENDING)
@ -316,24 +321,25 @@ internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: Realm,
/**
* Enhance each [ThreadSummary] root and latest event with the equivalent decrypted text edition/replacement.
*/
internal fun List<ThreadSummary>.enhanceWithEditions(realm: Realm, roomId: String): List<ThreadSummary> =
internal fun List<ThreadSummary>.enhanceWithEditions(realm: TypedRealm, roomId: String): List<ThreadSummary> =
this.map {
it.addEditionIfNeeded(realm, roomId, true)
it.addEditionIfNeeded(realm, roomId, false)
it
}
private fun ThreadSummary.addEditionIfNeeded(realm: Realm, roomId: String, enhanceRoot: Boolean) {
private fun ThreadSummary.addEditionIfNeeded(realm: TypedRealm, roomId: String, enhanceRoot: Boolean) {
val eventId = if (enhanceRoot) rootEventId else latestEvent?.eventId ?: return
EventAnnotationsSummaryEntity
.where(realm, roomId, eventId)
.findFirst()
.first()
.find()
?.editSummary
?.editions
?.lastOrNull()
?.eventId
?.let { editedEventId ->
TimelineEventEntity.where(realm, roomId, eventId = editedEventId).findFirst()?.let { editedEvent ->
TimelineEventEntity.where(realm, roomId, eventId = editedEventId).first().find()?.let { editedEvent ->
if (enhanceRoot) {
threadEditions.rootThreadEdition = editedEvent.root?.asDomain()?.getDecryptedTextSummary() ?: "(edited)"
} else {

View File

@ -16,22 +16,22 @@
package org.matrix.android.sdk.internal.database.mapper
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.internal.database.RealmObjectMapper
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import javax.inject.Inject
internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() :
Monarchy.Mapper<LiveLocationShareAggregatedSummary, LiveLocationShareAggregatedSummaryEntity> {
RealmObjectMapper<LiveLocationShareAggregatedSummaryEntity, LiveLocationShareAggregatedSummary> {
override fun map(entity: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
override fun map(realmObject: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
return LiveLocationShareAggregatedSummary(
userId = entity.userId,
isActive = entity.isActive,
endOfLiveTimestampMillis = entity.endOfLiveTimestampMillis,
lastLocationDataContent = ContentMapper.map(entity.lastLocationContent).toModel<MessageBeaconLocationDataContent>()
userId = realmObject.userId,
isActive = realmObject.isActive,
endOfLiveTimestampMillis = realmObject.endOfLiveTimestampMillis,
lastLocationDataContent = ContentMapper.map(realmObject.lastLocationContent).toModel<MessageBeaconLocationDataContent>()
)
}
}

View File

@ -16,41 +16,30 @@
package org.matrix.android.sdk.internal.database.mapper
import io.realm.Realm
import io.realm.RealmList
import io.realm.kotlin.isManaged
import io.realm.kotlin.TypedRealm
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
import org.matrix.android.sdk.internal.database.RealmSessionProvider
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.extensions.realm
import org.matrix.android.sdk.internal.di.SessionDatabase
import javax.inject.Inject
internal class ReadReceiptsSummaryMapper @Inject constructor(
private val realmSessionProvider: RealmSessionProvider
@SessionDatabase private val realmInstance: RealmInstance,
) {
fun map(readReceiptsSummaryEntity: ReadReceiptsSummaryEntity?): List<ReadReceipt> {
if (readReceiptsSummaryEntity == null) {
return emptyList()
}
val readReceipts = readReceiptsSummaryEntity.readReceipts
// Avoid opening a new realm if we already have one opened
return if (readReceiptsSummaryEntity.isManaged()) {
map(readReceipts, readReceiptsSummaryEntity.realm)
} else {
realmSessionProvider.withRealm { realm ->
map(readReceipts, realm)
}
}
val readReceipts = readReceiptsSummaryEntity?.readReceipts.orEmpty()
val realm = realmInstance.getBlockingRealm()
return map(readReceipts, realm)
}
private fun map(readReceipts: RealmList<ReadReceiptEntity>, realm: Realm): List<ReadReceipt> {
private fun map(readReceipts: List<ReadReceiptEntity>, realm: TypedRealm): List<ReadReceipt> {
return readReceipts
.mapNotNull {
val roomMember = RoomMemberSummaryEntity.where(realm, roomId = it.roomId, userId = it.userId).findFirst()
val roomMember = RoomMemberSummaryEntity.where(realm, roomId = it.roomId, userId = it.userId).first().find()
?: return@mapNotNull null
ReadReceipt(roomMember.asDomain(), it.originServerTs.toLong())
}

View File

@ -15,11 +15,13 @@
*/
package org.matrix.android.sdk.internal.database.model
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.ext.realmListOf
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import timber.log.Timber
internal class EventAnnotationsSummaryEntity : RealmObject {
@PrimaryKey
@ -52,6 +54,18 @@ internal class EventAnnotationsSummaryEntity : RealmObject {
companion object
}
internal fun MutableRealm.cleanUp(entity: EventAnnotationsSummaryEntity, originalEventSenderId: String?) {
originalEventSenderId ?: return
entity.editSummary?.editions?.filter {
it.senderId != originalEventSenderId
}
?.forEach {
Timber.w("Deleting an edition from ${it.senderId} of event sent by $originalEventSenderId")
delete(it)
}
}
/*
internal fun EventAnnotationsSummaryEntity.deleteOnCascade() {
reactionsSummary.deleteAllFromRealm()

View File

@ -25,6 +25,6 @@ import io.realm.kotlin.types.RealmObject
*/
internal class UserDraftsEntity : RealmObject {
var userDrafts: RealmList<DraftEntity> = realmListOf()
var roomId: String = ""
companion object
}

View File

@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.database.query
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.types.RealmList
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.internal.database.andIf
import org.matrix.android.sdk.internal.database.model.EventEntity
@ -91,9 +92,7 @@ internal fun EventEntity.Companion.whereTypes(
}
internal fun RealmList<EventEntity>.find(eventId: String): EventEntity? {
return this.where()
.equalTo(EventEntityFields.EVENT_ID, eventId)
.findFirst()
return return firstOrNull { it.eventId == eventId }
}
internal fun RealmList<EventEntity>.fastContains(eventId: String): Boolean {

View File

@ -16,79 +16,80 @@
package org.matrix.android.sdk.internal.database.query
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.kotlin.where
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
realm: Realm,
realm: TypedRealm,
eventId: String,
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
return realm.where<LiveLocationShareAggregatedSummaryEntity>()
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
return realm.query(LiveLocationShareAggregatedSummaryEntity::class)
.query("eventId == $0", eventId)
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.where(
realm: Realm,
realm: TypedRealm,
roomId: String,
eventId: String,
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
return LiveLocationShareAggregatedSummaryEntity
.whereRoomId(realm, roomId = roomId)
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, eventId)
.query("eventId == $0", eventId)
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.whereRoomId(
realm: Realm,
realm: TypedRealm,
roomId: String
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
return realm.where<LiveLocationShareAggregatedSummaryEntity>()
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, roomId)
return realm.query(LiveLocationShareAggregatedSummaryEntity::class)
.query("roomId == $0", roomId)
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.create(
realm: Realm,
realm: MutableRealm,
roomId: String,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity {
val obj = realm.createObject(LiveLocationShareAggregatedSummaryEntity::class.java, eventId).apply {
this.roomId = roomId
}
val entity = realm.copyToRealm(
LiveLocationShareAggregatedSummaryEntity().apply {
this.eventId = eventId
this.roomId = roomId
}
)
val annotationSummary = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId = roomId, eventId = eventId)
annotationSummary.liveLocationShareAggregatedSummary = obj
return obj
annotationSummary.liveLocationShareAggregatedSummary = entity
return entity
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.getOrCreate(
realm: Realm,
realm: MutableRealm,
roomId: String,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity {
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).first().find()
?: LiveLocationShareAggregatedSummaryEntity.create(realm, roomId, eventId)
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.get(
realm: Realm,
realm: TypedRealm,
roomId: String,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity? {
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).findFirst()
return LiveLocationShareAggregatedSummaryEntity.where(realm, roomId, eventId).first().find()
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.get(
realm: Realm,
realm: TypedRealm,
eventId: String,
): LiveLocationShareAggregatedSummaryEntity? {
return LiveLocationShareAggregatedSummaryEntity.where(realm, eventId).findFirst()
return LiveLocationShareAggregatedSummaryEntity.where(realm, eventId).first().find()
}
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveInRoomForUser(
realm: Realm,
realm: TypedRealm,
roomId: String,
userId: String,
ignoredEventId: String,
@ -96,11 +97,11 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveIn
): List<LiveLocationShareAggregatedSummaryEntity> {
return LiveLocationShareAggregatedSummaryEntity
.whereRoomId(realm, roomId = roomId)
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, userId)
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
.notEqualTo(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, ignoredEventId)
.lessThan(LiveLocationShareAggregatedSummaryEntityFields.START_OF_LIVE_TIMESTAMP_MILLIS, startOfLiveTimestampThreshold)
.findAll()
.query("userId == $0", userId)
.query("isActive == true")
.query("eventId != $0", ignoredEventId)
.query("startOfLiveTimestampMillis < $0", startOfLiveTimestampThreshold)
.find()
.toList()
}
@ -108,12 +109,12 @@ internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findActiveLiveIn
* A live is considered as running when active and with at least a last known location.
*/
internal fun LiveLocationShareAggregatedSummaryEntity.Companion.findRunningLiveInRoom(
realm: Realm,
realm: TypedRealm,
roomId: String,
): RealmQuery<LiveLocationShareAggregatedSummaryEntity> {
return LiveLocationShareAggregatedSummaryEntity
.whereRoomId(realm, roomId = roomId)
.equalTo(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
.isNotEmpty(LiveLocationShareAggregatedSummaryEntityFields.USER_ID)
.isNotNull(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT)
.query("isActive == true")
.query("userId != ''")
.query("lastLocationContent != ''")
}

View File

@ -19,10 +19,7 @@ import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import org.matrix.android.sdk.api.session.pushrules.RuleKind
import org.matrix.android.sdk.internal.database.andIf
import org.matrix.android.sdk.internal.database.model.PushRuleEntity
import org.matrix.android.sdk.internal.database.model.PushRuleEntityFields
import org.matrix.android.sdk.internal.database.model.PushRulesEntity
import org.matrix.android.sdk.internal.database.model.PushRulesEntityFields
import org.matrix.android.sdk.internal.database.model.PusherEntity
internal fun PusherEntity.Companion.where(
@ -45,15 +42,3 @@ internal fun PushRulesEntity.Companion.where(
.query("kindStr == $0", kind.name)
}
/*
internal fun PushRuleEntity.Companion.where(
realm: TypedRealm,
scope: String,
ruleId: String
): RealmQuery<PushRuleEntity> {
return realm.query(PushRuleEntity::class)
.equalTo(PushRuleEntityFields.PARENT.SCOPE, scope)
.equalTo(PushRuleEntityFields.RULE_ID, ruleId)
}
*/

View File

@ -133,9 +133,7 @@ internal fun RealmQuery<TimelineEventEntity>.filterTypes(filterTypes: List<Strin
}
internal fun RealmList<TimelineEventEntity>.find(eventId: String): TimelineEventEntity? {
return where()
.equalTo(TimelineEventEntityFields.EVENT_ID, eventId)
.findFirst()
return firstOrNull { it.eventId == eventId }
}
internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(

View File

@ -16,16 +16,14 @@
package org.matrix.android.sdk.internal.database.query
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.kotlin.where
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import org.matrix.android.sdk.internal.database.andIf
import org.matrix.android.sdk.internal.database.model.UserDraftsEntity
import org.matrix.android.sdk.internal.database.model.UserDraftsEntityFields
internal fun UserDraftsEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<UserDraftsEntity> {
val query = realm.where<UserDraftsEntity>()
if (roomId != null) {
query.equalTo(UserDraftsEntityFields.ROOM_SUMMARY_ENTITY.ROOM_ID, roomId)
}
return query
internal fun UserDraftsEntity.Companion.where(realm: TypedRealm, roomId: String? = null): RealmQuery<UserDraftsEntity> {
return realm.query(UserDraftsEntity::class)
.andIf(roomId != null) {
query("roomId == $0", roomId!!)
}
}

View File

@ -16,8 +16,6 @@
package org.matrix.android.sdk.internal.session.room.create
import com.zhuinden.monarchy.Monarchy
import io.realm.RealmConfiguration
import kotlinx.coroutines.TimeoutCancellationException
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
@ -26,10 +24,9 @@ import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.awaitTransaction
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
@ -40,7 +37,6 @@ import org.matrix.android.sdk.internal.session.room.read.SetReadMarkersTask
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import org.matrix.android.sdk.internal.util.time.Clock
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -49,13 +45,11 @@ internal interface CreateRoomTask : Task<CreateRoomParams, String>
internal class DefaultCreateRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
@SessionDatabase private val monarchy: Monarchy,
@SessionDatabase private val realmInstance: RealmInstance,
private val aliasAvailabilityChecker: RoomAliasAvailabilityChecker,
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val readMarkersTask: SetReadMarkersTask,
@SessionDatabase
private val realmConfiguration: RealmConfiguration,
private val createRoomBodyBuilder: CreateRoomBodyBuilder,
private val globalErrorReceiver: GlobalErrorReceiver,
private val clock: Clock,
@ -93,17 +87,16 @@ internal class DefaultCreateRoomTask @Inject constructor(
val roomId = createRoomResponse.roomId
// Wait for room to come back from the sync (but it can maybe be in the DB if the sync response is received before)
try {
awaitNotEmptyResult(realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
realm.where(RoomSummaryEntity::class.java)
.equalTo(RoomSummaryEntityFields.ROOM_ID, roomId)
.equalTo(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.JOIN.name)
awaitNotEmptyResult(realmInstance, TimeUnit.MINUTES.toMillis(1L)) { realm ->
RoomSummaryEntity.where(realm, roomId)
.query("membershipStr == $0", Membership.JOIN.name)
}
} catch (exception: TimeoutCancellationException) {
throw CreateRoomFailure.CreatedWithTimeout(roomId)
}
awaitTransaction(realmConfiguration) {
RoomSummaryEntity.where(it, roomId).findFirst()?.lastActivityTime = clock.epochMillis()
realmInstance.write {
RoomSummaryEntity.where(this, roomId).first().find()?.lastActivityTime = clock.epochMillis()
}
handleDirectChatCreation(roomId, createRoomBody.getDirectUserId())
@ -113,8 +106,8 @@ internal class DefaultCreateRoomTask @Inject constructor(
private suspend fun handleDirectChatCreation(roomId: String, otherUserId: String?) {
otherUserId ?: return // This is not a direct room
monarchy.awaitTransaction { realm ->
RoomSummaryEntity.where(realm, roomId).findFirst()?.apply {
realmInstance.write {
RoomSummaryEntity.where(this, roomId).first().find()?.apply {
this.directUserId = otherUserId
this.isDirect = true
}

View File

@ -17,76 +17,75 @@
package org.matrix.android.sdk.internal.session.room.draft
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.kotlin.createObject
import androidx.lifecycle.asLiveData
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.session.room.send.UserDraft
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.RealmSessionProvider
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.clearWith
import org.matrix.android.sdk.internal.database.mapper.DraftMapper
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.UserDraftsEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.util.awaitTransaction
import org.matrix.android.sdk.internal.util.mapOptional
import timber.log.Timber
import javax.inject.Inject
internal class DraftRepository @Inject constructor(
@SessionDatabase private val monarchy: Monarchy,
private val realmSessionProvider: RealmSessionProvider
@SessionDatabase private val realmInstance: RealmInstance,
) {
suspend fun saveDraft(roomId: String, userDraft: UserDraft) {
monarchy.awaitTransaction {
saveDraftInDb(it, userDraft, roomId)
realmInstance.write {
saveDraftInDb(this, userDraft, roomId)
}
}
suspend fun deleteDraft(roomId: String) {
monarchy.awaitTransaction {
deleteDraftFromDb(it, roomId)
realmInstance.write {
deleteDraftFromDb(this, roomId)
}
}
fun getDraft(roomId: String): UserDraft? {
return realmSessionProvider.withRealm { realm ->
UserDraftsEntity.where(realm, roomId).findFirst()
?.userDrafts
?.firstOrNull()
?.let {
DraftMapper.map(it)
}
}
val realm = realmInstance.getBlockingRealm()
return UserDraftsEntity.where(realm, roomId).first()
.find()
?.let { mapUserDrafts(it) }
}
fun getDraftsLive(roomId: String): LiveData<Optional<UserDraft>> {
val liveData = monarchy.findAllMappedWithChanges(
{ UserDraftsEntity.where(it, roomId) },
{
it.userDrafts.map { draft ->
DraftMapper.map(draft)
}
}
)
return Transformations.map(liveData) {
it.firstOrNull()?.firstOrNull().toOptional()
return realmInstance.queryFirst {
UserDraftsEntity.where(it, roomId).first()
}
.mapOptional(::mapUserDrafts)
.asLiveData()
}
private fun mapUserDrafts(userDraftsEntity: UserDraftsEntity): UserDraft? {
return userDraftsEntity.userDrafts.firstOrNull()?.let { draft ->
DraftMapper.map(draft)
}
}
private fun deleteDraftFromDb(realm: Realm, roomId: String) {
UserDraftsEntity.where(realm, roomId).findFirst()?.userDrafts?.clear()
private fun deleteDraftFromDb(realm: MutableRealm, roomId: String) {
UserDraftsEntity.where(realm, roomId).first().find()?.userDrafts?.clearWith {
realm.delete(it)
}
}
private fun saveDraftInDb(realm: Realm, draft: UserDraft, roomId: String) {
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
?: realm.createObject(roomId)
private fun saveDraftInDb(realm: MutableRealm, draft: UserDraft, roomId: String) {
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).first().find()
?: realm.copyToRealm(
RoomSummaryEntity().apply {
this.roomId = roomId
}
)
val userDraftsEntity = roomSummaryEntity.userDrafts
?: realm.createObject<UserDraftsEntity>().also {
?: realm.copyToRealm(UserDraftsEntity()).also {
roomSummaryEntity.userDrafts = it
}

View File

@ -17,8 +17,7 @@
package org.matrix.android.sdk.internal.session.room.location
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy
import androidx.lifecycle.asLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -27,16 +26,17 @@ import org.matrix.android.sdk.api.session.room.location.UpdateLiveLocationShareR
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.LiveLocationShareAggregatedSummaryMapper
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.query.findRunningLiveInRoom
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.util.mapOptional
internal class DefaultLocationSharingService @AssistedInject constructor(
@Assisted private val roomId: String,
@SessionDatabase private val monarchy: Monarchy,
@SessionDatabase private val realmInstance: RealmInstance,
private val sendStaticLocationTask: SendStaticLocationTask,
private val sendLiveLocationTask: SendLiveLocationTask,
private val startLiveLocationShareTask: StartLiveLocationShareTask,
@ -113,20 +113,16 @@ internal class DefaultLocationSharingService @AssistedInject constructor(
}
override fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> {
return monarchy.findAllMappedWithChanges(
{ LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId) },
liveLocationShareAggregatedSummaryMapper
)
return realmInstance.queryList(liveLocationShareAggregatedSummaryMapper) {
LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId)
}.asLiveData()
}
override fun getLiveLocationShareSummary(beaconInfoEventId: String): LiveData<Optional<LiveLocationShareAggregatedSummary>> {
return Transformations.map(
monarchy.findAllMappedWithChanges(
{ LiveLocationShareAggregatedSummaryEntity.where(it, roomId = roomId, eventId = beaconInfoEventId) },
liveLocationShareAggregatedSummaryMapper
)
) {
it.firstOrNull().toOptional()
return realmInstance.queryFirst {
LiveLocationShareAggregatedSummaryEntity.where(it, roomId = roomId, eventId = beaconInfoEventId).first()
}
.mapOptional(liveLocationShareAggregatedSummaryMapper::map)
.asLiveData()
}
}

View File

@ -16,19 +16,17 @@
package org.matrix.android.sdk.internal.session.room.membership
import com.zhuinden.monarchy.Monarchy
import io.realm.kotlin.createObject
import kotlinx.coroutines.TimeoutCancellationException
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.crypto.CryptoSessionInfoProvider
import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.getOrCreate
@ -41,7 +39,6 @@ import org.matrix.android.sdk.internal.session.room.RoomDataSource
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryUpdater
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import org.matrix.android.sdk.internal.util.time.Clock
import timber.log.Timber
import java.util.concurrent.TimeUnit
@ -57,7 +54,7 @@ internal interface LoadRoomMembersTask : Task<LoadRoomMembersTask.Params, Unit>
internal class DefaultLoadRoomMembersTask @Inject constructor(
private val roomAPI: RoomAPI,
@SessionDatabase private val monarchy: Monarchy,
@SessionDatabase private val realmInstance: RealmInstance,
private val roomDataSource: RoomDataSource,
private val syncTokenStore: SyncTokenStore,
private val roomSummaryUpdater: RoomSummaryUpdater,
@ -78,10 +75,9 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
private suspend fun waitPreviousRequestToFinish(params: LoadRoomMembersTask.Params) {
try {
awaitNotEmptyResult(monarchy.realmConfiguration, TimeUnit.MINUTES.toMillis(1L)) { realm ->
realm.where(RoomEntity::class.java)
.equalTo(RoomEntityFields.ROOM_ID, params.roomId)
.equalTo(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, RoomMembersLoadStatusType.LOADED.name)
awaitNotEmptyResult(realmInstance, TimeUnit.MINUTES.toMillis(1L)) { realm ->
RoomEntity.where(realm, roomId = params.roomId)
.query("membersLoadStatusStr == $0", RoomMembersLoadStatusType.LOADED.name)
}
} catch (exception: TimeoutCancellationException) {
// Timeout, do the request anyway (?)
@ -109,7 +105,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
private suspend fun insertInDb(response: RoomMembersResponse, roomId: String) {
val chunks = response.roomMemberEvents.chunked(500)
chunks.forEach { roomMemberEvents ->
monarchy.awaitTransaction { realm ->
realmInstance.write {
Timber.v("Insert ${roomMemberEvents.size} member events in room $roomId")
// We ignore all the already known members
val now = clock.epochMillis()
@ -118,9 +114,9 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
continue
}
val ageLocalTs = now - (roomMemberEvent.unsignedData?.age ?: 0)
val eventEntity = roomMemberEvent.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(realm, EventInsertType.PAGINATION)
val eventEntity = roomMemberEvent.toEntity(roomId, SendState.SYNCED, ageLocalTs).copyToRealmOrIgnore(this, EventInsertType.PAGINATION)
CurrentStateEventEntity.getOrCreate(
realm,
this,
roomId,
roomMemberEvent.stateKey,
roomMemberEvent.type
@ -128,15 +124,14 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
eventId = roomMemberEvent.eventId
root = eventEntity
}
roomMemberEventHandler.handle(realm, roomId, roomMemberEvent, false)
roomMemberEventHandler.handle(this, roomId, roomMemberEvent, false)
}
}
}
monarchy.awaitTransaction { realm ->
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
?: realm.createObject(roomId)
realmInstance.write {
val roomEntity = RoomEntity.getOrCreate(this, roomId)
roomEntity.membersLoadStatus = RoomMembersLoadStatusType.LOADED
roomSummaryUpdater.update(realm, roomId, updateMembers = true)
roomSummaryUpdater.update(this, roomId, updateMembers = true)
}
if (cryptoSessionInfoProvider.isRoomEncrypted(roomId)) {
deviceListManager.onRoomMembersLoadedFor(roomId)
@ -144,8 +139,8 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(
}
private suspend fun setRoomMembersLoadStatus(roomId: String, status: RoomMembersLoadStatusType) {
monarchy.awaitTransaction { realm ->
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
realmInstance.write {
val roomEntity = RoomEntity.getOrCreate(this, roomId)
roomEntity.membersLoadStatus = status
}
}

View File

@ -17,22 +17,16 @@
package org.matrix.android.sdk.internal.session.room.notification
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import org.matrix.android.sdk.api.session.pushrules.RuleScope
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import org.matrix.android.sdk.api.session.room.notification.RoomPushRuleService
import org.matrix.android.sdk.internal.database.model.PushRuleEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
internal class DefaultRoomPushRuleService @AssistedInject constructor(
@Assisted private val roomId: String,
private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
@SessionDatabase private val monarchy: Monarchy
private val roomPushRuleDataSource: RoomPushRuleDataSource,
) :
RoomPushRuleService {
@ -42,26 +36,10 @@ internal class DefaultRoomPushRuleService @AssistedInject constructor(
}
override fun getLiveRoomNotificationState(): LiveData<RoomNotificationState> {
return Transformations.map(getPushRuleForRoom()) {
it?.toRoomNotificationState() ?: RoomNotificationState.ALL_MESSAGES
}
return roomPushRuleDataSource.getLiveRoomNotificationState(roomId)
}
override suspend fun setRoomNotificationState(roomNotificationState: RoomNotificationState) {
setRoomNotificationStateTask.execute(SetRoomNotificationStateTask.Params(roomId, roomNotificationState))
}
private fun getPushRuleForRoom(): LiveData<RoomPushRule?> {
val liveData = monarchy.findAllMappedWithChanges(
{ realm ->
PushRuleEntity.where(realm, scope = RuleScope.GLOBAL, ruleId = roomId)
},
{ result ->
result.toRoomPushRule()
}
)
return Transformations.map(liveData) { results ->
results.firstOrNull()
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.session.room.notification
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmSingleQuery
import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.session.pushrules.RuleScope
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.model.PushRulesEntity
import org.matrix.android.sdk.internal.di.SessionDatabase
import javax.inject.Inject
internal class RoomPushRuleDataSource @Inject constructor(@SessionDatabase private val realmInstance: RealmInstance) {
suspend fun getCurrentRoomPushRule(roomId: String): RoomPushRule? {
val realm = realmInstance.getRealm()
return queryPushRulesEntity(realm, roomId)
.find()
?.toRoomPushRule(ruleId = roomId)
}
fun getLiveRoomNotificationState(roomId: String): LiveData<RoomNotificationState> {
return realmInstance.queryFirst {
queryPushRulesEntity(it, roomId)
}.map {
val pushRulesEntity = it.getOrNull()
pushRulesEntity
?.toRoomPushRule(ruleId = roomId)
?.toRoomNotificationState()
?: RoomNotificationState.ALL_MESSAGES
}.asLiveData()
}
private fun queryPushRulesEntity(realm: TypedRealm, roomId: String): RealmSingleQuery<PushRulesEntity> {
return realm.query(PushRulesEntity::class)
.query("scope == $0", RuleScope.GLOBAL)
.query("ANY pushRules.ruleId == $0", roomId)
.first()
}
}

View File

@ -25,20 +25,20 @@ import org.matrix.android.sdk.api.session.pushrules.rest.PushRule
import org.matrix.android.sdk.api.session.pushrules.toJson
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper
import org.matrix.android.sdk.internal.database.model.PushRuleEntity
import org.matrix.android.sdk.internal.database.model.PushRulesEntity
internal fun PushRuleEntity.toRoomPushRule(): RoomPushRule? {
val kind = parent?.firstOrNull()?.kind
internal fun PushRulesEntity.toRoomPushRule(ruleId: String): RoomPushRule? {
val pushRuleEntity = pushRules.firstOrNull { it.ruleId == ruleId } ?: return null
val pushRule = when (kind) {
RuleSetKey.OVERRIDE -> {
PushRulesMapper.map(this)
PushRulesMapper.map(pushRuleEntity)
}
RuleSetKey.ROOM -> {
PushRulesMapper.mapRoomRule(this)
PushRulesMapper.mapRoomRule(pushRuleEntity)
}
else -> null
}
return if (pushRule == null || kind == null) {
return if (pushRule == null) {
null
} else {
RoomPushRule(kind, pushRule)

View File

@ -16,13 +16,7 @@
package org.matrix.android.sdk.internal.session.room.notification
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import org.matrix.android.sdk.api.session.pushrules.RuleScope
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import org.matrix.android.sdk.internal.database.model.PushRuleEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.pushers.AddPushRuleTask
import org.matrix.android.sdk.internal.session.pushers.RemovePushRuleTask
import org.matrix.android.sdk.internal.task.Task
@ -36,16 +30,14 @@ internal interface SetRoomNotificationStateTask : Task<SetRoomNotificationStateT
}
internal class DefaultSetRoomNotificationStateTask @Inject constructor(
@SessionDatabase private val monarchy: Monarchy,
private val roomPushRuleDataSource: RoomPushRuleDataSource,
private val removePushRuleTask: RemovePushRuleTask,
private val addPushRuleTask: AddPushRuleTask
) :
SetRoomNotificationStateTask {
override suspend fun execute(params: SetRoomNotificationStateTask.Params) {
val currentRoomPushRule = Realm.getInstance(monarchy.realmConfiguration).use {
PushRuleEntity.where(it, scope = RuleScope.GLOBAL, ruleId = params.roomId).findFirst()?.toRoomPushRule()
}
val currentRoomPushRule = roomPushRuleDataSource.getCurrentRoomPushRule(params.roomId)
if (currentRoomPushRule != null) {
removePushRuleTask.execute(RemovePushRuleTask.Params(currentRoomPushRule.kind, currentRoomPushRule.rule.ruleId))
}

View File

@ -17,15 +17,15 @@
package org.matrix.android.sdk.internal.session.room.read
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy
import androidx.lifecycle.asLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
import org.matrix.android.sdk.api.session.room.read.ReadService
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.toOptional
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.ReadReceiptsSummaryMapper
import org.matrix.android.sdk.internal.database.model.ReadMarkerEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
@ -34,10 +34,11 @@ import org.matrix.android.sdk.internal.database.query.isEventRead
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.util.mapOptional
internal class DefaultReadService @AssistedInject constructor(
@Assisted private val roomId: String,
@SessionDatabase private val monarchy: Monarchy,
@SessionDatabase private val realmInstance: RealmInstance,
private val setReadMarkersTask: SetReadMarkersTask,
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper,
@UserId private val userId: String
@ -68,47 +69,40 @@ internal class DefaultReadService @AssistedInject constructor(
}
override fun isEventRead(eventId: String): Boolean {
return isEventRead(monarchy.realmConfiguration, userId, roomId, eventId)
val realm = realmInstance.getBlockingRealm()
return isEventRead(realm, userId, roomId, eventId)
}
override fun getReadMarkerLive(): LiveData<Optional<String>> {
val liveRealmData = monarchy.findAllMappedWithChanges(
{ ReadMarkerEntity.where(it, roomId) },
{ it.eventId }
)
return Transformations.map(liveRealmData) {
it.firstOrNull().toOptional()
return realmInstance.queryFirst {
ReadMarkerEntity.where(it, roomId).first()
}
.mapOptional { it.eventId }
.asLiveData()
}
override fun getMyReadReceiptLive(): LiveData<Optional<String>> {
val liveRealmData = monarchy.findAllMappedWithChanges(
{ ReadReceiptEntity.where(it, roomId = roomId, userId = userId) },
{ it.eventId }
)
return Transformations.map(liveRealmData) {
it.firstOrNull().toOptional()
return realmInstance.queryFirst {
ReadReceiptEntity.where(it, roomId = roomId, userId = userId).first()
}
.mapOptional { it.eventId }
.asLiveData()
}
override fun getUserReadReceipt(userId: String): String? {
var eventId: String? = null
monarchy.doWithRealm {
eventId = ReadReceiptEntity.where(it, roomId = roomId, userId = userId)
.findFirst()
?.eventId
}
return eventId
val realm = realmInstance.getBlockingRealm()
return ReadReceiptEntity.where(realm, roomId = roomId, userId = userId)
.first()
.find()
?.eventId
}
override fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> {
val liveRealmData = monarchy.findAllMappedWithChanges(
{ ReadReceiptsSummaryEntity.where(it, eventId) },
{ readReceiptsSummaryMapper.map(it) }
)
return Transformations.map(liveRealmData) {
it.firstOrNull().orEmpty()
}
return realmInstance.queryFirst {
ReadReceiptsSummaryEntity.where(it, eventId)
}.map {
readReceiptsSummaryMapper.map(it.getOrNull())
}.asLiveData()
}
private fun ReadService.MarkAsReadParams.forceReadMarker(): Boolean {

View File

@ -15,10 +15,10 @@
*/
package org.matrix.android.sdk.internal.session.room.relation.threads
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummaryUpdateType
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.helper.createOrUpdate
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
@ -32,7 +32,6 @@ import org.matrix.android.sdk.internal.session.room.RoomAPI
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.session.room.timeline.PaginationResponse
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import org.matrix.android.sdk.internal.util.time.Clock
import timber.log.Timber
import javax.inject.Inject
@ -53,7 +52,7 @@ internal interface FetchThreadSummariesTask : Task<FetchThreadSummariesTask.Para
internal class DefaultFetchThreadSummariesTask @Inject constructor(
private val roomAPI: RoomAPI,
private val globalErrorReceiver: GlobalErrorReceiver,
@SessionDatabase private val monarchy: Monarchy,
@SessionDatabase private val realmInstance: RealmInstance,
private val cryptoService: DefaultCryptoService,
@UserId private val userId: String,
private val clock: Clock,
@ -82,8 +81,8 @@ internal class DefaultFetchThreadSummariesTask @Inject constructor(
params: FetchThreadSummariesTask.Params
): Result {
val rootThreadList = response.events
monarchy.awaitTransaction { realm ->
val roomEntity = RoomEntity.where(realm, roomId = params.roomId).findFirst() ?: return@awaitTransaction
realmInstance.write {
val roomEntity = RoomEntity.where(this, roomId = params.roomId).first().find() ?: return@write
val roomMemberContentsByUser = HashMap<String, RoomMemberContent?>()
for (rootThreadEvent in rootThreadList) {
@ -93,7 +92,7 @@ internal class DefaultFetchThreadSummariesTask @Inject constructor(
ThreadSummaryEntity.createOrUpdate(
threadSummaryType = ThreadSummaryUpdateType.REPLACE,
realm = realm,
realm = this,
roomId = params.roomId,
rootThreadEvent = rootThreadEvent,
roomMemberContentsByUser = roomMemberContentsByUser,

View File

@ -16,11 +16,8 @@
package org.matrix.android.sdk.internal.session.room.summary
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.createObject
import io.realm.kotlin.deleteFromRealm
import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.extensions.tryOrNull
@ -48,7 +45,6 @@ import org.matrix.android.sdk.internal.database.clearWith
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntity
@ -60,8 +56,6 @@ import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.database.query.isEventRead
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.clearWith
import org.matrix.android.sdk.internal.extensions.realm
import org.matrix.android.sdk.internal.query.process
import org.matrix.android.sdk.internal.session.room.RoomAvatarResolver
import org.matrix.android.sdk.internal.session.room.accountdata.RoomAccountDataDataSource
@ -372,17 +366,14 @@ internal class RoomSummaryUpdater @Inject constructor(
val parent = RoomSummaryEntity.where(realm, entry.key.roomId).first().find()
if (parent != null) {
val flattenParentsIds = (flattenSpaceParents[parent.roomId] ?: emptyList()) + listOf(parent.roomId)
entry.value.forEach { child ->
RoomSummaryEntity.where(realm, child.roomId).first().find()?.let { childSum ->
childSum.directParentNames.add(parent.displayName())
if (childSum.flattenParentIds == null) {
childSum.flattenParentIds = ""
parent.displayName()?.also { directParentName ->
childSum.directParentNames.add(directParentName)
}
flattenParentsIds.forEach {
if (childSum.flattenParentIds?.contains(it) != true) {
childSum.flattenParentIds += "|$it"
if (!childSum.flattenParentIds.contains(it)) {
childSum.flattenParentIds.add(it)
}
}
}
@ -400,7 +391,7 @@ internal class RoomSummaryUpdater @Inject constructor(
val relatedSpaces = lookupMap.keys
.filter { it.roomType == RoomType.SPACE }
.filter {
dmRoom.otherMemberIds.toList().intersect(it.otherMemberIds.toList()).isNotEmpty()
dmRoom.otherMemberIds.toSet().intersect(it.otherMemberIds.toSet()).isNotEmpty()
}
.map { it.roomId }
.distinct()
@ -412,7 +403,7 @@ internal class RoomSummaryUpdater @Inject constructor(
}.distinct()
if (flattenRelated.isNotEmpty()) {
// we keep real m.child/m.parent relations and add the one for common memberships
dmRoom.flattenParentIds += "|${flattenRelated.joinToString("|")}|"
dmRoom.flattenParentIds += flattenRelated
}
// Timber.v("## SPACES: flatten of ${dmRoom.otherMemberIds.joinToString(",")} is ${dmRoom.flattenParentIds}")
}
@ -429,7 +420,7 @@ internal class RoomSummaryUpdater @Inject constructor(
realm.query(RoomSummaryEntity::class)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, listOf(Membership.JOIN))
.query("roomType != $0", RoomType.SPACE)
.query("flattenParentIds CONTAINS $0", space.roomId)
.query("ANY flattenParentIds == $0", space.roomId)
.find().forEach {
highlightCount += it.highlightCount
notificationCount += it.notificationCount

View File

@ -17,30 +17,26 @@
package org.matrix.android.sdk.internal.session.room.threads
import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy
import androidx.lifecycle.asLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.realm.Realm
import org.matrix.android.sdk.api.session.room.threads.ThreadsService
import org.matrix.android.sdk.api.session.room.threads.model.ThreadSummary
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.helper.enhanceWithEditions
import org.matrix.android.sdk.internal.database.helper.findAllThreadsForRoomId
import org.matrix.android.sdk.internal.database.mapper.ThreadSummaryMapper
import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadSummariesTask
import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadTimelineTask
internal class DefaultThreadsService @AssistedInject constructor(
@Assisted private val roomId: String,
@UserId private val userId: String,
private val fetchThreadTimelineTask: FetchThreadTimelineTask,
private val fetchThreadSummariesTask: FetchThreadSummariesTask,
@SessionDatabase private val monarchy: Monarchy,
private val timelineEventMapper: TimelineEventMapper,
@SessionDatabase private val realmInstance: RealmInstance,
private val threadSummaryMapper: ThreadSummaryMapper
) : ThreadsService {
@ -50,25 +46,22 @@ internal class DefaultThreadsService @AssistedInject constructor(
}
override fun getAllThreadSummariesLive(): LiveData<List<ThreadSummary>> {
return monarchy.findAllMappedWithChanges(
{ ThreadSummaryEntity.findAllThreadsForRoomId(it, roomId = roomId) },
{
threadSummaryMapper.map(roomId, it)
}
)
return realmInstance.queryList({ threadSummaryMapper.map(roomId, it) }) {
ThreadSummaryEntity.findAllThreadsForRoomId(it, roomId = roomId)
}.asLiveData()
}
override fun getAllThreadSummaries(): List<ThreadSummary> {
return monarchy.fetchAllMappedSync(
{ ThreadSummaryEntity.findAllThreadsForRoomId(it, roomId = roomId) },
{ threadSummaryMapper.map(roomId, it) }
)
val realm = realmInstance.getBlockingRealm()
return ThreadSummaryEntity.findAllThreadsForRoomId(realm, roomId = roomId).find()
.map {
threadSummaryMapper.map(roomId, it)
}
}
override fun enhanceThreadWithEditions(threads: List<ThreadSummary>): List<ThreadSummary> {
return Realm.getInstance(monarchy.realmConfiguration).use {
threads.enhanceWithEditions(it, roomId)
}
val realm = realmInstance.getBlockingRealm()
return threads.enhanceWithEditions(realm, roomId)
}
override suspend fun fetchThreadTimeline(rootThreadEventId: String, from: String, limit: Int) {

View File

@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.session.sync.handler.room
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.internal.database.model.ReadMarkerEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.query.getOrCreate
@ -26,7 +26,7 @@ import javax.inject.Inject
internal class RoomFullyReadHandler @Inject constructor() {
fun handle(realm: Realm, roomId: String, content: FullyReadContent?) {
fun handle(realm: MutableRealm, roomId: String, content: FullyReadContent?) {
if (content == null) {
return
}

View File

@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.sync.handler.room
import dagger.Lazy
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.createObject
import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
@ -40,6 +39,7 @@ import org.matrix.android.sdk.api.session.sync.model.RoomSync
import org.matrix.android.sdk.api.session.sync.model.RoomsSyncResponse
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.database.clearWith
import org.matrix.android.sdk.internal.database.helper.addIfNecessary
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
import org.matrix.android.sdk.internal.database.helper.createOrUpdate
@ -65,7 +65,6 @@ import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.clearWith
import org.matrix.android.sdk.internal.session.StreamEventsManager
import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent
import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
@ -233,7 +232,7 @@ internal class RoomSyncHandler @Inject constructor(
val roomEntity = RoomEntity.getOrCreate(realm, roomId)
if (roomEntity.membership == Membership.INVITE) {
roomEntity.chunks.deleteAllFromRealm()
realm.delete(roomEntity.chunks)
}
roomEntity.membership = Membership.JOIN
@ -359,10 +358,10 @@ internal class RoomSyncHandler @Inject constructor(
}
}
}
val leftMember = RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()
val leftMember = RoomMemberSummaryEntity.where(realm, roomId, userId).first().find()
val membership = leftMember?.membership ?: Membership.LEAVE
roomEntity.membership = membership
roomEntity.chunks.clearWith { it.deleteOnCascade(deleteStateEvents = true, canDeleteRoot = true) }
roomEntity.chunks.clearWith { realm.deleteOnCascade(it, deleteStateEvents = true, canDeleteRoot = true) }
roomTypingUsersHandler.handle(realm, roomId, null)
roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.LEAVE)
roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary, roomSync.unreadNotifications)
@ -386,12 +385,14 @@ internal class RoomSyncHandler @Inject constructor(
} else {
// Delete all chunks of the room in case of gap.
ChunkEntity.findAll(realm, roomId).forEach {
it.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = true)
}
realm.createObject<ChunkEntity>().apply {
this.prevToken = prevToken
this.isLastForward = true
realm.deleteOnCascade(it, deleteStateEvents = false, canDeleteRoot = true)
}
realm.copyToRealm(
ChunkEntity().apply {
this.prevToken = prevToken
this.isLastForward = true
}
)
}
val eventIds = ArrayList<String>(eventList.size)
val roomMemberContentsByUser = HashMap<String, RoomMemberContent?>()
@ -444,6 +445,7 @@ internal class RoomSyncHandler @Inject constructor(
}
val timelineEventAdded = chunkEntity.addTimelineEvent(
realm = realm,
roomId = roomId,
eventEntity = eventEntity,
direction = PaginationDirection.FORWARDS,
@ -491,14 +493,14 @@ internal class RoomSyncHandler @Inject constructor(
}
}
// Finally delete the local echo
sendingEventEntity.deleteOnCascade(true)
realm.deleteOnCascade(sendingEventEntity, true)
} else {
Timber.v("Can't find corresponding local echo for tx:$it")
}
}
}
// Handle deletion of [stuck] local echos if needed
deleteLocalEchosIfNeeded(insertType, roomEntity, eventList)
deleteLocalEchosIfNeeded(realm, insertType, roomEntity, eventList)
if (lightweightSettingsStorage.areThreadMessagesEnabled()) {
optimizedThreadSummaryMap.updateThreadSummaryIfNeeded(
roomId = roomId,
@ -625,7 +627,7 @@ internal class RoomSyncHandler @Inject constructor(
* While we cannot know when a specific event arrived from the pagination (no transactionId included), after each room /sync
* we clear all SENT events, and we are sure that we will receive it from /sync or pagination
*/
private fun deleteLocalEchosIfNeeded(insertType: EventInsertType, roomEntity: RoomEntity, eventList: List<Event>) {
private fun deleteLocalEchosIfNeeded(realm: MutableRealm, insertType: EventInsertType, roomEntity: RoomEntity, eventList: List<Event>) {
// Skip deletion if we are on initial sync
if (insertType == EventInsertType.INITIAL_SYNC) return
// Skip deletion if there are no timeline events or there is no event received from the current user
@ -634,7 +636,7 @@ internal class RoomSyncHandler @Inject constructor(
timelineEvent.root?.sendState == SendState.SENT
}.forEach {
roomEntity.sendingTimelineEvents.remove(it)
it.deleteOnCascade(true)
realm.deleteOnCascade(it, true)
}
}
}

View File

@ -16,21 +16,19 @@
package org.matrix.android.sdk.internal.session.sync.handler.room
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.api.session.room.model.tag.RoomTagContent
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomTagEntity
import org.matrix.android.sdk.internal.database.query.getOrCreate
import javax.inject.Inject
internal class RoomTagHandler @Inject constructor() {
fun handle(realm: Realm, roomId: String, content: RoomTagContent?) {
fun handle(realm: MutableRealm, roomId: String, content: RoomTagContent?) {
if (content == null) {
return
}
val tags = content.tags.entries.map { (tagName, params) ->
RoomTagEntity(tagName, params["order"] as? Double)
Pair(tagName, params["order"] as? Double)
}
RoomSummaryEntity.getOrCreate(realm, roomId).updateTags(tags)

View File

@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.session.sync.handler.room
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
@ -29,7 +29,7 @@ internal class RoomTypingUsersHandler @Inject constructor(
) {
// TODO This could be handled outside of the Realm transaction. Use the new aggregator?
fun handle(realm: Realm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) {
fun handle(realm: MutableRealm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) {
val roomMemberHelper = RoomMemberHelper(realm, roomId)
val typingIds = ephemeralResult?.typingUserIds?.filter { it != userId }.orEmpty()
val senderInfo = typingIds.map { userId ->

View File

@ -16,8 +16,8 @@
package org.matrix.android.sdk.internal.session.sync.handler.room
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.where
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
import org.matrix.android.sdk.api.session.events.model.Content
@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.mapper.EventMapper
import org.matrix.android.sdk.internal.database.mapper.asDomain
@ -63,7 +64,7 @@ import javax.inject.Inject
*/
internal class ThreadsAwarenessHandler @Inject constructor(
private val permalinkFactory: PermalinkFactory,
@SessionDatabase private val monarchy: Monarchy,
@SessionDatabase private val realmInstance: RealmInstance,
private val lightweightSettingsStorage: LightweightSettingsStorage,
private val getEventTask: GetEventTask,
private val clock: Clock,
@ -98,21 +99,20 @@ internal class ThreadsAwarenessHandler @Inject constructor(
* @param eventList a list with the events to examine
*/
suspend fun fetchRootThreadEventsIfNeeded(eventList: List<Event>) {
if (eventList.isNullOrEmpty()) return
if (eventList.isEmpty()) return
val threadsToFetch = emptyMap<String, String>().toMutableMap()
Realm.getInstance(monarchy.realmConfiguration).use { realm ->
eventList.asSequence()
.filter {
isThreadEvent(it) && it.roomId != null
}.mapNotNull { event ->
getRootThreadEventId(event)?.let {
Pair(it, event.roomId!!)
}
}.forEach { (rootThreadEventId, roomId) ->
EventEntity.where(realm, rootThreadEventId).findFirst() ?: run { threadsToFetch[rootThreadEventId] = roomId }
val realm = realmInstance.getRealm()
eventList.asSequence()
.filter {
isThreadEvent(it) && it.roomId != null
}.mapNotNull { event ->
getRootThreadEventId(event)?.let {
Pair(it, event.roomId!!)
}
}
}.forEach { (rootThreadEventId, roomId) ->
EventEntity.where(realm, rootThreadEventId).first().find() ?: run { threadsToFetch[rootThreadEventId] = roomId }
}
fetchThreadsEvents(threadsToFetch)
}
@ -126,12 +126,12 @@ internal class ThreadsAwarenessHandler @Inject constructor(
}
}
if (eventEntityList.isNullOrEmpty()) return
if (eventEntityList.isEmpty()) return
// Transaction should be done on its own thread, like below
monarchy.awaitTransaction { realm ->
realmInstance.write {
eventEntityList.forEach {
it.copyToRealmOrIgnore(realm, EventInsertType.INCREMENTAL_SYNC)
it.copyToRealmOrIgnore(this, EventInsertType.INCREMENTAL_SYNC)
}
}
}
@ -159,7 +159,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
* @return The content to inject in the roomSyncHandler live events
*/
fun makeEventThreadAware(
realm: Realm,
realm: MutableRealm,
roomId: String?,
event: Event?,
eventEntity: EventEntity? = null
@ -217,7 +217,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
* @return The content to inject in the roomSyncHandler live events
*/
private fun handleRootThreadEventsIfNeeded(
realm: Realm,
realm: MutableRealm,
roomId: String,
eventEntity: EventEntity?,
event: Event
@ -244,7 +244,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
* @return The content to inject in the roomSyncHandler live events
*/
private fun handleEventsThatRelatesTo(
realm: Realm,
realm: MutableRealm,
roomId: String,
event: Event,
eventBody: String,
@ -364,7 +364,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
return updateEventEntity(event, eventEntity, eventPayload, messageTextContent)
}
private fun eventThatRelatesTo(realm: Realm, currentEventId: String, rootThreadEventId: String): List<EventEntity>? {
private fun eventThatRelatesTo(realm: TypedRealm, currentEventId: String, rootThreadEventId: String): List<EventEntity>? {
val threadList = realm.where<EventEntity>()
.beginGroup()
.equalTo(EventEntityFields.ROOT_THREAD_EVENT_ID, rootThreadEventId)
@ -383,8 +383,8 @@ internal class ThreadsAwarenessHandler @Inject constructor(
* Try to get the event form the local DB, if the event does not exist null
* will be returned.
*/
private fun getEventFromDB(realm: Realm, eventId: String): Event? {
val eventEntity = EventEntity.where(realm, eventId = eventId).findFirst() ?: return null
private fun getEventFromDB(realm: TypedRealm, eventId: String): Event? {
val eventEntity = EventEntity.where(realm, eventId = eventId).first().find() ?: return null
return EventMapper.map(eventEntity)
}

View File

@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.session.sync.parsing
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
import org.matrix.android.sdk.api.session.room.model.tag.RoomTagContent
@ -37,7 +38,7 @@ internal class RoomSyncAccountDataHandler @Inject constructor(
private val roomFullyReadHandler: RoomFullyReadHandler
) {
fun handle(realm: Realm, roomId: String, accountData: RoomSyncAccountData) {
fun handle(realm: MutableRealm, roomId: String, accountData: RoomSyncAccountData) {
if (accountData.events.isNullOrEmpty()) {
return
}