From b2bb89ac944a55f45c292cc45ab0bfe3651b5f91 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 8 Nov 2018 13:56:07 +0100 Subject: [PATCH] Request : add some way to retry + introduce RequestExecutor --- .idea/caches/build_file_checksums.ser | Bin 661 -> 659 bytes .../matrix/android/api/failure/Failure.kt | 2 +- .../android/internal/di/NetworkModule.kt | 5 +++ .../android/internal/network/Request.kt | 2 +- .../internal/network/RequestExecutor.kt | 34 ++++++++++++++++++ .../session/group/GetGroupDataRequest.kt | 15 ++++---- .../internal/session/group/GroupModule.kt | 2 +- .../android/internal/util/CoroutineRetry.kt | 24 +++++++++++++ 8 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RequestExecutor.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CoroutineRetry.kt diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 8084fcddab4e06863c84e500c2f470fbe91181ed..de59e1fa0794524236c6a02938b9cd97c2c30ca2 100644 GIT binary patch delta 73 zcmV-P0Ji^?1(OAkm<00k1{RT=hz=(&RdZ!>b1!FMZf0^}lLZ1clVAZqlOzE=lb-=Z f6Mxpspp executeRequest(block: Request.() -> Unit) = Req internal class Request { - var moshi: Moshi = MoshiProvider.providesMoshi() + private val moshi: Moshi = MoshiProvider.providesMoshi() lateinit var apiCall: Call fun execute(): Try { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RequestExecutor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RequestExecutor.kt new file mode 100644 index 00000000..b5da240d --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RequestExecutor.kt @@ -0,0 +1,34 @@ +package im.vector.matrix.android.internal.network + +import arrow.core.Try +import im.vector.matrix.android.api.failure.Failure +import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers +import im.vector.matrix.android.internal.util.retry +import kotlinx.coroutines.withContext + +internal class RequestExecutor(private val networkConnectivityChecker: NetworkConnectivityChecker, + private val coroutineDispatchers: MatrixCoroutineDispatchers) { + + + suspend fun execute(retryTimes: Int = Int.MAX_VALUE, + initialDelay: Long = 100, + maxDelay: Long = 10_000, + factor: Double = 2.0, + block: suspend () -> Try): Try = withContext(coroutineDispatchers.io) { + + retry(retryTimes, initialDelay, maxDelay, factor) { + executeIfConnected { block() } + } + + } + + private suspend fun executeIfConnected(block: suspend () -> Try): Try { + return if (networkConnectivityChecker.isConnected()) { + block() + } else { + Try.raise(Failure.NetworkConnection()) + } + } + + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataRequest.kt index 3a5d3b9b..5b7c3001 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GetGroupDataRequest.kt @@ -9,6 +9,7 @@ import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.database.model.GroupSummaryEntity import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.network.RequestExecutor import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.group.model.GroupRooms import im.vector.matrix.android.internal.session.group.model.GroupSummaryResponse @@ -19,26 +20,27 @@ import im.vector.matrix.android.internal.util.tryTransactionSync import io.realm.kotlin.createObject import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext internal class GetGroupDataRequest( private val groupAPI: GroupAPI, private val monarchy: Monarchy, - private val coroutineDispatchers: MatrixCoroutineDispatchers + private val coroutineDispatchers: MatrixCoroutineDispatchers, + private val requestExecutor: RequestExecutor ) { fun execute(groupId: String, callback: MatrixCallback ): Cancelable { val job = GlobalScope.launch(coroutineDispatchers.main) { - val groupOrFailure = execute(groupId) + val groupOrFailure = requestExecutor.execute { getGroupData(groupId) } groupOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(true) }) } return CancelableCoroutine(job) } - private suspend fun execute(groupId: String) = withContext(coroutineDispatchers.io) { - Try.monad().binding { + private fun getGroupData(groupId: String): Try { + return Try.monad().binding { + val groupSummary = executeRequest { apiCall = groupAPI.getSummary(groupId) }.bind() @@ -50,6 +52,7 @@ internal class GetGroupDataRequest( val groupUsers = executeRequest { apiCall = groupAPI.getUsers(groupId) }.bind() + insertInDb(groupSummary, groupRooms, groupUsers, groupId).bind() }.fix() } @@ -61,7 +64,7 @@ internal class GetGroupDataRequest( return monarchy .tryTransactionSync { realm -> val groupSummaryEntity = GroupSummaryEntity.where(realm, groupId).findFirst() - ?: realm.createObject(groupId) + ?: realm.createObject(groupId) groupSummaryEntity.avatarUrl = groupSummary.profile?.avatarUrl ?: "" val name = groupSummary.profile?.name diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt index 1f8bf99c..eaca16b7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt @@ -16,7 +16,7 @@ class GroupModule : Module { } scope(DefaultSession.SCOPE) { - GetGroupDataRequest(get(), get(), get()) + GetGroupDataRequest(get(), get(), get(), get()) } }.invoke() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CoroutineRetry.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CoroutineRetry.kt new file mode 100644 index 00000000..28520a69 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/CoroutineRetry.kt @@ -0,0 +1,24 @@ +package im.vector.matrix.android.internal.util + +import arrow.core.Try +import kotlinx.coroutines.delay + +suspend fun retry( + times: Int = Int.MAX_VALUE, + initialDelay: Long = 100, // 0.1 second + maxDelay: Long = 10_000, // 10 second + factor: Double = 2.0, + block: suspend () -> Try): Try { + + var currentDelay = initialDelay + repeat(times - 1) { + val blockResult = block() + if (blockResult.isSuccess()) { + return blockResult + } else { + delay(currentDelay) + currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay) + } + } + return block() +} \ No newline at end of file