Create network module

This commit is contained in:
Kirill Kamakin
2022-08-06 18:20:23 +02:00
parent c2c67730d1
commit e0a4442e72
59 changed files with 560 additions and 479 deletions

View File

@@ -4,5 +4,5 @@ interface AuthDataSource {
/**
* Tries to acquire authentication token using the provided credentials
*/
suspend fun authenticate(username: String, password: String): String
suspend fun authenticate(username: String, password: String, baseUrl: String): String
}

View File

@@ -1,56 +1,25 @@
package gq.kirmanak.mealient.data.auth.impl
import gq.kirmanak.mealient.data.auth.AuthDataSource
import gq.kirmanak.mealient.data.network.ErrorDetail
import gq.kirmanak.mealient.data.network.NetworkError.NotMealie
import gq.kirmanak.mealient.data.network.NetworkError.Unauthorized
import gq.kirmanak.mealient.data.network.ServiceFactory
import gq.kirmanak.mealient.extensions.decodeErrorBody
import gq.kirmanak.mealient.datasource.MealieDataSource
import gq.kirmanak.mealient.extensions.logAndMapErrors
import gq.kirmanak.mealient.logging.Logger
import kotlinx.serialization.json.Json
import retrofit2.HttpException
import retrofit2.Response
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AuthDataSourceImpl @Inject constructor(
private val authServiceFactory: ServiceFactory<AuthService>,
private val json: Json,
private val logger: Logger,
private val mealieDataSource: MealieDataSource,
) : AuthDataSource {
override suspend fun authenticate(username: String, password: String): String {
override suspend fun authenticate(username: String, password: String, baseUrl: String): String {
logger.v { "authenticate() called with: username = $username, password = $password" }
val authService = authServiceFactory.provideService()
val response = sendRequest(authService, username, password)
val accessToken = parseToken(response)
val accessToken = logger.logAndMapErrors(
block = { mealieDataSource.authenticate(baseUrl, username, password) },
logProvider = { "sendRequest: can't get token" },
)
logger.v { "authenticate() returned: $accessToken" }
return accessToken
}
private suspend fun sendRequest(
authService: AuthService,
username: String,
password: String
): Response<GetTokenResponse> = logger.logAndMapErrors(
block = { authService.getToken(username = username, password = password) },
logProvider = { "sendRequest: can't get token" },
)
private fun parseToken(
response: Response<GetTokenResponse>
): String = if (response.isSuccessful) {
response.body()?.accessToken ?: throw NotMealie(NullPointerException("Body is null"))
} else {
val cause = HttpException(response)
val errorDetail = json.runCatching<Json, ErrorDetail> { decodeErrorBody(response) }
.onFailure { logger.e(it) { "Can't decode error body" } }
.getOrNull()
throw when (errorDetail?.detail) {
"Unauthorized" -> Unauthorized(cause)
else -> NotMealie(cause)
}
}
}

View File

@@ -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.data.baseurl.BaseURLStorage
import gq.kirmanak.mealient.extensions.runCatchingExceptCancel
import gq.kirmanak.mealient.logging.Logger
import kotlinx.coroutines.flow.Flow
@@ -14,6 +15,7 @@ import javax.inject.Singleton
class AuthRepoImpl @Inject constructor(
private val authStorage: AuthStorage,
private val authDataSource: AuthDataSource,
private val baseURLStorage: BaseURLStorage,
private val logger: Logger,
) : AuthRepo {
@@ -22,7 +24,7 @@ class AuthRepoImpl @Inject constructor(
override suspend fun authenticate(email: String, password: String) {
logger.v { "authenticate() called with: email = $email, password = $password" }
authDataSource.authenticate(email, password)
authDataSource.authenticate(email, password, baseURLStorage.requireBaseURL())
.let { AUTH_HEADER_FORMAT.format(it) }
.let { authStorage.setAuthHeader(it) }
authStorage.setEmail(email)

View File

@@ -1,15 +0,0 @@
package gq.kirmanak.mealient.data.auth.impl
import retrofit2.Response
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
interface AuthService {
@FormUrlEncoded
@POST("/api/auth/token")
suspend fun getToken(
@Field("username") username: String,
@Field("password") password: String,
): Response<GetTokenResponse>
}

View File

@@ -1,7 +0,0 @@
package gq.kirmanak.mealient.data.auth.impl
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GetTokenResponse(@SerialName("access_token") val accessToken: String)