119 lines
4.6 KiB
Kotlin
119 lines
4.6 KiB
Kotlin
package dev.inmo.postssystem.client.settings.auth
|
|
|
|
import dev.inmo.postssystem.client.DBDropper
|
|
import dev.inmo.postssystem.client.getAuthorizedFeaturesDIModule
|
|
import dev.inmo.postssystem.features.auth.client.AuthUnavailableException
|
|
import dev.inmo.postssystem.features.auth.client.ui.*
|
|
import dev.inmo.postssystem.features.auth.common.*
|
|
import dev.inmo.postssystem.features.roles.common.UserRole
|
|
import dev.inmo.postssystem.features.roles.common.UsersRolesStorage
|
|
import dev.inmo.postssystem.features.status.client.StatusFeatureClient
|
|
import dev.inmo.postssystem.features.users.common.User
|
|
import dev.inmo.micro_utils.common.Either
|
|
import dev.inmo.micro_utils.common.either
|
|
import dev.inmo.micro_utils.coroutines.plus
|
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
|
import dev.inmo.micro_utils.repos.*
|
|
import kotlinx.coroutines.*
|
|
import kotlinx.coroutines.flow.*
|
|
import org.koin.core.Koin
|
|
import org.koin.core.module.Module
|
|
|
|
data class DefaultAuthSettings(
|
|
private val repo: KeyValueRepo<String, Any>,
|
|
private val scope: CoroutineScope,
|
|
private val koin: Koin,
|
|
private val dbDropper: DBDropper
|
|
) : AuthSettings {
|
|
private val _authorizedDIModule = MutableStateFlow<Module?>(null)
|
|
override val authorizedDIModule: StateFlow<Module?> = _authorizedDIModule.asStateFlow()
|
|
private val _user = MutableStateFlow<User?>(null)
|
|
override val user: StateFlow<User?> = _user.asStateFlow()
|
|
private val _userRoles = MutableStateFlow<List<UserRole>>(emptyList())
|
|
override val userRoles: StateFlow<List<UserRole>> = _userRoles.asStateFlow()
|
|
|
|
private suspend fun getCurrentServerURL() = repo.get(SERVER_URL_FIELD) as? String
|
|
private suspend fun getCurrentUsername() = repo.get(USERNAME_FIELD) as? String
|
|
private suspend fun getCurrentToken() = repo.get(TOKEN_FIELD) as? AuthTokenInfo
|
|
|
|
override val loadingJob: Job = scope.launch {
|
|
val serverUrl = getCurrentServerURL() ?: return@launch
|
|
val token = getCurrentToken() ?: return@launch
|
|
updateModule(serverUrl, token.either())
|
|
}
|
|
|
|
val rolesUpdatingJob = (user + authorizedDIModule).subscribeSafelyWithoutExceptions(scope) {
|
|
val user = user.value
|
|
|
|
if (user == null || authorizedDIModule.value == null) {
|
|
_userRoles.value = emptyList()
|
|
} else {
|
|
_userRoles.value = koin.get<UsersRolesStorage<UserRole>>().getRoles(user.id)
|
|
}
|
|
println(user)
|
|
println(userRoles.value)
|
|
}
|
|
|
|
override suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError? {
|
|
return runCatching {
|
|
if (getCurrentServerURL() != serverUrl || getCurrentUsername() != creds.username.string) {
|
|
dbDropper()
|
|
}
|
|
repo.set(SERVER_URL_FIELD, serverUrl)
|
|
repo.set(USERNAME_FIELD, creds.username.string)
|
|
repo.unset(TOKEN_FIELD)
|
|
updateModule(serverUrl, creds.either())
|
|
}.onFailure {
|
|
it.printStackTrace()
|
|
}.getOrThrow()
|
|
}
|
|
|
|
private suspend fun updateModule(
|
|
serverUrl: String,
|
|
initialAuthKey: Either<AuthKey, AuthTokenInfo>,
|
|
): AuthUIError? {
|
|
val currentModule = authorizedDIModule.value
|
|
val newModule = getAuthorizedFeaturesDIModule(
|
|
serverUrl,
|
|
initialAuthKey,
|
|
{
|
|
repo.set(TOKEN_FIELD, it)
|
|
},
|
|
{
|
|
_user.value = it
|
|
}
|
|
) {
|
|
repo.unset(SERVER_URL_FIELD, USERNAME_FIELD, TOKEN_FIELD)
|
|
_authorizedDIModule.value = null
|
|
_user.value = null
|
|
throw AuthUnavailableException
|
|
}
|
|
currentModule ?.let { koin.unloadModules(listOf(currentModule)) }
|
|
koin.loadModules(listOf(newModule))
|
|
val statusFeature = koin.get<StatusFeatureClient>()
|
|
|
|
val serverAvailable = statusFeature.checkServerStatus()
|
|
val authCorrect = serverAvailable && runCatching {
|
|
statusFeature.checkServerStatusWithAuth()
|
|
}.getOrElse { false }
|
|
if (!serverAvailable && !authCorrect) {
|
|
koin.unloadModules(listOf(newModule))
|
|
currentModule ?.let { koin.loadModules(listOf(currentModule)) }
|
|
}
|
|
return when {
|
|
!serverAvailable -> ServerUnavailableAuthUIError
|
|
!authCorrect -> AuthIncorrectAuthUIError
|
|
else -> {
|
|
_authorizedDIModule.value = newModule
|
|
null
|
|
}
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private const val SERVER_URL_FIELD = "AuthServerURL"
|
|
private const val USERNAME_FIELD = "AuthUsername"
|
|
private const val TOKEN_FIELD = "AuthToken"
|
|
}
|
|
}
|