Skip to content

Commit

Permalink
init auth network client
Browse files Browse the repository at this point in the history
  • Loading branch information
stslex committed Jul 29, 2023
1 parent ce659de commit 34cee2a
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 2 deletions.
1 change: 1 addition & 0 deletions core/network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ plugins {
}

dependencies {
implementation(project(":core:datastore"))
implementation(libs.bundles.ktor)
implementation(libs.bundles.okhttp)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@
package com.stslex.aproselection.core.network.client

import com.stslex.aproselection.core.datastore.AppDataStore
import com.stslex.aproselection.core.network.BuildConfig
import com.stslex.aproselection.core.network.clients.auth.model.TokenResponse
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.ClientRequestException
import io.ktor.client.plugins.HttpResponseValidator
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.plugins.logging.DEFAULT
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logger
import io.ktor.client.plugins.logging.Logging
import io.ktor.client.request.bearerAuth
import io.ktor.client.request.get
import io.ktor.http.HttpStatusCode
import io.ktor.http.URLProtocol
import io.ktor.http.appendPathSegments
import io.ktor.http.encodedPath
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json

class NetworkClientImpl : NetworkClient {
class NetworkClientImpl(
private val dataStore: AppDataStore
) : NetworkClient {

private val scope = CoroutineScope(SupervisorJob())
private val _token = MutableStateFlow("")
private val token = _token.asStateFlow()
private val _uuid = MutableStateFlow("")
private val uuid = _uuid.asStateFlow()

init {
dataStore.token
.onEach {
_token.emit(it)
}
.launchIn(scope)

dataStore.uuid
.onEach {
_uuid.emit(it)
}
.launchIn(scope)
}

@OptIn(ExperimentalSerializationApi::class)
override val client: HttpClient
Expand All @@ -39,6 +75,17 @@ class NetworkClientImpl : NetworkClient {
}
)
}

HttpResponseValidator {
handleResponseExceptionWithRequest { exception, request ->
val clientException = exception as? ClientRequestException
?: return@handleResponseExceptionWithRequest
val exceptionResponse = clientException.response
if (exceptionResponse.status == HttpStatusCode.Unauthorized) {
regenerateToken()
}
}
}
}

override val apiClient: HttpClient
Expand All @@ -48,8 +95,21 @@ class NetworkClientImpl : NetworkClient {
host = BuildConfig.API_SERVER_HOST
encodedPath = BuildConfig.API_VERSION
protocol = URLProtocol.HTTP
headers.append("API_KEY", BuildConfig.API_KEY)
headers.append("DEVICE_ID", "test")
headers.append("uuid", uuid.value)
}
bearerAuth(BuildConfig.API_KEY)
bearerAuth(token = token.value)
}
}

private suspend fun regenerateToken() {
val token = client
.get {
url.appendPathSegments("token")
}
.body<TokenResponse>()
.token
dataStore.setToken(token)
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package com.stslex.aproselection.core.network.clients.auth

import com.stslex.aproselection.core.network.clients.auth.model.HelloRequestModel
import com.stslex.aproselection.core.network.clients.auth.model.UserAuthResponseModel
import com.stslex.aproselection.core.network.clients.auth.model.UserAuthSendModel
import kotlinx.coroutines.flow.Flow

interface AuthNetworkClient {

suspend fun getHello(username: String): HelloRequestModel

fun auth(user: UserAuthSendModel): Flow<UserAuthResponseModel>

fun register(user: UserAuthSendModel): Flow<UserAuthResponseModel>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ package com.stslex.aproselection.core.network.clients.auth

import com.stslex.aproselection.core.network.client.NetworkClient
import com.stslex.aproselection.core.network.clients.auth.model.HelloRequestModel
import com.stslex.aproselection.core.network.clients.auth.model.UserAuthResponseModel
import com.stslex.aproselection.core.network.clients.auth.model.UserAuthSendModel
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.setBody
import io.ktor.http.appendPathSegments
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.withContext

class AuthNetworkClientImpl(
Expand All @@ -22,4 +28,33 @@ class AuthNetworkClientImpl(
}
.body()
}


override fun auth(
user: UserAuthSendModel
): Flow<UserAuthResponseModel> = flow {
val result = networkClient
.apiClient
.get {
url.appendPathSegments("passport/auth")
setBody(user)
}
.body<UserAuthResponseModel>()
emit(result)
}
.flowOn(Dispatchers.IO)

override fun register(
user: UserAuthSendModel
): Flow<UserAuthResponseModel> = flow {
val result = networkClient
.apiClient
.get {
url.appendPathSegments("passport/register")
setBody(user)
}
.body<UserAuthResponseModel>()
emit(result)
}
.flowOn(Dispatchers.IO)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.stslex.aproselection.core.network.clients.auth.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class TokenResponse(
@SerialName("token")
val token: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.stslex.aproselection.core.network.clients.auth.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class UserAuthResponseModel(
@SerialName("uuid")
val uuid: String,
@SerialName("username")
val username: String,
@SerialName("nickname")
val nickname: String,
@SerialName("token")
val token: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.stslex.aproselection.core.network.clients.auth.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class UserAuthSendModel(
@SerialName("username")
val username: String,
@SerialName("password")
val password: String
)

0 comments on commit 34cee2a

Please sign in to comment.