forked from GitHub-Mirror/riotX-android
Request : add some way to retry + introduce RequestExecutor
This commit is contained in:
parent
240b4715fc
commit
b2bb89ac94
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
@ -5,7 +5,7 @@ import java.io.IOException
|
|||||||
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
|
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
|
||||||
|
|
||||||
data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
|
data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
|
||||||
data class NetworkConnection(val ioException: IOException) : Failure(ioException)
|
data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException)
|
||||||
data class ServerError(val error: MatrixError) : Failure(RuntimeException(error.toString()))
|
data class ServerError(val error: MatrixError) : Failure(RuntimeException(error.toString()))
|
||||||
|
|
||||||
abstract class FeatureFailure : Failure()
|
abstract class FeatureFailure : Failure()
|
||||||
|
@ -2,6 +2,7 @@ package im.vector.matrix.android.internal.di
|
|||||||
|
|
||||||
import im.vector.matrix.android.internal.network.AccessTokenInterceptor
|
import im.vector.matrix.android.internal.network.AccessTokenInterceptor
|
||||||
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
||||||
|
import im.vector.matrix.android.internal.network.RequestExecutor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import org.koin.dsl.context.ModuleDefinition
|
import org.koin.dsl.context.ModuleDefinition
|
||||||
@ -50,6 +51,10 @@ class NetworkModule : Module {
|
|||||||
NetworkConnectivityChecker(get())
|
NetworkConnectivityChecker(get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single {
|
||||||
|
RequestExecutor(get(), get())
|
||||||
|
}
|
||||||
|
|
||||||
factory {
|
factory {
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.client(get())
|
.client(get())
|
||||||
|
@ -19,7 +19,7 @@ internal inline fun <DATA> executeRequest(block: Request<DATA>.() -> Unit) = Req
|
|||||||
|
|
||||||
internal class Request<DATA> {
|
internal class Request<DATA> {
|
||||||
|
|
||||||
var moshi: Moshi = MoshiProvider.providesMoshi()
|
private val moshi: Moshi = MoshiProvider.providesMoshi()
|
||||||
lateinit var apiCall: Call<DATA>
|
lateinit var apiCall: Call<DATA>
|
||||||
|
|
||||||
fun execute(): Try<DATA> {
|
fun execute(): Try<DATA> {
|
||||||
|
@ -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 <T> execute(retryTimes: Int = Int.MAX_VALUE,
|
||||||
|
initialDelay: Long = 100,
|
||||||
|
maxDelay: Long = 10_000,
|
||||||
|
factor: Double = 2.0,
|
||||||
|
block: suspend () -> Try<T>): Try<T> = withContext(coroutineDispatchers.io) {
|
||||||
|
|
||||||
|
retry(retryTimes, initialDelay, maxDelay, factor) {
|
||||||
|
executeIfConnected { block() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun <T> executeIfConnected(block: suspend () -> Try<T>): Try<T> {
|
||||||
|
return if (networkConnectivityChecker.isConnected()) {
|
||||||
|
block()
|
||||||
|
} else {
|
||||||
|
Try.raise(Failure.NetworkConnection())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -9,6 +9,7 @@ import im.vector.matrix.android.api.MatrixCallback
|
|||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
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.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.group.model.GroupRooms
|
import im.vector.matrix.android.internal.session.group.model.GroupRooms
|
||||||
import im.vector.matrix.android.internal.session.group.model.GroupSummaryResponse
|
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 io.realm.kotlin.createObject
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
internal class GetGroupDataRequest(
|
internal class GetGroupDataRequest(
|
||||||
private val groupAPI: GroupAPI,
|
private val groupAPI: GroupAPI,
|
||||||
private val monarchy: Monarchy,
|
private val monarchy: Monarchy,
|
||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
private val requestExecutor: RequestExecutor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(groupId: String,
|
fun execute(groupId: String,
|
||||||
callback: MatrixCallback<Boolean>
|
callback: MatrixCallback<Boolean>
|
||||||
): Cancelable {
|
): Cancelable {
|
||||||
val job = GlobalScope.launch(coroutineDispatchers.main) {
|
val job = GlobalScope.launch(coroutineDispatchers.main) {
|
||||||
val groupOrFailure = execute(groupId)
|
val groupOrFailure = requestExecutor.execute { getGroupData(groupId) }
|
||||||
groupOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(true) })
|
groupOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(true) })
|
||||||
}
|
}
|
||||||
return CancelableCoroutine(job)
|
return CancelableCoroutine(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun execute(groupId: String) = withContext(coroutineDispatchers.io) {
|
private fun getGroupData(groupId: String): Try<Unit> {
|
||||||
Try.monad().binding {
|
return Try.monad().binding {
|
||||||
|
|
||||||
val groupSummary = executeRequest<GroupSummaryResponse> {
|
val groupSummary = executeRequest<GroupSummaryResponse> {
|
||||||
apiCall = groupAPI.getSummary(groupId)
|
apiCall = groupAPI.getSummary(groupId)
|
||||||
}.bind()
|
}.bind()
|
||||||
@ -50,6 +52,7 @@ internal class GetGroupDataRequest(
|
|||||||
val groupUsers = executeRequest<GroupUsers> {
|
val groupUsers = executeRequest<GroupUsers> {
|
||||||
apiCall = groupAPI.getUsers(groupId)
|
apiCall = groupAPI.getUsers(groupId)
|
||||||
}.bind()
|
}.bind()
|
||||||
|
|
||||||
insertInDb(groupSummary, groupRooms, groupUsers, groupId).bind()
|
insertInDb(groupSummary, groupRooms, groupUsers, groupId).bind()
|
||||||
}.fix()
|
}.fix()
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ class GroupModule : Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
GetGroupDataRequest(get(), get(), get())
|
GetGroupDataRequest(get(), get(), get(), get())
|
||||||
}
|
}
|
||||||
|
|
||||||
}.invoke()
|
}.invoke()
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package im.vector.matrix.android.internal.util
|
||||||
|
|
||||||
|
import arrow.core.Try
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
suspend fun <T> 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<T>): Try<T> {
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user