Extract Authorization header to an interceptor
This commit is contained in:
@@ -3,6 +3,7 @@ package gq.kirmanak.mealient.data.auth.impl
|
||||
import gq.kirmanak.mealient.data.auth.AuthDataSource
|
||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||
import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||
import gq.kirmanak.mealient.logging.Logger
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -15,7 +16,7 @@ class AuthRepoImpl @Inject constructor(
|
||||
private val authStorage: AuthStorage,
|
||||
private val authDataSource: AuthDataSource,
|
||||
private val logger: Logger,
|
||||
) : AuthRepo {
|
||||
) : AuthRepo, AuthenticationProvider {
|
||||
|
||||
override val isAuthorizedFlow: Flow<Boolean>
|
||||
get() = authStorage.authHeaderFlow.map { it != null }
|
||||
|
||||
@@ -35,12 +35,12 @@ class MealieDataSourceWrapper @Inject constructor(
|
||||
|
||||
override suspend fun addRecipe(
|
||||
recipe: AddRecipeInfo,
|
||||
): String = makeCall { token, url, version ->
|
||||
): String = makeCall { url, version ->
|
||||
when (version) {
|
||||
ServerVersion.V0 -> v0Source.addRecipe(url, token, recipe.toV0Request())
|
||||
ServerVersion.V0 -> v0Source.addRecipe(url, recipe.toV0Request())
|
||||
ServerVersion.V1 -> {
|
||||
val slug = v1Source.createRecipe(url, token, recipe.toV1CreateRequest())
|
||||
v1Source.updateRecipe(url, token, slug, recipe.toV1UpdateRequest())
|
||||
val slug = v1Source.createRecipe(url, recipe.toV1CreateRequest())
|
||||
v1Source.updateRecipe(url, slug, recipe.toV1UpdateRequest())
|
||||
slug
|
||||
}
|
||||
}
|
||||
@@ -49,53 +49,53 @@ class MealieDataSourceWrapper @Inject constructor(
|
||||
override suspend fun requestRecipes(
|
||||
start: Int,
|
||||
limit: Int,
|
||||
): List<RecipeSummaryInfo> = makeCall { token, url, version ->
|
||||
): List<RecipeSummaryInfo> = makeCall { url, version ->
|
||||
when (version) {
|
||||
ServerVersion.V0 -> {
|
||||
v0Source.requestRecipes(url, token, start, limit).map { it.toRecipeSummaryInfo() }
|
||||
v0Source.requestRecipes(url, start, limit).map { it.toRecipeSummaryInfo() }
|
||||
}
|
||||
ServerVersion.V1 -> {
|
||||
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
|
||||
val page = start / limit + 1
|
||||
v1Source.requestRecipes(url, token, page, limit).map { it.toRecipeSummaryInfo() }
|
||||
v1Source.requestRecipes(url, page, limit).map { it.toRecipeSummaryInfo() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun requestRecipeInfo(
|
||||
slug: String,
|
||||
): FullRecipeInfo = makeCall { token, url, version ->
|
||||
): FullRecipeInfo = makeCall { url, version ->
|
||||
when (version) {
|
||||
ServerVersion.V0 -> v0Source.requestRecipeInfo(url, token, slug).toFullRecipeInfo()
|
||||
ServerVersion.V1 -> v1Source.requestRecipeInfo(url, token, slug).toFullRecipeInfo()
|
||||
ServerVersion.V0 -> v0Source.requestRecipeInfo(url, slug).toFullRecipeInfo()
|
||||
ServerVersion.V1 -> v1Source.requestRecipeInfo(url, slug).toFullRecipeInfo()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun parseRecipeFromURL(
|
||||
parseRecipeURLInfo: ParseRecipeURLInfo,
|
||||
): String = makeCall { token, url, version ->
|
||||
): String = makeCall { url, version ->
|
||||
when (version) {
|
||||
ServerVersion.V0 -> {
|
||||
v0Source.parseRecipeFromURL(url, token, parseRecipeURLInfo.toV0Request())
|
||||
v0Source.parseRecipeFromURL(url, parseRecipeURLInfo.toV0Request())
|
||||
}
|
||||
ServerVersion.V1 -> {
|
||||
v1Source.parseRecipeFromURL(url, token, parseRecipeURLInfo.toV1Request())
|
||||
v1Source.parseRecipeFromURL(url, parseRecipeURLInfo.toV1Request())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend inline fun <T> makeCall(block: (String?, String, ServerVersion) -> T): T {
|
||||
private suspend inline fun <T> makeCall(block: (String, ServerVersion) -> T): T {
|
||||
val authHeader = authRepo.getAuthHeader()
|
||||
val url = serverInfoRepo.requireUrl()
|
||||
val version = serverInfoRepo.getVersion()
|
||||
return runCatchingExceptCancel { block(authHeader, url, version) }.getOrElse {
|
||||
return runCatchingExceptCancel { block(url, version) }.getOrElse {
|
||||
if (it is NetworkError.Unauthorized) {
|
||||
logger.e { "Unauthorized, trying to invalidate token" }
|
||||
authRepo.invalidateAuthHeader()
|
||||
// Trying again with new authentication header
|
||||
val newHeader = authRepo.getAuthHeader()
|
||||
logger.e { "New token ${if (newHeader == authHeader) "matches" else "doesn't match"} old token" }
|
||||
if (newHeader == authHeader) throw it else block(newHeader, url, version)
|
||||
if (newHeader == authHeader) throw it else block(url, version)
|
||||
} else {
|
||||
throw it
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||
import gq.kirmanak.mealient.data.auth.impl.AuthDataSourceImpl
|
||||
import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl
|
||||
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
|
||||
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@@ -37,6 +38,10 @@ interface AuthModule {
|
||||
@Singleton
|
||||
fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindAuthProvider(authRepo: AuthRepoImpl): AuthenticationProvider
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package gq.kirmanak.mealient.ui.recipes.images
|
||||
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.model.*
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.ModelCache
|
||||
import com.bumptech.glide.load.model.ModelLoader
|
||||
import com.bumptech.glide.load.model.stream.BaseGlideUrlLoader
|
||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||
import gq.kirmanak.mealient.data.recipes.impl.RecipeImageUrlProvider
|
||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||
import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME
|
||||
import gq.kirmanak.mealient.logging.Logger
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.InputStream
|
||||
@@ -16,7 +16,6 @@ import javax.inject.Singleton
|
||||
class RecipeModelLoader private constructor(
|
||||
private val recipeImageUrlProvider: RecipeImageUrlProvider,
|
||||
private val logger: Logger,
|
||||
private val authRepo: AuthRepo,
|
||||
concreteLoader: ModelLoader<GlideUrl, InputStream>,
|
||||
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
|
||||
) : BaseGlideUrlLoader<RecipeSummaryEntity>(concreteLoader, cache) {
|
||||
@@ -25,13 +24,12 @@ class RecipeModelLoader private constructor(
|
||||
class Factory @Inject constructor(
|
||||
private val recipeImageUrlProvider: RecipeImageUrlProvider,
|
||||
private val logger: Logger,
|
||||
private val authRepo: AuthRepo,
|
||||
) {
|
||||
|
||||
fun build(
|
||||
concreteLoader: ModelLoader<GlideUrl, InputStream>,
|
||||
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
|
||||
) = RecipeModelLoader(recipeImageUrlProvider, logger, authRepo, concreteLoader, cache)
|
||||
) = RecipeModelLoader(recipeImageUrlProvider, logger, concreteLoader, cache)
|
||||
|
||||
}
|
||||
|
||||
@@ -46,20 +44,4 @@ class RecipeModelLoader private constructor(
|
||||
logger.v { "getUrl() called with: model = $model, width = $width, height = $height, options = $options" }
|
||||
return runBlocking { recipeImageUrlProvider.generateImageUrl(model?.imageId) }
|
||||
}
|
||||
|
||||
override fun getHeaders(
|
||||
model: RecipeSummaryEntity?,
|
||||
width: Int,
|
||||
height: Int,
|
||||
options: Options?
|
||||
): Headers? {
|
||||
val authorization = runBlocking { authRepo.getAuthHeader() }
|
||||
return if (authorization.isNullOrBlank()) {
|
||||
super.getHeaders(model, width, height, options)
|
||||
} else {
|
||||
LazyHeaders.Builder()
|
||||
.setHeader(AUTHORIZATION_HEADER_NAME, authorization)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user