1
0
mirror of https://github.com/vector-im/riotX-android synced 2025-10-06 00:02:48 +02:00

Compare commits

...

14 Commits

150 changed files with 1462 additions and 902 deletions

View File

@@ -29,7 +29,6 @@ def glide = "4.13.2"
def bigImageViewer = "1.8.1"
def jjwt = "0.11.5"
def vanniktechEmoji = "0.15.0"
def fragment = "1.5.0"
// Testing
@@ -162,6 +161,9 @@ ext.libs = [
apache : [
'commonsImaging' : "org.apache.sanselan:sanselan:0.97-incubator"
],
realm : [
'base' : "io.realm.kotlin:library-base:${realmKotlinVersion}"
],
tests : [
'kluent' : "org.amshove.kluent:kluent-android:1.68",
'timberJunitRule' : "net.lachlanmckee:timber-junit-rule:1.0.1",

View File

@@ -138,6 +138,7 @@ ext.groups = [
'io.opencensus',
'io.reactivex.rxjava2',
'io.realm',
'io.realm.kotlin',
'it.unimi.dsi',
'jakarta.activation',
'jakarta.xml.bind',

View File

@@ -33,6 +33,9 @@ signing.element.storePassword=Secret
signing.element.keyId=Secret
signing.element.keyPassword=Secret
# This belongs here as it's the only way to share the version number between the plugin and the library.
realmKotlinVersion = 1.0.1
# Dummy values for signing secrets / nightly
signing.element.nightly.storePassword=Secret
signing.element.nightly.keyId=Secret

View File

@@ -1,14 +1,3 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
apply plugin: 'realm-android'
apply plugin: "org.jetbrains.dokka"
if (project.hasProperty("coverage")) {
apply plugin: 'jacoco'
}
buildscript {
repositories {
// Do not use `mavenCentral()`, it prevents Dependabot from working properly
@@ -21,6 +10,21 @@ buildscript {
}
}
plugins {
id("io.realm.kotlin") version "${realmKotlinVersion}"
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
apply plugin: 'realm-android'
apply plugin: "org.jetbrains.dokka"
if (project.hasProperty("coverage")) {
apply plugin: 'jacoco'
}
dokkaHtml {
dokkaSourceSets {
configureEach {
@@ -172,6 +176,7 @@ dependencies {
// Database
implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
implementation libs.realm.base
kapt 'dk.ilios:realmfieldnameshelper:2.0.0'

View File

@@ -16,12 +16,15 @@
package org.matrix.android.sdk.api
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import okhttp3.ConnectionSpec
import okhttp3.Interceptor
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
import java.net.Proxy
data class MatrixConfiguration(
val coroutineScope: CoroutineScope = MainScope(),
val applicationFlavor: String = "Default-application-flavor",
val cryptoConfig: MXCryptoConfig = MXCryptoConfig(),
val integrationUIUrl: String = "https://scalar.vector.im/",

View File

@@ -32,7 +32,7 @@ interface IdentityService {
/**
* Return the current identity server URL used by this account. Returns null if no identity server is configured.
*/
fun getCurrentIdentityServerUrl(): String?
suspend fun getCurrentIdentityServerUrl(): String?
/**
* Check if the identity server is valid.
@@ -105,7 +105,7 @@ interface IdentityService {
* @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server
* has been changed
*/
fun getUserConsent(): Boolean
suspend fun getUserConsent(): Boolean
/**
* Set the user consent to the provided value. Application MUST explicitly ask for the user consent to send their private data
@@ -113,7 +113,7 @@ interface IdentityService {
* Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details.
* @param newValue true if the user explicitly give their consent, false if the user wants to revoke their consent.
*/
fun setUserConsent(newValue: Boolean)
suspend fun setUserConsent(newValue: Boolean)
/**
* Get the status of the current user's threePid.

View File

@@ -20,18 +20,23 @@ import android.content.Context
import dagger.Binds
import dagger.Module
import dagger.Provides
import io.realm.RealmConfiguration
import io.realm.kotlin.RealmConfiguration
import kotlinx.coroutines.CoroutineScope
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
import org.matrix.android.sdk.internal.auth.db.AUTH_REALM_SCHEMA
import org.matrix.android.sdk.internal.auth.db.AuthRealmMigration
import org.matrix.android.sdk.internal.auth.db.AuthRealmModule
import org.matrix.android.sdk.internal.auth.db.RealmPendingSessionStore
import org.matrix.android.sdk.internal.auth.db.RealmSessionParamsStore
import org.matrix.android.sdk.internal.auth.login.DefaultDirectLoginTask
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.RealmKeysUtils
import org.matrix.android.sdk.internal.di.AuthDatabase
import org.matrix.android.sdk.internal.di.MatrixCoroutineScope
import org.matrix.android.sdk.internal.di.MatrixScope
import org.matrix.android.sdk.internal.legacy.DefaultLegacySessionImporter
import org.matrix.android.sdk.internal.wellknown.WellknownModule
import java.io.File
@@ -56,16 +61,31 @@ internal abstract class AuthModule {
old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm"))
}
return RealmConfiguration.Builder()
return RealmConfiguration.Builder(AUTH_REALM_SCHEMA)
.apply {
realmKeysUtils.configureEncryption(this, DB_ALIAS)
}
.name("matrix-sdk-auth.realm")
.modules(AuthRealmModule())
.schemaVersion(authRealmMigration.schemaVersion)
.migration(authRealmMigration)
.build()
}
@JvmStatic
@Provides
@AuthDatabase
@MatrixScope
fun providesRealmInstance(
@AuthDatabase realmConfiguration: RealmConfiguration,
@MatrixCoroutineScope matrixCoroutineScope: CoroutineScope,
matrixCoroutineDispatchers: MatrixCoroutineDispatchers
): RealmInstance {
return RealmInstance(
coroutineScope = matrixCoroutineScope,
realmConfiguration = realmConfiguration,
coroutineDispatcher = matrixCoroutineDispatchers.io
)
}
}
@Binds

View File

@@ -16,35 +16,23 @@
package org.matrix.android.sdk.internal.auth
import com.zhuinden.monarchy.Monarchy
import io.realm.kotlin.where
import kotlinx.coroutines.runBlocking
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
import org.matrix.android.sdk.internal.database.model.KnownServerUrlEntity
import org.matrix.android.sdk.internal.di.GlobalDatabase
import javax.inject.Inject
internal class DefaultHomeServerHistoryService @Inject constructor(
@GlobalDatabase private val monarchy: Monarchy
private val knownServerUrlStore: KnownServerUrlStore
) : HomeServerHistoryService {
override fun getKnownServersUrls(): List<String> {
return monarchy.fetchAllMappedSync(
{ realm ->
realm.where<KnownServerUrlEntity>()
},
{ it.url }
)
override fun getKnownServersUrls(): List<String> = runBlocking {
knownServerUrlStore.getAll()
}
override fun addHomeServerToHistory(url: String) {
monarchy.writeAsync { realm ->
KnownServerUrlEntity(url).let {
realm.insertOrUpdate(it)
}
}
override fun addHomeServerToHistory(url: String) = runBlocking {
knownServerUrlStore.add(url)
}
override fun clearHistory() {
monarchy.runTransactionSync { it.where<KnownServerUrlEntity>().findAll().deleteAllFromRealm() }
override fun clearHistory() = runBlocking {
knownServerUrlStore.deleteAll()
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 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.auth
import io.realm.kotlin.UpdatePolicy
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.await
import org.matrix.android.sdk.internal.di.GlobalDatabase
import org.matrix.android.sdk.internal.raw.db.model.KnownServerUrlEntity
import javax.inject.Inject
internal class KnownServerUrlStore @Inject constructor(
@GlobalDatabase private val realmInstance: RealmInstance,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
) {
suspend fun getAll(): List<String> = withContext(coroutineDispatchers.io) {
val realm = realmInstance.getRealm()
realm.query(KnownServerUrlEntity::class)
.await()
.map { it.url }
}
suspend fun add(url: String) {
realmInstance.write {
val entity = KnownServerUrlEntity().apply {
this.url = url
}
copyToRealm(entity, updatePolicy = UpdatePolicy.ALL)
}
}
suspend fun deleteAll() {
realmInstance.write {
val entities = query(KnownServerUrlEntity::class).find()
delete(entities)
}
}
}

View File

@@ -16,18 +16,18 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo001
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo002
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo003
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo004
import org.matrix.android.sdk.internal.auth.db.migration.MigrateAuthTo005
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import org.matrix.android.sdk.internal.database.MatrixAutomaticSchemaMigration
import javax.inject.Inject
internal class AuthRealmMigration @Inject constructor() : MatrixRealmMigration(
internal class AuthRealmMigration @Inject constructor() : MatrixAutomaticSchemaMigration(
dbName = "Auth",
schemaVersion = 5L,
schemaVersion = 5L
) {
/**
* Forces all AuthRealmMigration instances to be equal.
@@ -36,11 +36,11 @@ internal class AuthRealmMigration @Inject constructor() : MatrixRealmMigration(
override fun equals(other: Any?) = other is AuthRealmMigration
override fun hashCode() = 4000
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
if (oldVersion < 1) MigrateAuthTo001(realm).perform()
if (oldVersion < 2) MigrateAuthTo002(realm).perform()
if (oldVersion < 3) MigrateAuthTo003(realm).perform()
if (oldVersion < 4) MigrateAuthTo004(realm).perform()
if (oldVersion < 5) MigrateAuthTo005(realm).perform()
override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) {
if (oldVersion < 1) MigrateAuthTo001(migrationContext).perform()
if (oldVersion < 2) MigrateAuthTo002(migrationContext).perform()
if (oldVersion < 3) MigrateAuthTo003(migrationContext).perform()
if (oldVersion < 4) MigrateAuthTo004(migrationContext).perform()
if (oldVersion < 5) MigrateAuthTo005(migrationContext).perform()
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright 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.
@@ -16,16 +16,10 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.annotations.RealmModule
/**
* Realm module for authentication classes.
*/
@RealmModule(
library = true,
classes = [
SessionParamsEntity::class,
PendingSessionEntity::class
]
internal val AUTH_REALM_SCHEMA = setOf(
SessionParamsEntity::class,
PendingSessionEntity::class
)
internal class AuthRealmModule

View File

@@ -16,14 +16,14 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.RealmObject
import io.realm.kotlin.types.RealmObject
internal open class PendingSessionEntity(
var homeServerConnectionConfigJson: String = "",
var clientSecret: String = "",
var sendAttempt: Int = 0,
var resetPasswordDataJson: String? = null,
var currentSession: String? = null,
var isRegistrationStarted: Boolean = false,
var currentThreePidDataJson: String? = null
) : RealmObject()
internal class PendingSessionEntity : RealmObject {
var homeServerConnectionConfigJson: String = ""
var clientSecret: String = ""
var sendAttempt: Int = 0
var resetPasswordDataJson: String? = null
var currentSession: String? = null
var isRegistrationStarted: Boolean = false
var currentThreePidDataJson: String? = null
}

View File

@@ -57,14 +57,14 @@ internal class PendingSessionMapper @Inject constructor(moshi: Moshi) {
val resetPasswordDataJson = resetPasswordDataAdapter.toJson(sessionData.resetPasswordData)
val currentThreePidDataJson = threePidDataAdapter.toJson(sessionData.currentThreePidData)
return PendingSessionEntity(
homeServerConnectionConfigJson = homeServerConnectionConfigJson,
clientSecret = sessionData.clientSecret,
sendAttempt = sessionData.sendAttempt,
resetPasswordDataJson = resetPasswordDataJson,
currentSession = sessionData.currentSession,
isRegistrationStarted = sessionData.isRegistrationStarted,
currentThreePidDataJson = currentThreePidDataJson
)
return PendingSessionEntity().apply {
this.homeServerConnectionConfigJson = homeServerConnectionConfigJson
this.clientSecret = sessionData.clientSecret
this.sendAttempt = sessionData.sendAttempt
this.resetPasswordDataJson = resetPasswordDataJson
this.currentSession = sessionData.currentSession
this.isRegistrationStarted = sessionData.isRegistrationStarted
this.currentThreePidDataJson = currentThreePidDataJson
}
}
}

View File

@@ -16,47 +16,44 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.internal.auth.PendingSessionStore
import org.matrix.android.sdk.internal.database.awaitTransaction
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.di.AuthDatabase
import javax.inject.Inject
internal class RealmPendingSessionStore @Inject constructor(
private val mapper: PendingSessionMapper,
@AuthDatabase
private val realmConfiguration: RealmConfiguration
private val realmInstance: RealmInstance,
) : PendingSessionStore {
override suspend fun savePendingSessionData(pendingSessionData: PendingSessionData) {
awaitTransaction(realmConfiguration) { realm ->
realmInstance.write {
val entity = mapper.map(pendingSessionData)
if (entity != null) {
realm.where(PendingSessionEntity::class.java)
.findAll()
.deleteAllFromRealm()
realm.insert(entity)
deleteAllPendingSessions()
copyToRealm(entity)
}
}
}
override fun getPendingSessionData(): PendingSessionData? {
return Realm.getInstance(realmConfiguration).use { realm ->
realm
.where(PendingSessionEntity::class.java)
.findAll()
.map { mapper.map(it) }
.firstOrNull()
}
return realmInstance.getBlockingRealm()
.query(PendingSessionEntity::class)
.find()
.map { mapper.map(it) }
.firstOrNull()
}
override suspend fun delete() {
awaitTransaction(realmConfiguration) {
it.where(PendingSessionEntity::class.java)
.findAll()
.deleteAllFromRealm()
realmInstance.write {
deleteAllPendingSessions()
}
}
private fun MutableRealm.deleteAllPendingSessions() {
val pendingSessionEntities = query(PendingSessionEntity::class).find()
delete(pendingSessionEntities)
}
}

View File

@@ -16,14 +16,12 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.exceptions.RealmPrimaryKeyConstraintException
import io.realm.kotlin.UpdatePolicy
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.auth.data.SessionParams
import org.matrix.android.sdk.api.auth.data.sessionId
import org.matrix.android.sdk.internal.auth.SessionParamsStore
import org.matrix.android.sdk.internal.database.awaitTransaction
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.di.AuthDatabase
import timber.log.Timber
import javax.inject.Inject
@@ -31,60 +29,49 @@ import javax.inject.Inject
internal class RealmSessionParamsStore @Inject constructor(
private val mapper: SessionParamsMapper,
@AuthDatabase
private val realmConfiguration: RealmConfiguration
private val realmInstance: RealmInstance
) : SessionParamsStore {
override fun getLast(): SessionParams? {
return Realm.getInstance(realmConfiguration).use { realm ->
realm
.where(SessionParamsEntity::class.java)
.findAll()
.map { mapper.map(it) }
.lastOrNull()
}
return realmInstance.getBlockingRealm()
.query(SessionParamsEntity::class)
.find()
.map { mapper.map(it) }
.lastOrNull()
}
override fun get(sessionId: String): SessionParams? {
return Realm.getInstance(realmConfiguration).use { realm ->
realm
.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
.findAll()
.map { mapper.map(it) }
.firstOrNull()
}
return realmInstance.getBlockingRealm()
.query(SessionParamsEntity::class)
.query("sessionId == $0", sessionId)
.first()
.find()
?.let { mapper.map(it) }
}
override fun getAll(): List<SessionParams> {
return Realm.getInstance(realmConfiguration).use { realm ->
realm
.where(SessionParamsEntity::class.java)
.findAll()
.mapNotNull { mapper.map(it) }
}
return realmInstance.getBlockingRealm()
.query(SessionParamsEntity::class)
.find()
.mapNotNull { mapper.map(it) }
}
override suspend fun save(sessionParams: SessionParams) {
awaitTransaction(realmConfiguration) {
realmInstance.write {
val entity = mapper.map(sessionParams)
if (entity != null) {
try {
it.insert(entity)
} catch (e: RealmPrimaryKeyConstraintException) {
Timber.e(e, "Something wrong happened during previous session creation. Override with new credentials")
it.insertOrUpdate(entity)
}
copyToRealm(entity, updatePolicy = UpdatePolicy.ALL)
}
}
}
override suspend fun setTokenInvalid(sessionId: String) {
awaitTransaction(realmConfiguration) { realm ->
val currentSessionParams = realm
.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
.findAll()
.firstOrNull()
realmInstance.write {
val currentSessionParams =
query(SessionParamsEntity::class)
.query("sessionId == $0", sessionId)
.first()
.find()
if (currentSessionParams == null) {
// Should not happen
@@ -98,13 +85,12 @@ internal class RealmSessionParamsStore @Inject constructor(
}
override suspend fun updateCredentials(newCredentials: Credentials) {
awaitTransaction(realmConfiguration) { realm ->
val currentSessionParams = realm
.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.SESSION_ID, newCredentials.sessionId())
.findAll()
.map { mapper.map(it) }
.firstOrNull()
realmInstance.write {
val currentSessionParams = query(SessionParamsEntity::class)
.query("sessionId == $0", newCredentials.sessionId())
.first()
.find()
?.let { mapper.map(it) }
if (currentSessionParams == null) {
// Should not happen
@@ -119,26 +105,25 @@ internal class RealmSessionParamsStore @Inject constructor(
val entity = mapper.map(newSessionParams)
if (entity != null) {
realm.insertOrUpdate(entity)
copyToRealm(entity, updatePolicy = UpdatePolicy.ALL)
}
}
}
}
override suspend fun delete(sessionId: String) {
awaitTransaction(realmConfiguration) {
it.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.SESSION_ID, sessionId)
.findAll()
.deleteAllFromRealm()
realmInstance.write {
val sessionParam = query(SessionParamsEntity::class)
.query("sessionId == $0", sessionId)
.find()
delete(sessionParam)
}
}
override suspend fun deleteAll() {
awaitTransaction(realmConfiguration) {
it.where(SessionParamsEntity::class.java)
.findAll()
.deleteAllFromRealm()
realmInstance.write {
val sessionParam = query(SessionParamsEntity::class).find()
delete(sessionParam)
}
}
}

View File

@@ -16,16 +16,17 @@
package org.matrix.android.sdk.internal.auth.db
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey
internal open class SessionParamsEntity(
@PrimaryKey var sessionId: String = "",
var userId: String = "",
var credentialsJson: String = "",
var homeServerConnectionConfigJson: String = "",
// Set to false when the token is invalid and the user has been soft logged out
// In case of hard logout, this object is deleted from DB
var isTokenValid: Boolean = true,
var loginType: String = "",
) : RealmObject()
internal class SessionParamsEntity : RealmObject {
@PrimaryKey var sessionId: String = ""
var userId: String = ""
var credentialsJson: String = ""
var homeServerConnectionConfigJson: String = ""
// Set to false when the token is invalid and the user has been soft logged out
// In case of hard logout, this object is deleted from DB
var isTokenValid: Boolean = true
var loginType: String = ""
}

View File

@@ -50,13 +50,13 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
if (credentialsJson == null || homeServerConnectionConfigJson == null) {
return null
}
return SessionParamsEntity(
sessionParams.credentials.sessionId(),
sessionParams.userId,
credentialsJson,
homeServerConnectionConfigJson,
sessionParams.isTokenValid,
sessionParams.loginType.name,
)
return SessionParamsEntity().apply {
this.sessionId = sessionParams.credentials.sessionId()
this.userId = sessionParams.userId
this.credentialsJson = credentialsJson
this.homeServerConnectionConfigJson = homeServerConnectionConfigJson
this.isTokenValid = sessionParams.isTokenValid
this.loginType = sessionParams.loginType.name
}
}
}

View File

@@ -16,26 +16,13 @@
package org.matrix.android.sdk.internal.auth.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.auth.db.PendingSessionEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateAuthTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
internal class MigrateAuthTo001(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 1) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Create PendingSessionEntity")
realm.schema.create("PendingSessionEntity")
.addField(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, String::class.java)
.setRequired(PendingSessionEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, true)
.addField(PendingSessionEntityFields.CLIENT_SECRET, String::class.java)
.setRequired(PendingSessionEntityFields.CLIENT_SECRET, true)
.addField(PendingSessionEntityFields.SEND_ATTEMPT, Integer::class.java)
.setRequired(PendingSessionEntityFields.SEND_ATTEMPT, true)
.addField(PendingSessionEntityFields.RESET_PASSWORD_DATA_JSON, String::class.java)
.addField(PendingSessionEntityFields.CURRENT_SESSION, String::class.java)
.addField(PendingSessionEntityFields.IS_REGISTRATION_STARTED, Boolean::class.java)
.addField(PendingSessionEntityFields.CURRENT_THREE_PID_DATA_JSON, String::class.java)
}
}

View File

@@ -16,18 +16,13 @@
package org.matrix.android.sdk.internal.auth.db.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateAuthTo002(realm: DynamicRealm) : RealmMigrator(realm, 2) {
internal class MigrateAuthTo002(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 2) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Add boolean isTokenValid in SessionParamsEntity, with value true")
realm.schema.get("SessionParamsEntity")
?.addField(SessionParamsEntityFields.IS_TOKEN_VALID, Boolean::class.java)
?.transform { it.set(SessionParamsEntityFields.IS_TOKEN_VALID, true) }
}
}

View File

@@ -16,32 +16,24 @@
package org.matrix.android.sdk.internal.auth.db.migration
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.auth.data.sessionId
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
internal class MigrateAuthTo003(realm: DynamicRealm) : RealmMigrator(realm, 3) {
internal class MigrateAuthTo003(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 3) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update SessionParamsEntity primary key, to allow several sessions with the same userId")
realm.schema.get("SessionParamsEntity")
?.removePrimaryKey()
?.addField(SessionParamsEntityFields.SESSION_ID, String::class.java)
?.setRequired(SessionParamsEntityFields.SESSION_ID, true)
?.transform {
val credentialsJson = it.getString(SessionParamsEntityFields.CREDENTIALS_JSON)
val credentials = MoshiProvider.providesMoshi()
.adapter(Credentials::class.java)
.fromJson(credentialsJson)
it.set(SessionParamsEntityFields.SESSION_ID, credentials!!.sessionId())
}
?.addPrimaryKey(SessionParamsEntityFields.SESSION_ID)
val credentialsAdapter = MoshiProvider.providesMoshi()
.adapter(Credentials::class.java)
migrationContext.enumerate("SessionParamsEntity") { oldObject, newObject ->
val credentialsJson = oldObject.getValue("credentialsJson", String::class)
val credentials = credentialsAdapter.fromJson(credentialsJson)
newObject?.set("sessionId", credentials!!.sessionId())
}
}
}

View File

@@ -17,41 +17,39 @@
package org.matrix.android.sdk.internal.auth.db.migration
import android.net.Uri
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
internal class MigrateAuthTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
internal class MigrateAuthTo004(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 4) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update SessionParamsEntity to add HomeServerConnectionConfig.homeServerUriBase value")
val adapter = MoshiProvider.providesMoshi()
.adapter(HomeServerConnectionConfig::class.java)
realm.schema.get("SessionParamsEntity")
?.transform {
val homeserverConnectionConfigJson = it.getString(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON)
migrationContext.enumerate("SessionParamsEntity") { oldObj, newObj ->
val homeserverConnectionConfigJson = oldObj.getValue("homeServerConnectionConfigJson", String::class)
val homeserverConnectionConfig = adapter
.fromJson(homeserverConnectionConfigJson)
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
val homeserverConnectionConfig = adapter
.fromJson(homeserverConnectionConfigJson)
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
// "https://matrix-client.matrix.org". So fix that here
val alteredHomeserverConnectionConfig =
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
homeserverConnectionConfig.copy(
homeServerUri = Uri.parse("https://matrix.org"),
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
)
} else {
homeserverConnectionConfig
}
newObj?.set("homeServerConnectionConfigJson", adapter.toJson(alteredHomeserverConnectionConfig))
val homeserverUrl = homeserverConnectionConfig?.homeServerUri?.toString()
// Special case for matrix.org. Old session may use "https://matrix.org", newer one may use
// "https://matrix-client.matrix.org". So fix that here
val alteredHomeserverConnectionConfig =
if (homeserverUrl == "https://matrix.org" || homeserverUrl == "https://matrix-client.matrix.org") {
homeserverConnectionConfig.copy(
homeServerUri = Uri.parse("https://matrix.org"),
homeServerUriBase = Uri.parse("https://matrix-client.matrix.org")
)
} else {
homeserverConnectionConfig
}
it.set(SessionParamsEntityFields.HOME_SERVER_CONNECTION_CONFIG_JSON, adapter.toJson(alteredHomeserverConnectionConfig))
}
}
}
}

View File

@@ -16,20 +16,18 @@
package org.matrix.android.sdk.internal.auth.db.migration
import io.realm.DynamicRealm
import io.realm.kotlin.migration.AutomaticSchemaMigration
import org.matrix.android.sdk.api.auth.LoginType
import org.matrix.android.sdk.internal.auth.db.SessionParamsEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
import timber.log.Timber
internal class MigrateAuthTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
internal class MigrateAuthTo005(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, targetSchemaVersion = 5) {
override fun doMigrate(realm: DynamicRealm) {
override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
Timber.d("Update SessionParamsEntity to add LoginType")
realm.schema.get("SessionParamsEntity")
?.addField(SessionParamsEntityFields.LOGIN_TYPE, String::class.java)
?.setRequired(SessionParamsEntityFields.LOGIN_TYPE, true)
?.transform { it.set(SessionParamsEntityFields.LOGIN_TYPE, LoginType.UNKNOWN.name) }
migrationContext.enumerate("SessionParamsEntity") { _, newObj ->
newObj?.set("loginType", LoginType.UNKNOWN.name)
}
}
}

View File

@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.crypto.store.db
import android.util.Base64
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmObject
import io.realm.RealmModel
import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.util.zip.GZIPInputStream
@@ -37,7 +37,7 @@ internal fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Re
/**
* Get realm, do the query, copy from realm, close realm, and return the copied result.
*/
internal fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
internal fun <T : RealmModel> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
return Realm.getInstance(realmConfiguration).use { realm ->
action.invoke(realm)?.let { realm.copyFromRealm(it) }
}
@@ -46,7 +46,7 @@ internal fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConf
/**
* Get realm, do the list query, copy from realm, close realm, and return the copied result.
*/
internal fun <T : RealmObject> doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable<T>): Iterable<T> {
internal fun <T : RealmModel> doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable<T>): Iterable<T> {
return Realm.getInstance(realmConfiguration).use { realm ->
action.invoke(realm).let { realm.copyFromRealm(it) }
}

View File

@@ -25,6 +25,7 @@ import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.Sort
import io.realm.kotlin.createObject
import io.realm.kotlin.deleteFromRealm
import io.realm.kotlin.where
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.extensions.tryOrNull

View File

@@ -16,13 +16,15 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
@RealmClass
internal open class AuditTrailEntity(
var ageLocalTs: Long? = null,
@Index var type: String? = null,
var contentJson: String? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -17,16 +17,19 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.session.crypto.crosssigning.KeyUsage
import org.matrix.android.sdk.internal.extensions.clearWith
@RealmClass
internal open class CrossSigningInfoEntity(
@PrimaryKey
var userId: String? = null,
var crossSigningKeys: RealmList<KeyInfoEntity> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object

View File

@@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo

View File

@@ -16,12 +16,14 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.olm.OlmAccount
@RealmClass
internal open class CryptoMetadataEntity(
// The current user id.
@PrimaryKey var userId: String? = null,
@@ -53,7 +55,7 @@ internal open class CryptoMetadataEntity(
var keyBackupRecoveryKeyVersion: String? = null
// var crossSigningInfoEntity: CrossSigningInfoEntity? = null
) : RealmObject() {
) : RealmModel {
// Deserialize data
fun getOlmAccount(): OlmAccount? {

View File

@@ -16,9 +16,11 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class CryptoRoomEntity(
@PrimaryKey var roomId: String? = null,
var algorithm: String? = null,
@@ -34,7 +36,7 @@ internal open class CryptoRoomEntity(
// even if a new state event with empty encryption, or state is reset somehow
var wasEncryptedOnce: Boolean? = false
) :
RealmObject() {
RealmModel {
companion object
}

View File

@@ -16,13 +16,16 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
internal fun DeviceInfoEntity.Companion.createPrimaryKey(userId: String, deviceId: String) = "$userId|$deviceId"
@RealmClass
internal open class DeviceInfoEntity(
@PrimaryKey var primaryKey: String = "",
var deviceId: String? = null,
@@ -40,7 +43,7 @@ internal open class DeviceInfoEntity(
* and new ones. Used for example to detect new unverified login
*/
var firstTimeSeenLocalTs: Long? = null
) : RealmObject() {
) : RealmModel {
@LinkingObjects("devices")
val users: RealmResults<UserEntity>? = null

View File

@@ -17,8 +17,11 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
@RealmClass
internal open class KeyInfoEntity(
var publicKeyBase64: String? = null,
// var isTrusted: Boolean = false,
@@ -29,7 +32,7 @@ internal open class KeyInfoEntity(
*/
var signatures: String? = null,
var trustLevelEntity: TrustLevelEntity? = null
) : RealmObject()
) : RealmModel
internal fun KeyInfoEntity.deleteOnCascade() {
trustLevelEntity?.deleteFromRealm()

View File

@@ -16,15 +16,17 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.internal.di.MoshiProvider
@RealmClass
internal open class KeyRequestReplyEntity(
var senderId: String? = null,
var fromDevice: String? = null,
var eventJson: String? = null
) : RealmObject() {
) : RealmModel {
companion object
fun getEvent(): Event? {

View File

@@ -16,9 +16,11 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class KeysBackupDataEntity(
// Primary key to update this object. There is only one object, so it's a constant, please do not set it
@PrimaryKey
@@ -27,4 +29,4 @@ internal open class KeysBackupDataEntity(
var backupLastServerHash: String? = null,
// The last known number of backed up keys on the server
var backupLastServerNumberOfKeys: Int? = null
) : RealmObject()
) : RealmModel

View File

@@ -16,9 +16,11 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class MyDeviceLastSeenInfoEntity(
/** The device id. */
@PrimaryKey var deviceId: String? = null,
@@ -28,7 +30,7 @@ internal open class MyDeviceLastSeenInfoEntity(
var lastSeenTs: Long? = null,
/** The last ip address. */
var lastSeenIp: String? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,8 +16,9 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
@@ -28,6 +29,7 @@ import timber.log.Timber
internal fun OlmInboundGroupSessionEntity.Companion.createPrimaryKey(sessionId: String?, senderKey: String?) = "$sessionId|$senderKey"
@RealmClass
internal open class OlmInboundGroupSessionEntity(
// Combined value to build a primary key
@PrimaryKey var primaryKey: String? = null,
@@ -54,7 +56,7 @@ internal open class OlmInboundGroupSessionEntity(
// Indicate if the key has been backed up to the homeserver
var backedUp: Boolean = false
) :
RealmObject() {
RealmModel {
fun store(wrapper: MXInboundMegolmSessionWrapper) {
this.serializedOlmInboundGroupSession = serializeForRealm(wrapper.session)

View File

@@ -16,8 +16,9 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.olm.OlmSession
@@ -25,6 +26,7 @@ import org.matrix.olm.OlmSession
internal fun OlmSessionEntity.Companion.createPrimaryKey(sessionId: String, deviceKey: String) = "$sessionId|$deviceKey"
// olmSessionData is a serialized OlmSession
@RealmClass
internal open class OlmSessionEntity(
@PrimaryKey var primaryKey: String = "",
var sessionId: String? = null,
@@ -32,7 +34,7 @@ internal open class OlmSessionEntity(
var olmSessionData: String? = null,
var lastReceivedMessageTs: Long = 0
) :
RealmObject() {
RealmModel {
fun getOlmSession(): OlmSession? {
return deserializeFromRealm(olmSessionData)

View File

@@ -16,17 +16,19 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.internal.crypto.store.db.deserializeFromRealm
import org.matrix.android.sdk.internal.crypto.store.db.serializeForRealm
import org.matrix.olm.OlmOutboundGroupSession
import timber.log.Timber
@RealmClass
internal open class OutboundGroupSessionInfoEntity(
var serializedOutboundSessionData: String? = null,
var creationTime: Long? = null,
var shouldShareHistory: Boolean = false
) : RealmObject() {
) : RealmModel {
fun getOutboundGroupSession(): OlmOutboundGroupSession? {
return try {

View File

@@ -19,8 +19,10 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Types
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
@@ -33,6 +35,7 @@ import org.matrix.android.sdk.api.session.events.model.content.RoomKeyWithHeldCo
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.internal.di.MoshiProvider
@RealmClass
internal open class OutgoingKeyRequestEntity(
@Index var requestId: String? = null,
var requestedIndex: Int? = null,
@@ -44,7 +47,7 @@ internal open class OutgoingKeyRequestEntity(
@Index var megolmSessionId: String? = null,
var replies: RealmList<KeyRequestReplyEntity> = RealmList()
) : RealmObject() {
) : RealmModel {
@Index private var requestStateStr: String = OutgoingRoomKeyRequestState.UNSENT.name

View File

@@ -16,14 +16,16 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
/**
* Keep a record of to whom (user/device) a given session should have been shared.
* It will be used to reply to keyshare requests from other users, in order to see if
* this session was originaly shared with a given user
*/
@RealmClass
internal open class SharedSessionEntity(
var roomId: String? = null,
var algorithm: String? = null,
@@ -32,7 +34,7 @@ internal open class SharedSessionEntity(
@Index var deviceId: String? = null,
@Index var deviceIdentityKey: String? = null,
var chainIndex: Int? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,12 +16,14 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class TrustLevelEntity(
var crossSignedVerified: Boolean? = null,
var locallyVerified: Boolean? = null
) : RealmObject() {
) : RealmModel {
companion object

View File

@@ -17,16 +17,19 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.internal.extensions.clearWith
@RealmClass
internal open class UserEntity(
@PrimaryKey var userId: String? = null,
var devices: RealmList<DeviceInfoEntity> = RealmList(),
var crossSigningInfoEntity: CrossSigningInfoEntity? = null,
var deviceTrackingStatus: Int = 0
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,8 +16,9 @@
package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
/**
@@ -27,6 +28,7 @@ import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
* For example, the sender may have blacklisted certain devices or users,
* or may be choosing to not send the megolm key to devices that they have not verified yet.
*/
@RealmClass
internal open class WithHeldSessionEntity(
var roomId: String? = null,
var algorithm: String? = null,
@@ -34,7 +36,7 @@ internal open class WithHeldSessionEntity(
@Index var senderKey: String? = null,
var codeString: String? = null,
var reason: String? = null
) : RealmObject() {
) : RealmModel {
var code: WithHeldCode?
get() {

View File

@@ -0,0 +1,43 @@
/*
* 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.database
import io.realm.kotlin.migration.AutomaticSchemaMigration
import timber.log.Timber
internal abstract class KotlinRealmMigrator(
private val migrationContext: AutomaticSchemaMigration.MigrationContext,
private val targetSchemaVersion: Int
) {
fun perform() {
Timber.d("Migrate ${migrationContext.oldRealm.configuration.name} to $targetSchemaVersion")
doMigrate(migrationContext)
}
protected abstract fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext)
}
val AutomaticSchemaMigration.MigrationContext.oldVersion: Long
get() {
return oldRealm.schemaVersion()
}
val AutomaticSchemaMigration.MigrationContext.newVersion: Long
get() {
return newRealm.schemaVersion()
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 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.database
import io.realm.kotlin.migration.AutomaticSchemaMigration
import timber.log.Timber
import kotlin.system.measureTimeMillis
abstract class MatrixAutomaticSchemaMigration(
private val dbName: String,
val schemaVersion: Long
) : AutomaticSchemaMigration {
final override fun migrate(migrationContext: AutomaticSchemaMigration.MigrationContext) {
val oldVersion = migrationContext.oldVersion
val newVersion = migrationContext.newVersion
Timber.d("Migrating Realm $dbName from $oldVersion to $newVersion")
val duration = measureTimeMillis {
doMigrate(oldVersion, migrationContext)
}
Timber.d("Migrating Realm $dbName from $oldVersion to $newVersion took $duration ms.")
}
abstract fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext)
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 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.database
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmSingleQuery
import io.realm.kotlin.types.RealmObject
import kotlinx.coroutines.flow.first
internal suspend fun <T : RealmObject> RealmSingleQuery<T>.await(): T? {
return asFlow().first().obj
}
internal suspend fun <T : RealmObject> RealmQuery<T>.await(): List<T> {
return asFlow().first().list
}

View File

@@ -0,0 +1,138 @@
package org.matrix.android.sdk.internal.database
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.notifications.ResultsChange
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.types.RealmObject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.database.pagedlist.RealmTiledDataSource
internal typealias RealmQueryBuilder<T> = (Realm) -> RealmQuery<T>
/**
* This class is responsible for managing an instance of realm.
* You should make sure to keep this class as a singleton.
* You can force opening the realm by calling [open] method.
* Otherwise it will be lazily opened when first querying/writing.
* Makes sure to call [close] when you don't need the instance anymore.
*/
internal class RealmInstance(
val coroutineScope: CoroutineScope,
private val realmConfiguration: RealmConfiguration,
coroutineDispatcher: CoroutineDispatcher
) {
private val realm =
coroutineScope.async(context = coroutineDispatcher, start = CoroutineStart.LAZY) {
Realm.open(realmConfiguration)
}
suspend fun open() {
coroutineScope.launch {
realm.await()
}.join()
}
suspend fun close() = withContext(NonCancellable) {
realm.await().close()
}
fun <T : RealmObject> queryResults(
realmQueryBuilder: RealmQueryBuilder<T>
): Flow<ResultsChange<T>> {
return getRealmFlow().flatMapConcat {
realmQueryBuilder(it).asFlow()
}
}
fun <T : RealmObject> queryList(
realmQueryBuilder: RealmQueryBuilder<T>
): Flow<List<T>> {
return queryResults(realmQueryBuilder).map {
it.list
}
}
fun <T : RealmObject> queryFirst(
realmQueryBuilder: RealmQueryBuilder<T>
): Flow<Optional<T>> {
return getRealmFlow().flatMapConcat {
realmQueryBuilder(it).first().asFlow()
}.map {
Optional.from(it.obj)
}
}
fun <T : RealmObject> queryPagedList(
config: PagedList.Config,
queryBuilder: RealmQueryBuilder<T>
): Flow<PagedList<T>> {
fun <T> LiveData<T>.asFlow(): Flow<T> = callbackFlow {
val observer = Observer<T> { value -> trySend(value) }
observeForever(observer)
awaitClose {
removeObserver(observer)
}
}.flowOn(Dispatchers.Main.immediate)
return getRealmFlow().flatMapConcat { realm ->
val livePagedList = LivePagedListBuilder(
RealmTiledDataSource.Factory(
realm = realm,
queryBuilder = queryBuilder,
coroutineScope = coroutineScope
),
config
).build()
livePagedList.asFlow()
}
}
suspend fun <R> write(block: MutableRealm.() -> R): R {
return getRealm().write(block)
}
fun <R> blockingWrite(block: MutableRealm.() -> R): R {
return runBlocking {
write(block)
}
}
suspend fun getRealm(): Realm = realm.await()
fun getRealmFlow(): Flow<Realm> = flow {
emit(getRealm())
}
fun getBlockingRealm(): Realm {
return runBlocking {
getRealm()
}
}
}

View File

@@ -95,6 +95,12 @@ internal class RealmKeysUtils @Inject constructor(
realmConfigurationBuilder.encryptionKey(key)
}
fun configureEncryption(realmConfigurationBuilder: io.realm.kotlin.RealmConfiguration.Builder, alias: String) {
val key = getRealmEncryptionKey(alias)
realmConfigurationBuilder.encryptionKey(key)
}
// Expose to handle Realm migration to riotX
fun getRealmEncryptionKey(alias: String): ByteArray {
val key = if (hasKeyForDatabase(alias)) {

View File

@@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmChangeListener
import io.realm.RealmConfiguration
import io.realm.RealmModel
import io.realm.RealmObject
import io.realm.RealmResults
import kotlinx.coroutines.CoroutineScope
@@ -34,7 +35,7 @@ import java.util.concurrent.atomic.AtomicReference
internal interface LiveEntityObserver : SessionLifecycleObserver
internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val realmConfiguration: RealmConfiguration) :
internal abstract class RealmLiveEntityObserver<T : RealmModel>(protected val realmConfiguration: RealmConfiguration) :
LiveEntityObserver, RealmChangeListener<RealmResults<T>> {
private companion object {

View File

@@ -17,6 +17,7 @@
package org.matrix.android.sdk.internal.database.helper
import io.realm.Realm
import io.realm.RealmObject
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
@@ -38,6 +39,7 @@ 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

View File

@@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.helper
import com.squareup.moshi.JsonDataException
import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmQuery
import io.realm.Sort
import org.matrix.android.sdk.api.session.events.model.UnsignedData
@@ -37,6 +38,7 @@ import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.database.query.whereRoomId
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.extensions.realm
import timber.log.Timber
private typealias Summary = Pair<Int, TimelineEventEntity>?

View File

@@ -44,6 +44,7 @@ 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

View File

@@ -18,12 +18,14 @@ package org.matrix.android.sdk.internal.database.mapper
import io.realm.Realm
import io.realm.RealmList
import io.realm.kotlin.isManaged
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.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 javax.inject.Inject
internal class ReadReceiptsSummaryMapper @Inject constructor(
@@ -36,7 +38,7 @@ internal class ReadReceiptsSummaryMapper @Inject constructor(
}
val readReceipts = readReceiptsSummaryEntity.readReceipts
// Avoid opening a new realm if we already have one opened
return if (readReceiptsSummaryEntity.isManaged) {
return if (readReceiptsSummaryEntity.isManaged()) {
map(readReceipts, readReceiptsSummaryEntity.realm)
} else {
realmSessionProvider.withRealm { realm ->

View File

@@ -17,11 +17,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class BreadcrumbsEntity(
var recentRoomIds: RealmList<String> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -17,13 +17,16 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.Index
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.internal.extensions.assertIsManaged
import org.matrix.android.sdk.internal.extensions.clearWith
@RealmClass
internal open class ChunkEntity(
@Index var prevToken: String? = null,
// Because of gaps we can have several chunks with nextToken == null
@@ -38,7 +41,7 @@ internal open class ChunkEntity(
// Threads
@Index var rootThreadEventId: String? = null,
@Index var isLastForwardThread: Boolean = false,
) : RealmObject() {
) : RealmModel {
fun identifier() = "${prevToken}_$nextToken"

View File

@@ -17,15 +17,17 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
@RealmClass
internal open class CurrentStateEventEntity(
var eventId: String = "",
var root: EventEntity? = null,
@Index var roomId: String = "",
@Index var type: String = "",
@Index var stateKey: String = ""
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,13 +16,15 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class DraftEntity(
var content: String = "",
var draftMode: String = MODE_REGULAR,
var linkedEventId: String = ""
) : RealmObject() {
) : RealmModel {
companion object {
const val MODE_REGULAR = "REGULAR"

View File

@@ -16,16 +16,17 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* Keep all the editions of a message.
*/
@RealmClass
internal open class EditAggregatedSummaryEntity(
// The list of the editions used to build the summary (might be out of sync if chunked received from message chunk)
var editions: RealmList<EditionOfEvent> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object
}
@@ -37,4 +38,4 @@ internal open class EditionOfEvent(
var content: String? = null,
var timestamp: Long = 0,
var isLocalEcho: Boolean = false
) : RealmObject()
) : RealmModel

View File

@@ -16,11 +16,14 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import timber.log.Timber
@RealmClass
internal open class EventAnnotationsSummaryEntity(
@PrimaryKey
var eventId: String = "",
@@ -30,7 +33,7 @@ internal open class EventAnnotationsSummaryEntity(
var referencesSummaryEntity: ReferencesAggregatedSummaryEntity? = null,
var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null,
var liveLocationShareAggregatedSummary: LiveLocationShareAggregatedSummaryEntity? = null,
) : RealmObject() {
) : RealmModel {
/**
* Cleanup undesired editions, done by users different from the originalEventSender.

View File

@@ -16,8 +16,10 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmModel
import io.realm.RealmObject
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
import org.matrix.android.sdk.api.session.room.send.SendState
@@ -25,6 +27,7 @@ import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.extensions.assertIsManaged
@RealmClass
internal open class EventEntity(
@Index var eventId: String = "",
@Index var roomId: String = "",
@@ -48,7 +51,7 @@ internal open class EventEntity(
// Number messages within the thread
var numberOfThreads: Int = 0,
var threadSummaryLatestMessage: TimelineEventEntity? = null
) : RealmObject() {
) : RealmModel {
private var sendStateStr: String = SendState.UNKNOWN.name
@@ -95,7 +98,7 @@ internal open class EventEntity(
decryptionErrorReason = null
// If we have an EventInsertEntity for the eventId we make sures it can be processed now.
realm.where(EventInsertEntity::class.java)
RealmObject.getRealm(this).where(EventInsertEntity::class.java)
.equalTo(EventInsertEntityFields.EVENT_ID, eventId)
.findFirst()
?.canBeProcessed = true

View File

@@ -16,12 +16,14 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* This class is used to get notification on new events being inserted. It's to avoid realm getting slow when listening to insert
* in EventEntity table.
*/
@RealmClass
internal open class EventInsertEntity(
var eventId: String = "",
var eventType: String = "",
@@ -30,7 +32,7 @@ internal open class EventInsertEntity(
* Currently it's set to false when the event content is encrypted.
*/
var canBeProcessed: Boolean = true
) : RealmObject() {
) : RealmModel {
private var insertTypeStr: String = EventInsertType.INCREMENTAL_SYNC.name
var insertType: EventInsertType

View File

@@ -16,12 +16,14 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* Contain a map between Json filter string and filterId (from Homeserver).
* Currently there is only one object in this table.
*/
@RealmClass
internal open class FilterEntity(
// The serialized FilterBody
var filterBodyJson: String = "",
@@ -30,7 +32,7 @@ internal open class FilterEntity(
// the id server side of the filterBodyJson, can be used instead of filterBodyJson if not blank
var filterId: String = ""
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,9 +16,11 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
@RealmClass
internal open class HomeServerCapabilitiesEntity(
var canChangePassword: Boolean = true,
var canChangeDisplayName: Boolean = true,
@@ -31,7 +33,7 @@ internal open class HomeServerCapabilitiesEntity(
var lastUpdatedTimestamp: Long = 0L,
var canUseThreading: Boolean = false,
var canControlLogoutDevices: Boolean = false
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,9 +16,11 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
internal open class IgnoredUserEntity(var userId: String = "") : RealmObject() {
@RealmClass
internal open class IgnoredUserEntity(var userId: String = "") : RealmModel {
companion object
}

View File

@@ -16,11 +16,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* This class is used to store pending threePid data, when user wants to add a threePid to his account.
*/
@RealmClass
internal open class PendingThreePidEntity(
var email: String? = null,
var msisdn: String? = null,
@@ -28,4 +30,4 @@ internal open class PendingThreePidEntity(
var sendAttempt: Int = 0,
var sid: String = "",
var submitUrl: String? = null
) : RealmObject()
) : RealmModel

View File

@@ -16,11 +16,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* Keep the latest state of a poll.
*/
@RealmClass
internal open class PollResponseAggregatedSummaryEntity(
// For now we persist this a JSON for greater flexibility
// #see PollSummaryContent
@@ -34,7 +36,7 @@ internal open class PollResponseAggregatedSummaryEntity(
// The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk)
var sourceEvents: RealmList<String> = RealmList(),
var sourceLocalEchoEvents: RealmList<String> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,9 +16,11 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class PreviewUrlCacheEntity(
@PrimaryKey
var url: String = "",
@@ -31,7 +33,7 @@ internal open class PreviewUrlCacheEntity(
var imageWidth: Int? = null,
var imageHeight: Int? = null,
var lastUpdatedTimestamp: Long = 0L
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -15,14 +15,16 @@
*/
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class PushConditionEntity(
var kind: String = "",
var key: String? = null,
var pattern: String? = null,
var iz: String? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,10 +16,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
@RealmClass
internal open class PushRuleEntity(
// Required. The actions to perform when this rule is matched.
var actionsStr: String? = null,
@@ -33,7 +36,7 @@ internal open class PushRuleEntity(
var conditions: RealmList<PushConditionEntity>? = RealmList(),
// The glob-style pattern to match against. Only applicable to content rules.
var pattern: String? = null
) : RealmObject() {
) : RealmModel {
@LinkingObjects("pushRules")
val parent: RealmResults<PushRulesEntity>? = null

View File

@@ -16,14 +16,17 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.session.pushrules.RuleKind
import org.matrix.android.sdk.internal.extensions.clearWith
@RealmClass
internal open class PushRulesEntity(
var scope: String = "",
var pushRules: RealmList<PushRuleEntity> = RealmList()
) : RealmObject() {
) : RealmModel {
private var kindStr: String = RuleKind.CONTENT.name
var kind: RuleKind

View File

@@ -15,11 +15,13 @@
*/
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class PusherDataEntity(
var url: String? = null,
var format: String? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -15,7 +15,9 @@
*/
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.session.pushers.PusherState
// TODO
@@ -27,6 +29,7 @@ import org.matrix.android.sdk.api.session.pushers.PusherState
// at org.matrix.android.sdk.internal.database.model.PusherEntity.setData(PusherEntity.kt:16)
// at org.matrix.android.sdk.internal.session.pushers.AddHttpPusherWorker$doWork$$inlined$fold$lambda$2.execute(AddHttpPusherWorker.kt:70)
// at io.realm.Realm.executeTransaction(Realm.java:1493)
@RealmClass
internal open class PusherEntity(
var pushKey: String = "",
var kind: String? = null,
@@ -36,7 +39,7 @@ internal open class PusherEntity(
var profileTag: String? = null,
var lang: String? = null,
var data: PusherDataEntity? = null
) : RealmObject() {
) : RealmModel {
private var stateStr: String = PusherState.UNREGISTERED.name
var state: PusherState

View File

@@ -17,11 +17,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* Aggregated Summary of a reaction.
*/
@RealmClass
internal open class ReactionAggregatedSummaryEntity(
// The reaction String 😀
var key: String = "",
@@ -35,7 +37,7 @@ internal open class ReactionAggregatedSummaryEntity(
var sourceEvents: RealmList<String> = RealmList(),
// List of transaction ids for local echos
var sourceLocalEcho: RealmList<String> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,14 +16,16 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class ReadMarkerEntity(
@PrimaryKey
var roomId: String = "",
var eventId: String = ""
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,18 +16,20 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class ReadReceiptEntity(
@PrimaryKey var primaryKey: String = "",
var eventId: String = "",
var roomId: String = "",
var userId: String = "",
var originServerTs: Double = 0.0
) : RealmObject() {
) : RealmModel {
companion object
@LinkingObjects("readReceipts")

View File

@@ -17,17 +17,20 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
@RealmClass
internal open class ReadReceiptsSummaryEntity(
@PrimaryKey
var eventId: String = "",
var roomId: String = "",
var readReceipts: RealmList<ReadReceiptEntity> = RealmList()
) : RealmObject() {
) : RealmModel {
@LinkingObjects("readReceipts")
val timelineEvent: RealmResults<TimelineEventEntity>? = null

View File

@@ -16,8 +16,10 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class ReferencesAggregatedSummaryEntity(
var eventId: String = "",
var content: String? = null,
@@ -25,7 +27,7 @@ internal open class ReferencesAggregatedSummaryEntity(
var sourceEvents: RealmList<String> = RealmList(),
// List of transaction ids for local echos
var sourceLocalEcho: RealmList<String> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,7 +16,7 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
@@ -24,4 +24,4 @@ import io.realm.annotations.RealmClass
internal open class RoomAccountDataEntity(
@Index var type: String? = null,
var contentStr: String? = null
) : RealmObject()
) : RealmModel

View File

@@ -17,20 +17,23 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
import org.matrix.android.sdk.internal.database.query.findRootOrLatest
import org.matrix.android.sdk.internal.extensions.assertIsManaged
@RealmClass
internal open class RoomEntity(
@PrimaryKey var roomId: String = "",
var chunks: RealmList<ChunkEntity> = RealmList(),
var sendingTimelineEvents: RealmList<TimelineEventEntity> = RealmList(),
var threadSummaries: RealmList<ThreadSummaryEntity> = RealmList(),
var accountData: RealmList<RoomAccountDataEntity> = RealmList()
) : RealmObject() {
) : RealmModel {
private var membershipStr: String = Membership.NONE.name
var membership: Membership

View File

@@ -16,13 +16,15 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
@RealmClass
internal open class RoomMemberSummaryEntity(
@PrimaryKey var primaryKey: String = "",
@Index var userId: String = "",
@@ -31,7 +33,7 @@ internal open class RoomMemberSummaryEntity(
var avatarUrl: String? = null,
var reason: String? = null,
var isDirect: Boolean = false
) : RealmObject() {
) : RealmModel {
private var membershipStr: String = Membership.NONE.name
var membership: Membership

View File

@@ -17,9 +17,11 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.room.model.Membership
@@ -30,13 +32,14 @@ import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntity
import org.matrix.android.sdk.internal.session.room.membership.RoomName
@RealmClass
internal open class RoomSummaryEntity(
@PrimaryKey var roomId: String = "",
var roomType: String? = null,
var parents: RealmList<SpaceParentSummaryEntity> = RealmList(),
var children: RealmList<SpaceChildSummaryEntity> = RealmList(),
var directParentNames: RealmList<String> = RealmList(),
) : RealmObject() {
) : RealmModel {
private var displayName: String? = ""

View File

@@ -16,12 +16,14 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class RoomTagEntity(
var tagName: String = "",
var tagOrder: Double? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,13 +16,15 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class ScalarTokenEntity(
@PrimaryKey var serverUrl: String = "",
var token: String = ""
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -17,11 +17,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* Decorates room summary with space related information.
*/
@RealmClass
internal open class SpaceChildSummaryEntity(
// var isSpace: Boolean = false,
@@ -40,7 +42,7 @@ internal open class SpaceChildSummaryEntity(
// var level: Int = 0
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -17,11 +17,13 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
/**
* Decorates room summary with space related information.
*/
@RealmClass
internal open class SpaceParentSummaryEntity(
/**
* Determines whether this is the main parent for the space
@@ -39,7 +41,7 @@ internal open class SpaceParentSummaryEntity(
var viaServers: RealmList<String> = RealmList()
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,10 +16,12 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class SyncEntity(
var nextBatch: String? = null,
@PrimaryKey var id: Long = 0
) : RealmObject()
) : RealmModel

View File

@@ -16,12 +16,15 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.Index
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
import io.realm.kotlin.deleteFromRealm
import org.matrix.android.sdk.internal.extensions.assertIsManaged
@RealmClass
internal open class TimelineEventEntity(
var localId: Long = 0,
@Index var eventId: String = "",
@@ -37,7 +40,7 @@ internal open class TimelineEventEntity(
// to a thread chunk and is a temporarily event.
var ownedByThreadChunk: Boolean = false,
var readReceipts: ReadReceiptsSummaryEntity? = null
) : RealmObject() {
) : RealmModel {
@LinkingObjects("timelineEvents")
val chunk: RealmResults<ChunkEntity>? = null

View File

@@ -16,8 +16,9 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.Index
import io.realm.annotations.RealmClass
/**
* Clients can store custom config data for their account on their homeserver.
@@ -25,10 +26,11 @@ import io.realm.annotations.Index
* Users may only view the account data for their own account.
* The account_data may be either global or scoped to a particular rooms.
*/
@RealmClass
internal open class UserAccountDataEntity(
@Index var type: String? = null,
var contentStr: String? = null
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -17,16 +17,18 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
/**
* Create a specific table to be able to do direct query on it and keep the draft ordered.
*/
@RealmClass
internal open class UserDraftsEntity(
var userDrafts: RealmList<DraftEntity> = RealmList()
) : RealmObject() {
) : RealmModel {
// Link to RoomSummaryEntity
@LinkingObjects("userDrafts")

View File

@@ -16,14 +16,16 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class UserEntity(
@PrimaryKey var userId: String = "",
var displayName: String = "",
var avatarUrl: String = ""
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -15,11 +15,13 @@
*/
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.RealmClass
@RealmClass
internal open class UserThreePidEntity(
var medium: String = "",
var address: String = "",
var validatedAt: Long = 0,
var addedAt: Long = 0
) : RealmObject()
) : RealmModel

View File

@@ -16,14 +16,16 @@
package org.matrix.android.sdk.internal.database.model
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
@RealmClass
internal open class WellknownIntegrationManagerConfigEntity(
@PrimaryKey var id: Long = 0,
var apiUrl: String = "",
var uiUrl: String = ""
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -17,12 +17,14 @@
package org.matrix.android.sdk.internal.database.model.livelocation
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
/**
* Aggregation info concerning a live location share.
*/
@RealmClass
internal open class LiveLocationShareAggregatedSummaryEntity(
/**
* Event id of the event that started the live.
@@ -53,6 +55,6 @@ internal open class LiveLocationShareAggregatedSummaryEntity(
* @see [org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent]
*/
var lastLocationContent: String? = null,
) : RealmObject() {
) : RealmModel {
companion object
}

View File

@@ -16,11 +16,13 @@
package org.matrix.android.sdk.internal.database.model.presence
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
import org.matrix.android.sdk.api.session.presence.model.UserPresence
@RealmClass
internal open class UserPresenceEntity(
@PrimaryKey var userId: String = "",
var lastActiveAgo: Long? = null,
@@ -28,7 +30,7 @@ internal open class UserPresenceEntity(
var isCurrentlyActive: Boolean? = null,
var avatarUrl: String? = null,
var displayName: String? = null
) : RealmObject() {
) : RealmModel {
var presence: PresenceEnum
get() {

View File

@@ -16,13 +16,15 @@
package org.matrix.android.sdk.internal.database.model.threads
import io.realm.RealmObject
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.annotations.Index
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
@RealmClass
internal open class ThreadSummaryEntity(
@Index var rootThreadEventId: String? = "",
var rootThreadEventEntity: EventEntity? = null,
@@ -35,7 +37,7 @@ internal open class ThreadSummaryEntity(
var isUserParticipating: Boolean = false,
var latestThreadIsUniqueDisplayName: Boolean = false,
var numberOfThreads: Int = 0
) : RealmObject() {
) : RealmModel {
@LinkingObjects("threadSummaries")
val room: RealmResults<RoomEntity>? = null

View File

@@ -0,0 +1,67 @@
package org.matrix.android.sdk.internal.database.pagedlist
import androidx.paging.DataSource
import io.realm.kotlin.Realm
import io.realm.kotlin.notifications.UpdatedResults
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.types.RealmObject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
internal class RealmTiledDataSource<T : RealmObject> internal constructor(
realm: Realm,
queryBuilder: (Realm) -> RealmQuery<T>,
coroutineScope: CoroutineScope
) :
TiledDataSource<T>() {
class Factory<T : RealmObject>(
private val realm: Realm,
private val queryBuilder: (Realm) -> RealmQuery<T>,
private val coroutineScope: CoroutineScope,
) : DataSource.Factory<Int, T>() {
override fun create(): DataSource<Int, T> {
val childScope = CoroutineScope(SupervisorJob() + coroutineScope.coroutineContext)
return RealmTiledDataSource(realm, queryBuilder, childScope)
}
}
private val results: RealmResults<T>
init {
addInvalidatedCallback {
coroutineScope.coroutineContext.cancelChildren()
}
results = queryBuilder(realm).find()
results.asFlow()
.onEach { resultsChange ->
when (resultsChange) {
is UpdatedResults -> invalidate()
else -> Unit
}
}
.launchIn(coroutineScope)
}
override fun countItems(): Int {
return results.size
}
override fun loadRange(startPosition: Int, count: Int): List<T> {
val size = countItems()
if (size == 0) return emptyList()
return buildList {
val endPosition = minOf(startPosition + count, size)
for (position in startPosition until endPosition) {
results.getOrNull(position)?.also { item ->
add(item)
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
package org.matrix.android.sdk.internal.database.pagedlist
import android.annotation.SuppressLint
import androidx.paging.PositionalDataSource
@Suppress("DEPRECATION")
public abstract class TiledDataSource<T : Any> : PositionalDataSource<T>() {
public abstract fun countItems(): Int
public abstract fun loadRange(startPosition: Int, count: Int): List<T>?
@SuppressLint("RestrictedApi") // For computeInitialLoadPosition, computeInitialLoadSize
override fun loadInitial(
params: LoadInitialParams,
callback: LoadInitialCallback<T>
) {
val totalCount = countItems()
if (totalCount == 0) {
callback.onResult(emptyList(), 0, 0)
return
}
val firstLoadPosition = computeInitialLoadPosition(params, totalCount)
val firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount)
val list = loadRange(firstLoadPosition, firstLoadSize)
if (list != null && list.size == firstLoadSize) {
callback.onResult(list, firstLoadPosition, totalCount)
} else {
invalidate()
}
}
override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<T>) {
val list = loadRange(params.startPosition, params.loadSize)
if (list != null) {
callback.onResult(list)
} else {
invalidate()
}
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2020 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.database.query
import io.realm.Realm
import io.realm.kotlin.createObject
import io.realm.kotlin.where
import org.matrix.android.sdk.internal.database.model.RawCacheEntity
import org.matrix.android.sdk.internal.database.model.RawCacheEntityFields
/**
* Get the current RawCacheEntity, return null if it does not exist.
*/
internal fun RawCacheEntity.Companion.get(realm: Realm, url: String): RawCacheEntity? {
return realm.where<RawCacheEntity>()
.equalTo(RawCacheEntityFields.URL, url)
.findFirst()
}
/**
* Get the current RawCacheEntity, create one if it does not exist.
*/
internal fun RawCacheEntity.Companion.getOrCreate(realm: Realm, url: String): RawCacheEntity {
return get(realm, url) ?: realm.createObject(url)
}

View File

@@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
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.RoomEntityFields
import org.matrix.android.sdk.internal.extensions.realm
internal fun RoomEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<RoomEntity> {
return realm.where<RoomEntity>()

View File

@@ -25,20 +25,20 @@ import org.matrix.android.sdk.internal.di.GlobalDatabase
import javax.inject.Inject
internal class DefaultDebugService @Inject constructor(
@AuthDatabase private val realmConfigurationAuth: RealmConfiguration,
@GlobalDatabase private val realmConfigurationGlobal: RealmConfiguration,
//@AuthDatabase private val realmConfigurationAuth: RealmConfiguration,
//@GlobalDatabase private val realmConfigurationGlobal: RealmConfiguration,
private val sessionManager: SessionManager,
) : DebugService {
override fun getAllRealmConfigurations(): List<RealmConfiguration> {
return sessionManager.getLastSession()?.getRealmConfigurations().orEmpty() +
realmConfigurationAuth +
realmConfigurationGlobal
return sessionManager.getLastSession()?.getRealmConfigurations().orEmpty()
//realmConfigurationAuth +
//realmConfigurationGlobal
}
override fun logDbUsageInfo() {
RealmDebugTools(realmConfigurationAuth).logInfo("Auth")
RealmDebugTools(realmConfigurationGlobal).logInfo("Global")
//RealmDebugTools(realmConfigurationAuth).logInfo("Auth")
//RealmDebugTools(realmConfigurationGlobal).logInfo("Global")
sessionManager.getLastSession()?.logDbUsageInfo()
}
}

View File

@@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.model
package org.matrix.android.sdk.internal.di
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import javax.inject.Qualifier
internal open class KnownServerUrlEntity(
@PrimaryKey
var url: String = ""
) : RealmObject() {
companion object
}
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class MatrixCoroutineScope
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class SessionCoroutineScope

Some files were not shown because too many files have changed in this diff Show More