Remove some use of sync write in realm

This commit is contained in:
ganfra 2019-11-06 18:47:11 +01:00
parent fb3e953e28
commit 93ef3edab3
12 changed files with 130 additions and 154 deletions

View file

@ -67,5 +67,5 @@ interface Authenticator {
/**
* Create a session after a SSO successful login
*/
fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session
fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<Session>): Cancelable
}

View file

@ -112,10 +112,24 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
sessionManager.getOrCreateSession(sessionParams)
}
override fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
override fun createSessionFromSso(credentials: Credentials,
homeServerConnectionConfig: HomeServerConnectionConfig,
callback: MatrixCallback<Session>): Cancelable {
val job = GlobalScope.launch(coroutineDispatchers.main) {
val sessionOrFailure = runCatching {
createSessionFromSso(credentials, homeServerConnectionConfig)
}
sessionOrFailure.foldToCallback(callback)
}
return CancelableCoroutine(job)
}
private suspend fun createSessionFromSso(credentials: Credentials,
homeServerConnectionConfig: HomeServerConnectionConfig): Session = withContext(coroutineDispatchers.computation) {
val sessionParams = SessionParams(credentials, homeServerConnectionConfig)
sessionParamsStore.save(sessionParams)
return sessionManager.getOrCreateSession(sessionParams)
sessionManager.getOrCreateSession(sessionParams)
}
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {

View file

@ -27,9 +27,9 @@ internal interface SessionParamsStore {
fun getAll(): List<SessionParams>
fun save(sessionParams: SessionParams): Try<Unit>
suspend fun save(sessionParams: SessionParams)
fun delete(userId: String): Try<Unit>
suspend fun delete(userId: String)
fun deleteAll(): Try<Unit>
suspend fun deleteAll()
}

View file

@ -16,9 +16,9 @@
package im.vector.matrix.android.internal.auth.db
import arrow.core.Try
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.di.AuthDatabase
import io.realm.Realm
import io.realm.RealmConfiguration
@ -62,41 +62,29 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
return sessionParams
}
override fun save(sessionParams: SessionParams): Try<Unit> {
return Try {
override suspend fun save(sessionParams: SessionParams) {
awaitTransaction(realmConfiguration) {
val entity = mapper.map(sessionParams)
if (entity != null) {
val realm = Realm.getInstance(realmConfiguration)
realm.executeTransaction {
it.insert(entity)
}
realm.close()
it.insert(entity)
}
}
}
override fun delete(userId: String): Try<Unit> {
return Try {
val realm = Realm.getInstance(realmConfiguration)
realm.executeTransaction {
it.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.USER_ID, userId)
.findAll()
.deleteAllFromRealm()
}
realm.close()
override suspend fun delete(userId: String) {
awaitTransaction(realmConfiguration) {
it.where(SessionParamsEntity::class.java)
.equalTo(SessionParamsEntityFields.USER_ID, userId)
.findAll()
.deleteAllFromRealm()
}
}
override fun deleteAll(): Try<Unit> {
return Try {
val realm = Realm.getInstance(realmConfiguration)
realm.executeTransaction {
it.where(SessionParamsEntity::class.java)
.findAll()
.deleteAllFromRealm()
}
realm.close()
override suspend fun deleteAll() {
awaitTransaction(realmConfiguration) {
it.where(SessionParamsEntity::class.java)
.findAll()
.deleteAllFromRealm()
}
}
}

View file

@ -16,6 +16,7 @@
package im.vector.matrix.android.internal.database.query
import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.database.model.FilterEntity
import im.vector.matrix.android.internal.session.filter.FilterFactory
import io.realm.Realm
@ -25,18 +26,17 @@ import io.realm.kotlin.where
/**
* Get the current filter, create one if it does not exist
*/
internal fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
internal suspend fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
var filter = realm.where<FilterEntity>().findFirst()
if (filter == null) {
realm.executeTransaction {
realm.createObject<FilterEntity>().apply {
filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
filterId = ""
}
filter = FilterEntity().apply {
filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
filterId = ""
}
awaitTransaction(realm.configuration) {
it.insert(filter)
}
filter = realm.where<FilterEntity>().findFirst()!!
}
return filter
}

View file

@ -36,7 +36,7 @@ internal object MatrixModule {
@MatrixScope
fun providesMatrixCoroutineDispatchers(): MatrixCoroutineDispatchers {
return MatrixCoroutineDispatchers(io = Dispatchers.IO,
computation = Dispatchers.IO,
computation = Dispatchers.Default,
main = Dispatchers.Main,
crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(),
sync = Executors.newSingleThreadExecutor().asCoroutineDispatcher()

View file

@ -16,54 +16,46 @@
package im.vector.matrix.android.internal.session.filter
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.FilterEntity
import im.vector.matrix.android.internal.database.model.FilterEntityFields
import im.vector.matrix.android.internal.database.query.getFilter
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.where
import javax.inject.Inject
internal class DefaultFilterRepository @Inject constructor(
@SessionDatabase private val realmConfiguration: RealmConfiguration
) : FilterRepository {
internal class DefaultFilterRepository @Inject constructor(private val monarchy: Monarchy) : FilterRepository {
override fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
val result: Boolean
override suspend fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
val filter = FilterEntity.getFilter(realm)
val result = if (filter.filterBodyJson != filterBody.toJSONString()) {
// Filter has changed, store it and reset the filter Id
monarchy.awaitTransaction {
// We manage only one filter for now
val filterBodyJson = filterBody.toJSONString()
val roomEventFilterJson = roomEventFilter.toJSONString()
val realm = Realm.getInstance(realmConfiguration)
val filterEntity = FilterEntity.getFilter(it)
val filter = FilterEntity.getFilter(realm)
if (filter.filterBodyJson != filterBody.toJSONString()) {
// Filter has changed, store it and reset the filter Id
realm.executeTransaction {
// We manage only one filter for now
val filterBodyJson = filterBody.toJSONString()
val roomEventFilterJson = roomEventFilter.toJSONString()
val filterEntity = FilterEntity.getFilter(it)
filterEntity.filterBodyJson = filterBodyJson
filterEntity.roomEventFilterJson = roomEventFilterJson
// Reset filterId
filterEntity.filterId = ""
filterEntity.filterBodyJson = filterBodyJson
filterEntity.roomEventFilterJson = roomEventFilterJson
// Reset filterId
filterEntity.filterId = ""
}
true
} else {
filter.filterId.isBlank()
}
result = true
} else {
result = filter.filterId.isBlank()
result
}
realm.close()
return result
}
override fun storeFilterId(filterBody: FilterBody, filterId: String) {
val realm = Realm.getInstance(realmConfiguration)
realm.executeTransaction {
override suspend fun storeFilterId(filterBody: FilterBody, filterId: String) {
monarchy.awaitTransaction {
// We manage only one filter for now
val filterBodyJson = filterBody.toJSONString()
@ -73,39 +65,24 @@ internal class DefaultFilterRepository @Inject constructor(
?.findFirst()
?.filterId = filterId
}
realm.close()
}
override fun getFilter(): String {
val result: String
val realm = Realm.getInstance(realmConfiguration)
val filter = FilterEntity.getFilter(realm)
result = if (filter.filterId.isBlank()) {
// Use the Json format
filter.filterBodyJson
} else {
// Use FilterId
filter.filterId
override suspend fun getFilter(): String {
return Realm.getInstance(monarchy.realmConfiguration).use {
val filter = FilterEntity.getFilter(it)
if (filter.filterId.isBlank()) {
// Use the Json format
filter.filterBodyJson
} else {
// Use FilterId
filter.filterId
}
}
realm.close()
return result
}
override fun getRoomFilter(): String {
val realm = Realm.getInstance(realmConfiguration)
val filter = FilterEntity.getFilter(realm)
val result = filter.roomEventFilterJson
realm.close()
return result
override suspend fun getRoomFilter(): String {
return Realm.getInstance(monarchy.realmConfiguration).use {
FilterEntity.getFilter(it).roomEventFilterJson
}
}
}

View file

@ -21,36 +21,13 @@ import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import javax.inject.Inject
internal class DefaultFilterService @Inject constructor(private val filterRepository: FilterRepository,
private val saveFilterTask: SaveFilterTask,
internal class DefaultFilterService @Inject constructor(private val saveFilterTask: SaveFilterTask,
private val taskExecutor: TaskExecutor) : FilterService {
// TODO Pass a list of support events instead
override fun setFilter(filterPreset: FilterService.FilterPreset) {
val filterBody = when (filterPreset) {
FilterService.FilterPreset.RiotFilter -> {
FilterFactory.createRiotFilterBody()
}
FilterService.FilterPreset.NoFilter -> {
FilterFactory.createDefaultFilterBody()
}
}
val roomFilter = when (filterPreset) {
FilterService.FilterPreset.RiotFilter -> {
FilterFactory.createRiotRoomFilter()
}
FilterService.FilterPreset.NoFilter -> {
FilterFactory.createDefaultRoomFilter()
}
}
val updated = filterRepository.storeFilter(filterBody, roomFilter)
if (updated) {
saveFilterTask
.configureWith(SaveFilterTask.Params(filterBody))
.executeBy(taskExecutor)
}
saveFilterTask
.configureWith(SaveFilterTask.Params(filterPreset))
.executeBy(taskExecutor)
}
}

View file

@ -16,18 +16,19 @@
package im.vector.matrix.android.internal.session.filter
import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import javax.inject.Inject
/**
* Save a filter to the server
* Save a filter, in db and if any changes, upload to the server
*/
internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
data class Params(
val filter: FilterBody
val filterPreset: FilterService.FilterPreset
)
}
@ -37,10 +38,29 @@ internal class DefaultSaveFilterTask @Inject constructor(@UserId private val use
) : SaveFilterTask {
override suspend fun execute(params: SaveFilterTask.Params) {
val filterResponse = executeRequest<FilterResponse> {
// TODO auto retry
apiCall = filterAPI.uploadFilter(userId, params.filter)
val filterBody = when (params.filterPreset) {
FilterService.FilterPreset.RiotFilter -> {
FilterFactory.createRiotFilterBody()
}
FilterService.FilterPreset.NoFilter -> {
FilterFactory.createDefaultFilterBody()
}
}
val roomFilter = when (params.filterPreset) {
FilterService.FilterPreset.RiotFilter -> {
FilterFactory.createRiotRoomFilter()
}
FilterService.FilterPreset.NoFilter -> {
FilterFactory.createDefaultRoomFilter()
}
}
val updated = filterRepository.storeFilter(filterBody, roomFilter)
if (updated) {
val filterResponse = executeRequest<FilterResponse> {
// TODO auto retry
apiCall = filterAPI.uploadFilter(userId, filterBody)
}
filterRepository.storeFilterId(filterBody, filterResponse.filterId)
}
filterRepository.storeFilterId(params.filter, filterResponse.filterId)
}
}

View file

@ -21,20 +21,20 @@ internal interface FilterRepository {
/**
* Return true if the filterBody has changed, or need to be sent to the server
*/
fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
suspend fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
/**
* Set the filterId of this filter
*/
fun storeFilterId(filterBody: FilterBody, filterId: String)
suspend fun storeFilterId(filterBody: FilterBody, filterId: String)
/**
* Return filter json or filter id
*/
fun getFilter(): String
suspend fun getFilter(): String
/**
* Return the room filter
*/
fun getRoomFilter(): String
suspend fun getRoomFilter(): String
}

View file

@ -16,27 +16,26 @@
package im.vector.matrix.android.internal.session.sync
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.SyncEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
import io.realm.RealmConfiguration
import javax.inject.Inject
internal class SyncTokenStore @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration) {
internal class SyncTokenStore @Inject constructor(private val monarchy: Monarchy) {
fun getLastToken(): String? {
val realm = Realm.getInstance(realmConfiguration)
val token = realm.where(SyncEntity::class.java).findFirst()?.nextBatch
realm.close()
return token
return Realm.getInstance(monarchy.realmConfiguration).use {
it.where(SyncEntity::class.java).findFirst()?.nextBatch
}
}
fun saveToken(token: String?) {
val realm = Realm.getInstance(realmConfiguration)
realm.executeTransaction {
suspend fun saveToken(token: String?) {
monarchy.awaitTransaction {
val sync = SyncEntity(token)
it.insertOrUpdate(sync)
}
realm.close()
}
}

View file

@ -116,7 +116,6 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
private fun onSessionCreated(session: Session) {
activeSessionHolder.setActiveSession(session)
session.configureAndStart(pushRuleTriggerListener, sessionListener)
setState {
copy(
asyncLoginAction = Success(Unit)
@ -131,9 +130,11 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
// Should not happen
Timber.w("homeServerConnectionConfig is null")
} else {
val session = authenticator.createSessionFromSso(action.credentials, homeServerConnectionConfigFinal)
onSessionCreated(session)
authenticator.createSessionFromSso(action.credentials, homeServerConnectionConfigFinal, object : MatrixCallback<Session> {
override fun onSuccess(data: Session) {
onSessionCreated(data)
}
})
}
}