Skip to content

Commit

Permalink
load score on login
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Apr 19, 2024
1 parent 6cf1dff commit e085fa9
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 26 deletions.
5 changes: 5 additions & 0 deletions anilist/src/commonMain/graphql/MediaListEntry.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query MediaListEntry($id: Int) {
MediaList(mediaId: $id) {
score(format: POINT_5)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ class TokenRefreshHandler(

private val mutex = Mutex()
private var lastRefresh: Int = 0
private var memoryAccessToken: String? = null

suspend fun getAccessToken(): String? {
return storeUserSettings.aniList.saveFirstOrNull()?.accessToken
return mutex.withLock(storeUserSettings) {
storeUserSettings.aniList.saveFirstOrNull()?.accessToken?.ifBlank { null }
} ?: memoryAccessToken
}

suspend fun refreshAndSaveToken(client: OpenIdConnectClient, oldAccessToken: String): OauthTokens {
Expand All @@ -31,7 +34,9 @@ class TokenRefreshHandler(

suspend fun refreshAndSaveToken(refreshCall: suspend (String) -> AccessTokenResponse, oldAccessToken: String): OauthTokens {
mutex.withLock {
val storeData = storeUserSettings.aniList.saveFirstOrNull()
val storeData = mutex.withLock(storeUserSettings) {
storeUserSettings.aniList.saveFirstOrNull()
}
val currentTokens = storeData?.let {
OauthTokens(
accessToken = it.accessToken ?: return@let null,
Expand All @@ -46,16 +51,11 @@ class TokenRefreshHandler(
return if (currentTokens != null && currentTokens.accessToken != oldAccessToken && !requiresRefresh) {
currentTokens
} else {
val refreshToken = storeUserSettings.aniListRefreshToken.saveFirstOrNull()
val refreshToken = mutex.withLock(storeUserSettings) {
storeUserSettings.aniListRefreshToken.saveFirstOrNull()
}
val newTokens = refreshCall(refreshToken ?: "")
storeUserSettings.setAniListTokens(
access = newTokens.access_token,
refresh = newTokens.refresh_token,
id = newTokens.id_token,
expires = (newTokens.refresh_token_expires_in ?: newTokens.expires_in)?.let {
Clock.System.now().epochSeconds + it
}?.toInt()
)
updateStoredToken(newTokens)
lastRefresh = Clock.System.now().epochSeconds.toInt()

OauthTokens(
Expand All @@ -66,4 +66,19 @@ class TokenRefreshHandler(
}
}
}

suspend fun updateStoredToken(tokenResponse: AccessTokenResponse) {
mutex.withLock(storeUserSettings) {
memoryAccessToken = tokenResponse.access_token

storeUserSettings.setAniListTokens(
access = tokenResponse.access_token,
refresh = tokenResponse.refresh_token,
id = tokenResponse.id_token,
expires = (tokenResponse.refresh_token_expires_in ?: tokenResponse.expires_in)?.let {
Clock.System.now().epochSeconds + it
}?.toInt()
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.arkivanov.essenty.backhandler.BackCallback
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import dev.chrisbanes.haze.HazeState
import dev.datlag.aniflow.LocalHaze
import dev.datlag.aniflow.anilist.MediaListEntryQuery
import dev.datlag.aniflow.anilist.MediumQuery
import dev.datlag.aniflow.anilist.MediumStateMachine
import dev.datlag.aniflow.anilist.RatingMutation
Expand All @@ -20,6 +21,8 @@ import dev.datlag.aniflow.common.nullableFirebaseInstance
import dev.datlag.aniflow.common.onRenderApplyCommonScheme
import dev.datlag.aniflow.common.popular
import dev.datlag.aniflow.common.rated
import dev.datlag.aniflow.model.CatchResult
import dev.datlag.aniflow.model.alsoTrue
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.aniflow.other.Constants
import dev.datlag.aniflow.other.TokenRefreshHandler
Expand All @@ -37,6 +40,7 @@ import org.kodein.di.DI
import org.kodein.di.instance
import org.publicvalue.multiplatform.oidc.OpenIdConnectClient
import org.publicvalue.multiplatform.oidc.appsupport.CodeAuthFlowFactory
import kotlin.time.Duration.Companion.seconds

class MediumScreenComponent(
componentContext: ComponentContext,
Expand All @@ -47,6 +51,8 @@ class MediumScreenComponent(

private val aniListClient by di.instance<ApolloClient>(Constants.AniList.APOLLO_CLIENT)
private val aniListFallbackClient by di.instance<ApolloClient>(Constants.AniList.FALLBACK_APOLLO_CLIENT)
private val tokenRefreshHandler by di.instance<TokenRefreshHandler>()

private val mediumStateMachine = MediumStateMachine(
client = aniListClient,
fallbackClient = aniListFallbackClient,
Expand Down Expand Up @@ -328,17 +334,21 @@ class MediumScreenComponent(
}

tokenResult.getOrNull()?.let {
userSettings.setAniListTokens(
access = it.access_token,
refresh = it.refresh_token,
id = it.id_token,
expires = (it.refresh_token_expires_in ?: it.expires_in)?.let { time ->
Clock.System.now().epochSeconds + time
}?.toInt()
)
tokenRefreshHandler.updateStoredToken(it)
}

return tokenResult.isSuccess
return tokenResult.isSuccess.alsoTrue {
val query = MediaListEntryQuery(
id = Optional.present(mediaId.saveFirstOrNull() ?: mediaId.value)
)
val execution = CatchResult.timeout(5.seconds) {
apolloClient.query(query).execute()
}.asNullableSuccess()

execution?.data?.MediaList?.let { entry ->
changedRating.emit(entry.score?.toInt() ?: changedRating.value)
}
}
}

override fun rate(onLoggedIn: () -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import dev.datlag.tooling.async.suspendCatching
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.withTimeout
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds

sealed interface CatchResult<T> {
Expand Down Expand Up @@ -91,9 +93,7 @@ sealed interface CatchResult<T> {
return@coroutineScope if (result.isFailure) {
Error(result.exceptionOrNull())
} else {
result.getOrNull()?.let {
Success(it)
} ?: Error(result.exceptionOrNull())
result.getOrNull()?.let(::Success) ?: Error(result.exceptionOrNull())
}
}

Expand All @@ -113,11 +113,31 @@ sealed interface CatchResult<T> {
return@coroutineScope if (result.isFailure) {
Error(result.exceptionOrNull())
} else {
result.getOrNull()?.let {
Success(it)
} ?: Error(result.exceptionOrNull())
result.getOrNull()?.let(::Success) ?: Error(result.exceptionOrNull())
}
}

suspend fun <T> timeout(
time: Duration,
block: suspend CoroutineScope.() -> T
): CatchResult<T & Any> = coroutineScope {
val result = suspendCatching {
withTimeout(time, block)
}

return@coroutineScope if (result.isFailure) {
Error(result.exceptionOrNull())
} else {
result.getOrNull()?.let(::Success) ?: Error(result.exceptionOrNull())
}
}

suspend fun <T> timeout(
timeMillis: Long,
block: suspend CoroutineScope.() -> T
): CatchResult<T & Any> {
return timeout(timeMillis.milliseconds, block)
}
}
}

Expand Down
15 changes: 15 additions & 0 deletions model/src/commonMain/kotlin/dev/datlag/aniflow/model/ExtendAny.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.datlag.aniflow.model

inline fun Boolean.alsoTrue(block: Boolean.() -> Unit): Boolean {
if (this) {
block(this)
}
return this
}

inline fun Boolean.alsoFalse(block: Boolean.() -> Unit): Boolean {
if (!this) {
block(this)
}
return this
}

0 comments on commit e085fa9

Please sign in to comment.