diff --git a/CHANGES.md b/CHANGES.md index 8b9a298d38..e08c36d406 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -56,6 +56,7 @@ Bugfix 🐛: - Widgets: Support $matrix_widget_id parameter (#2748) - Data for Worker overload (#2721) - Fix multiple tasks + - Object deletion in database is not complete (#2759) SDK API changes ⚠️: - Increase targetSdkVersion to 30 (#2600) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/Extensions.kt index e494cb5b31..cf2d6aa269 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/Extensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/Extensions.kt @@ -21,11 +21,11 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.util.JsonCanonicalizer import timber.log.Timber -fun CryptoDeviceInfo.canonicalSignable(): String { +internal fun CryptoDeviceInfo.canonicalSignable(): String { return JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableJSONDictionary()) } -fun CryptoCrossSigningKey.canonicalSignable(): String { +internal fun CryptoCrossSigningKey.canonicalSignable(): String { return JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableJSONDictionary()) } @@ -40,7 +40,7 @@ fun String.fromBase64(): ByteArray { /** * Decode the base 64. Return null in case of bad format. Should be used when parsing received data from external source */ -fun String.fromBase64Safe(): ByteArray? { +internal fun String.fromBase64Safe(): ByteArray? { return try { Base64.decode(this, Base64.DEFAULT) } catch (throwable: Throwable) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/CryptoCrossSigningKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/CryptoCrossSigningKey.kt index 202aa55624..606d2e3fc0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/CryptoCrossSigningKey.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/CryptoCrossSigningKey.kt @@ -63,7 +63,7 @@ data class CryptoCrossSigningKey( ) } - data class Builder( + internal data class Builder( val userId: String, val usage: KeyUsage, private var base64Pkey: String? = null, @@ -97,7 +97,7 @@ data class CryptoCrossSigningKey( } } -enum class KeyUsage(val value: String) { +internal enum class KeyUsage(val value: String) { MASTER("master"), SELF_SIGNING("self_signing"), USER_SIGNING("user_signing") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 369a4976c9..b9213ba758 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -83,6 +83,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey +import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade import org.matrix.android.sdk.internal.crypto.store.db.query.create import org.matrix.android.sdk.internal.crypto.store.db.query.delete import org.matrix.android.sdk.internal.crypto.store.db.query.get @@ -94,6 +95,7 @@ import org.matrix.android.sdk.internal.di.CryptoDatabase import org.matrix.android.sdk.internal.di.DeviceId 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.SessionScope import org.matrix.olm.OlmAccount import org.matrix.olm.OlmException @@ -293,7 +295,7 @@ internal class RealmCryptoStore @Inject constructor( realm.insertOrUpdate(entity) } // Ensure all other devices are deleted - u.devices.deleteAllFromRealm() + u.devices.clearWith { it.deleteOnCascade() } u.devices.addAll(new) } } @@ -309,7 +311,7 @@ internal class RealmCryptoStore @Inject constructor( .let { userEntity -> if (masterKey == null || selfSigningKey == null) { // The user has disabled cross signing? - userEntity.crossSigningInfoEntity?.deleteFromRealm() + userEntity.crossSigningInfoEntity?.deleteOnCascade() userEntity.crossSigningInfoEntity = null } else { var shouldResetMyDevicesLocalTrust = false @@ -1633,7 +1635,7 @@ internal class RealmCryptoStore @Inject constructor( } else { // Just override existing, caller should check and untrust id needed val existing = CrossSigningInfoEntity.getOrCreate(realm, userId) - existing.crossSigningKeys.deleteAllFromRealm() + existing.crossSigningKeys.clearWith { it.deleteOnCascade() } existing.crossSigningKeys.addAll( info.crossSigningKeys.map { crossSigningKeysMapper.map(it) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt index fdd3e94754..8599c972e9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/CrossSigningInfoEntity.kt @@ -16,10 +16,11 @@ package org.matrix.android.sdk.internal.crypto.store.db.model -import org.matrix.android.sdk.internal.crypto.model.KeyUsage import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import org.matrix.android.sdk.internal.crypto.model.KeyUsage +import org.matrix.android.sdk.internal.extensions.clearWith internal open class CrossSigningInfoEntity( @PrimaryKey @@ -56,3 +57,8 @@ internal open class CrossSigningInfoEntity( info?.let { crossSigningKeys.add(it) } } } + +internal fun CrossSigningInfoEntity.deleteOnCascade() { + crossSigningKeys.clearWith { it.deleteOnCascade() } + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt index 571b9bb05f..61870ec486 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/DeviceInfoEntity.kt @@ -47,3 +47,8 @@ internal open class DeviceInfoEntity( companion object } + +internal fun DeviceInfoEntity.deleteOnCascade() { + trustLevelEntity?.deleteFromRealm() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt index 8f2357223e..9133413589 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/KeyInfoEntity.kt @@ -30,3 +30,8 @@ internal open class KeyInfoEntity( var signatures: String? = null, var trustLevelEntity: TrustLevelEntity? = null ) : RealmObject() + +internal fun KeyInfoEntity.deleteOnCascade() { + trustLevelEntity?.deleteFromRealm() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt index 52c30a27cc..df9482bf96 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/model/UserEntity.kt @@ -19,13 +19,20 @@ package org.matrix.android.sdk.internal.crypto.store.db.model import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import org.matrix.android.sdk.internal.extensions.clearWith internal open class UserEntity( @PrimaryKey var userId: String? = null, var devices: RealmList = RealmList(), var crossSigningInfoEntity: CrossSigningInfoEntity? = null, - var deviceTrackingStatus: Int = 0) - : RealmObject() { + var deviceTrackingStatus: Int = 0 +) : RealmObject() { companion object } + +internal fun UserEntity.deleteOnCascade() { + devices.clearWith { it.deleteOnCascade() } + crossSigningInfoEntity?.deleteOnCascade() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt index a1f8bd7262..5a3b8e5397 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/query/UserEntitiesQueries.kt @@ -16,11 +16,12 @@ package org.matrix.android.sdk.internal.crypto.store.db.query -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity -import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields import io.realm.Realm import io.realm.kotlin.createObject import io.realm.kotlin.where +import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity +import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields +import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade /** * Get or create a user @@ -39,5 +40,5 @@ internal fun UserEntity.Companion.delete(realm: Realm, userId: String) { realm.where() .equalTo(UserEntityFields.USER_ID, userId) .findFirst() - ?.deleteFromRealm() + ?.deleteOnCascade() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt index 4c1e896a21..052b3f4e72 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tools/Tools.kt @@ -21,7 +21,7 @@ import org.matrix.olm.OlmPkEncryption import org.matrix.olm.OlmPkSigning import org.matrix.olm.OlmUtility -fun withOlmEncryption(block: (OlmPkEncryption) -> T): T { +internal fun withOlmEncryption(block: (OlmPkEncryption) -> T): T { val olmPkEncryption = OlmPkEncryption() try { return block(olmPkEncryption) @@ -30,7 +30,7 @@ fun withOlmEncryption(block: (OlmPkEncryption) -> T): T { } } -fun withOlmDecryption(block: (OlmPkDecryption) -> T): T { +internal fun withOlmDecryption(block: (OlmPkDecryption) -> T): T { val olmPkDecryption = OlmPkDecryption() try { return block(olmPkDecryption) @@ -39,7 +39,7 @@ fun withOlmDecryption(block: (OlmPkDecryption) -> T): T { } } -fun withOlmSigning(block: (OlmPkSigning) -> T): T { +internal fun withOlmSigning(block: (OlmPkSigning) -> T): T { val olmPkSigning = OlmPkSigning() try { return block(olmPkSigning) @@ -48,7 +48,7 @@ fun withOlmSigning(block: (OlmPkSigning) -> T): T { } } -fun withOlmUtility(block: (OlmUtility) -> T): T { +internal fun withOlmUtility(block: (OlmUtility) -> T): T { val olmUtility = OlmUtility() try { return block(olmUtility) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt index e305c7ea38..8b4ce6106b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/DatabaseCleaner.kt @@ -16,6 +16,10 @@ package org.matrix.android.sdk.internal.database +import io.realm.Realm +import io.realm.RealmConfiguration +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.matrix.android.sdk.internal.database.helper.nextDisplayIndex import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntityFields @@ -23,14 +27,11 @@ import org.matrix.android.sdk.internal.database.model.EventEntity 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.TimelineEventEntityFields +import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.SessionLifecycleObserver import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.task.TaskExecutor -import io.realm.Realm -import io.realm.RealmConfiguration -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -56,7 +57,7 @@ internal class DatabaseCleaner @Inject constructor(@SessionDatabase private val } } - private suspend fun cleanUp(realm: Realm, threshold: Long) { + private fun cleanUp(realm: Realm, threshold: Long) { val numberOfEvents = realm.where(EventEntity::class.java).findAll().size val numberOfTimelineEvents = realm.where(TimelineEventEntity::class.java).findAll().size Timber.v("Number of events in db: $numberOfEvents | Number of timeline events in db: $numberOfTimelineEvents") @@ -76,20 +77,7 @@ internal class DatabaseCleaner @Inject constructor(@SessionDatabase private val chunk.numberOfTimelineEvents = chunk.numberOfTimelineEvents - eventsToRemove.size eventsToRemove.forEach { val canDeleteRoot = it.root?.stateKey == null - if (canDeleteRoot) { - it.root?.deleteFromRealm() - } - it.readReceipts?.readReceipts?.deleteAllFromRealm() - it.readReceipts?.deleteFromRealm() - it.annotations?.apply { - editSummary?.deleteFromRealm() - pollResponseSummary?.deleteFromRealm() - referencesSummaryEntity?.deleteFromRealm() - reactionsSummary.deleteAllFromRealm() - } - it.annotations?.deleteFromRealm() - it.readReceipts?.deleteFromRealm() - it.deleteFromRealm() + it.deleteOnCascade(canDeleteRoot) } // We reset the prevToken so we will need to fetch again. chunk.prevToken = null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt index f764c4da4b..b4935cfdcc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt @@ -38,12 +38,6 @@ import io.realm.Sort import io.realm.kotlin.createObject import timber.log.Timber -internal fun ChunkEntity.deleteOnCascade() { - assertIsManaged() - this.timelineEvents.deleteAllFromRealm() - this.deleteFromRealm() -} - internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) { assertIsManaged() val localRealm = this.realm diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/RoomEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/RoomEntityHelper.kt index a4108f0966..724f307e3b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/RoomEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/RoomEntityHelper.kt @@ -19,12 +19,7 @@ package org.matrix.android.sdk.internal.database.helper import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.RoomEntity -internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) { - chunks.remove(chunkEntity) - chunkEntity.deleteOnCascade() -} - -internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) { +internal fun RoomEntity.addIfNecessary(chunkEntity: ChunkEntity) { if (!chunks.contains(chunkEntity)) { chunks.add(chunkEntity) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/TimelineEventEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/TimelineEventEntityHelper.kt index 6f4dac182c..90e867749e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/TimelineEventEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/TimelineEventEntityHelper.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.database.helper import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields -import org.matrix.android.sdk.internal.extensions.assertIsManaged import io.realm.Realm internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long { @@ -29,11 +28,3 @@ internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long { currentIdNum.toLong() + 1 } } - -internal fun TimelineEventEntity.deleteOnCascade() { - assertIsManaged() - root?.deleteFromRealm() - annotations?.deleteFromRealm() - readReceipts?.deleteFromRealm() - deleteFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt index 9770352a95..68533a3c19 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ChunkEntity.kt @@ -21,6 +21,8 @@ import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.Index import io.realm.annotations.LinkingObjects +import org.matrix.android.sdk.internal.extensions.assertIsManaged +import org.matrix.android.sdk.internal.extensions.clearWith internal open class ChunkEntity(@Index var prevToken: String? = null, // Because of gaps we can have several chunks with nextToken == null @@ -43,3 +45,12 @@ internal open class ChunkEntity(@Index var prevToken: String? = null, companion object } + +internal fun ChunkEntity.deleteOnCascade(deleteStateEvents: Boolean, canDeleteRoot: Boolean) { + assertIsManaged() + if (deleteStateEvents) { + stateEvents.deleteAllFromRealm() + } + timelineEvents.clearWith { it.deleteOnCascade(canDeleteRoot) } + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt index 3e5e277613..33f26d439f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt @@ -31,3 +31,11 @@ internal open class EventAnnotationsSummaryEntity( companion object } + +internal fun EventAnnotationsSummaryEntity.deleteOnCascade() { + reactionsSummary.deleteAllFromRealm() + editSummary?.deleteFromRealm() + referencesSummaryEntity?.deleteFromRealm() + pollResponseSummary?.deleteFromRealm() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRuleEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRuleEntity.kt index 85375c8064..5bfe2833f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRuleEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRuleEntity.kt @@ -40,3 +40,8 @@ internal open class PushRuleEntity( companion object } + +internal fun PushRuleEntity.deleteOnCascade() { + conditions?.deleteAllFromRealm() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt index 21e3510cd2..571bc71c27 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PushRulesEntity.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model import org.matrix.android.sdk.api.pushrules.RuleKind import io.realm.RealmList import io.realm.RealmObject +import org.matrix.android.sdk.internal.extensions.clearWith internal open class PushRulesEntity( var scope: String = "", @@ -35,3 +36,8 @@ internal open class PushRulesEntity( companion object } + +internal fun PushRulesEntity.deleteOnCascade() { + pushRules.clearWith { it.deleteOnCascade() } + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PusherEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PusherEntity.kt index f85c01c48a..af8e4f2d37 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PusherEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PusherEntity.kt @@ -15,8 +15,8 @@ */ package org.matrix.android.sdk.internal.database.model -import org.matrix.android.sdk.api.session.pushers.PusherState import io.realm.RealmObject +import org.matrix.android.sdk.api.session.pushers.PusherState // TODO // at java.lang.Thread.run(Thread.java:764) @@ -54,3 +54,8 @@ internal open class PusherEntity( companion object } + +internal fun PusherEntity.deleteOnCascade() { + data?.deleteFromRealm() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptsSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptsSummaryEntity.kt index 98b4329076..9ca4adc33e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/ReadReceiptsSummaryEntity.kt @@ -34,3 +34,8 @@ internal open class ReadReceiptsSummaryEntity( companion object } + +internal fun ReadReceiptsSummaryEntity.deleteOnCascade() { + readReceipts.deleteAllFromRealm() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt index 7bd0dbbb8f..30bbde70c2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/TimelineEventEntity.kt @@ -20,6 +20,7 @@ import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.Index import io.realm.annotations.LinkingObjects +import org.matrix.android.sdk.internal.extensions.assertIsManaged internal open class TimelineEventEntity(var localId: Long = 0, @Index var eventId: String = "", @@ -39,3 +40,13 @@ internal open class TimelineEventEntity(var localId: Long = 0, companion object } + +internal fun TimelineEventEntity.deleteOnCascade(canDeleteRoot: Boolean) { + assertIsManaged() + if (canDeleteRoot) { + root?.deleteFromRealm() + } + annotations?.deleteOnCascade() + readReceipts?.deleteOnCascade() + deleteFromRealm() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt index 0718096fd5..e52e32e16a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/extensions/RealmExtensions.kt @@ -16,8 +16,18 @@ package org.matrix.android.sdk.internal.extensions +import io.realm.RealmList import io.realm.RealmObject internal fun RealmObject.assertIsManaged() { check(isManaged) { "${javaClass.simpleName} entity should be managed to use this function" } } + +/** + * Clear a RealmList by deleting all its items calling the provided lambda + */ +internal fun RealmList.clearWith(delete: (T) -> Unit) { + while (!isEmpty()) { + first()?.let { delete.invoke(it) } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt index 4c7d370446..125c8f0022 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/GetPushersTask.kt @@ -19,6 +19,7 @@ import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.api.session.pushers.PusherState import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.PusherEntity +import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.executeRequest @@ -41,7 +42,8 @@ internal class DefaultGetPushersTask @Inject constructor( monarchy.awaitTransaction { realm -> // clear existings? realm.where(PusherEntity::class.java) - .findAll().deleteAllFromRealm() + .findAll() + .forEach { it.deleteOnCascade() } response.pushers?.forEach { jsonPusher -> jsonPusher.toEntity().also { it.state = PusherState.REGISTERED diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt index 6ba769a3b7..6a4b891ecf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/SavePushRulesTask.kt @@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.pushrules.RuleSetKey import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper import org.matrix.android.sdk.internal.database.model.PushRulesEntity +import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.util.awaitTransaction @@ -40,7 +41,7 @@ internal class DefaultSavePushRulesTask @Inject constructor(@SessionDatabase pri // clear current push rules realm.where(PushRulesEntity::class.java) .findAll() - .deleteAllFromRealm() + .forEach { it.deleteOnCascade() } // Save only global rules for the moment val globalRules = params.pushRules.global diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt index 1a497b8835..c38dcd00a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -22,16 +22,16 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.send.SendState -import org.matrix.android.sdk.internal.database.helper.addOrUpdate +import org.matrix.android.sdk.internal.database.helper.addIfNecessary import org.matrix.android.sdk.internal.database.helper.addStateEvent import org.matrix.android.sdk.internal.database.helper.addTimelineEvent -import org.matrix.android.sdk.internal.database.helper.deleteOnCascade import org.matrix.android.sdk.internal.database.helper.merge import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity 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.RoomSummaryEntity +import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.find @@ -172,7 +172,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri val currentLastForwardChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) if (currentChunk != currentLastForwardChunk) { currentChunk.isLastForward = true - currentLastForwardChunk?.deleteOnCascade() + currentLastForwardChunk?.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = false) RoomSummaryEntity.where(realm, roomId).findFirst()?.apply { latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } @@ -235,7 +235,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri } } chunksToDelete.forEach { - it.deleteOnCascade() + it.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = false) } val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) val shouldUpdateSummary = roomSummaryEntity.latestPreviewableEvent == null @@ -244,7 +244,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) } if (currentChunk.isValid) { - RoomEntity.where(realm, roomId).findFirst()?.addOrUpdate(currentChunk) + RoomEntity.where(realm, roomId).findFirst()?.addIfNecessary(currentChunk) } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt index 456b0f9c26..6d1b3ae034 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt @@ -30,9 +30,8 @@ import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult -import org.matrix.android.sdk.internal.database.helper.addOrUpdate +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.deleteOnCascade import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity @@ -40,6 +39,7 @@ 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.RoomMemberSummaryEntity +import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.find import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom @@ -48,6 +48,7 @@ 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.DefaultInitialSyncProgressService import org.matrix.android.sdk.internal.session.mapWithProgress import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource @@ -175,7 +176,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle syncLocalTimestampMillis, isInitialSync ) - roomEntity.addOrUpdate(chunkEntity) + roomEntity.addIfNecessary(chunkEntity) } val hasRoomMember = roomSync.state?.events?.firstOrNull { it.type == EventType.STATE_ROOM_MEMBER @@ -263,7 +264,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle val leftMember = RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst() val membership = leftMember?.membership ?: Membership.LEAVE roomEntity.membership = membership - roomEntity.chunks.deleteAllFromRealm() + roomEntity.chunks.clearWith { it.deleteOnCascade(deleteStateEvents = true, canDeleteRoot = true) } roomTypingUsersHandler.handle(realm, roomId, null) roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.LEAVE) roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary, roomSync.unreadNotifications) @@ -340,7 +341,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } } // Finally delete the local echo - sendingEventEntity.deleteOnCascade() + sendingEventEntity.deleteOnCascade(true) } else { Timber.v("Can't find corresponding local echo for tx:$it") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt index 0e549172f3..449d47abe5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/UserAccountDataSyncHandler.kt @@ -16,8 +16,10 @@ package org.matrix.android.sdk.internal.session.sync -import com.squareup.moshi.Moshi import com.zhuinden.monarchy.Monarchy +import io.realm.Realm +import io.realm.RealmList +import io.realm.kotlin.where import org.matrix.android.sdk.api.pushrules.RuleScope import org.matrix.android.sdk.api.pushrules.RuleSetKey import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse @@ -37,6 +39,7 @@ 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.UserAccountDataEntity import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields +import org.matrix.android.sdk.internal.database.model.deleteOnCascade import org.matrix.android.sdk.internal.database.query.getDirectRooms import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.where @@ -50,9 +53,6 @@ import org.matrix.android.sdk.internal.session.sync.model.accountdata.IgnoredUse import org.matrix.android.sdk.internal.session.sync.model.accountdata.UserAccountDataSync import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask -import io.realm.Realm -import io.realm.RealmList -import io.realm.kotlin.where import timber.log.Timber import javax.inject.Inject @@ -60,7 +60,6 @@ internal class UserAccountDataSyncHandler @Inject constructor( @SessionDatabase private val monarchy: Monarchy, @UserId private val userId: String, private val directChatsHelper: DirectChatsHelper, - private val moshi: Moshi, private val updateUserAccountDataTask: UpdateUserAccountDataTask) { fun handle(realm: Realm, accountData: UserAccountDataSync?) { @@ -113,7 +112,7 @@ internal class UserAccountDataSyncHandler @Inject constructor( val pushRules = event.content.toModel() ?: return realm.where(PushRulesEntity::class.java) .findAll() - .deleteAllFromRealm() + .forEach { it.deleteOnCascade() } // Save only global rules for the moment val globalRules = pushRules.global