Add http retry back on unauthorized request
This commit is contained in:
parent
9860ccd576
commit
8ecc6f9b69
|
@ -7,6 +7,7 @@ import com.github.kittinunf.fuel.Fuel
|
|||
import com.github.kittinunf.fuel.core.FuelError
|
||||
import com.github.kittinunf.fuel.core.ResponseDeserializable
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResult
|
||||
import com.github.kittinunf.result.Result
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
@ -32,6 +33,8 @@ class HttpUpstream<D : Any, R : OtterResponse<D>>(
|
|||
Progressive
|
||||
}
|
||||
|
||||
private val http = HTTP(context, oAuth)
|
||||
|
||||
override fun fetch(size: Int): Flow<Repository.Response<D>> = flow<Repository.Response<D>> {
|
||||
|
||||
context?.let {
|
||||
|
@ -89,10 +92,36 @@ class HttpUpstream<D : Any, R : OtterResponse<D>>(
|
|||
val request = Fuel.get(mustNormalizeUrl(url)).apply {
|
||||
authorize(context, oAuth)
|
||||
}
|
||||
val (_, _, result) = request.awaitObjectResponseResult(GenericDeserializer<R>(type))
|
||||
val (_, response, result) = request.awaitObjectResponseResult(GenericDeserializer<R>(type))
|
||||
|
||||
if (response.statusCode == 401) {
|
||||
return retryGet(url)
|
||||
}
|
||||
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
Result.error(FuelError.wrap(e))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun retryGet(url: String): Result<R, FuelError> {
|
||||
context?.let {
|
||||
return try {
|
||||
return if (http.refresh()) {
|
||||
val request = Fuel.get(mustNormalizeUrl(url)).apply {
|
||||
if (!Settings.isAnonymous()) {
|
||||
header("Authorization", "Bearer ${oAuth.state().accessToken}")
|
||||
}
|
||||
}
|
||||
|
||||
request.awaitObjectResult(GenericDeserializer(type))
|
||||
} else {
|
||||
Result.Failure(FuelError.wrap(RefreshError))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Result.error(FuelError.wrap(e))
|
||||
}
|
||||
}
|
||||
throw IllegalStateException("Illegal state: context is null")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
package audio.funkwhale.ffa.utils
|
||||
|
||||
import android.content.Context
|
||||
import audio.funkwhale.ffa.activities.FwCredentials
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.core.FuelError
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResult
|
||||
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
|
||||
import com.github.kittinunf.result.Result
|
||||
import com.preference.PowerPreference
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
|
@ -8,6 +16,78 @@ import java.security.MessageDigest
|
|||
|
||||
object RefreshError : Throwable()
|
||||
|
||||
class HTTP(
|
||||
val context: Context?,
|
||||
val oAuth: OAuth
|
||||
) {
|
||||
|
||||
suspend fun refresh(): Boolean {
|
||||
context?.let {
|
||||
val body = mapOf(
|
||||
"username" to PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS)
|
||||
.getString("username"),
|
||||
"password" to PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS)
|
||||
.getString("password")
|
||||
).toList()
|
||||
|
||||
val result = Fuel.post(mustNormalizeUrl("/api/v1/token"), body).apply {
|
||||
if (!Settings.isAnonymous()) {
|
||||
authorize(it, oAuth)
|
||||
header("Authorization", "Bearer ${oAuth.state().accessToken}")
|
||||
}
|
||||
}
|
||||
.awaitObjectResult(gsonDeserializerOf(FwCredentials::class.java))
|
||||
|
||||
return result.fold(
|
||||
{ data ->
|
||||
PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS)
|
||||
.setString("access_token", data.token)
|
||||
|
||||
true
|
||||
},
|
||||
{ false }
|
||||
)
|
||||
}
|
||||
throw IllegalStateException("Illegal state: context is null")
|
||||
}
|
||||
|
||||
suspend inline fun <reified T : Any> get(url: String): Result<T, FuelError> {
|
||||
|
||||
context?.let {
|
||||
val request = Fuel.get(mustNormalizeUrl(url)).apply {
|
||||
if (!Settings.isAnonymous()) {
|
||||
authorize(it, oAuth)
|
||||
header("Authorization", "Bearer ${oAuth.state().accessToken}")
|
||||
}
|
||||
}
|
||||
|
||||
val (_, response, result) = request.awaitObjectResponseResult(gsonDeserializerOf(T::class.java))
|
||||
|
||||
if (response.statusCode == 401) {
|
||||
return retryGet(url)
|
||||
} else {
|
||||
return result
|
||||
}
|
||||
}
|
||||
throw IllegalStateException("Illegal state: context is null")
|
||||
}
|
||||
|
||||
suspend inline fun <reified T : Any> retryGet(
|
||||
url: String
|
||||
): Result<T, FuelError> {
|
||||
context?.let {
|
||||
val request = Fuel.get(mustNormalizeUrl(url)).apply {
|
||||
if (!Settings.isAnonymous()) {
|
||||
authorize(context,oAuth)
|
||||
header("Authorization", "Bearer ${oAuth.state().accessToken}")
|
||||
}
|
||||
}
|
||||
request.awaitObjectResult(gsonDeserializerOf(T::class.java))
|
||||
}
|
||||
throw IllegalStateException("Illegal state: context is null")
|
||||
}
|
||||
}
|
||||
|
||||
object FFACache {
|
||||
private fun key(key: String): String {
|
||||
val md = MessageDigest.getInstance("SHA-1")
|
||||
|
|
Loading…
Reference in New Issue