Create network module
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user