Skip to content

Commit

Permalink
fix not going back after scan and refresh token if time requires it
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Apr 19, 2024
1 parent e436181 commit 451b45f
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@ package dev.datlag.aniflow.other
import dev.datlag.aniflow.model.saveFirstOrNull
import dev.datlag.aniflow.settings.DataStoreUserSettings
import dev.datlag.aniflow.settings.Settings
import io.github.aakira.napier.Napier
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.publicvalue.multiplatform.oidc.OpenIdConnectClient
import org.publicvalue.multiplatform.oidc.tokenstore.OauthTokens
import org.publicvalue.multiplatform.oidc.types.remote.AccessTokenResponse
import kotlin.time.Duration.Companion.minutes

class TokenRefreshHandler(
private val storeUserSettings: Settings.PlatformUserSettings
) {

private val mutex = Mutex()
private var lastRefresh: Int = 0

suspend fun getAccessToken(): String? {
return storeUserSettings.aniList.saveFirstOrNull()?.accessToken
Expand All @@ -26,24 +31,32 @@ class TokenRefreshHandler(

suspend fun refreshAndSaveToken(refreshCall: suspend (String) -> AccessTokenResponse, oldAccessToken: String): OauthTokens {
mutex.withLock {
val currentTokens = storeUserSettings.aniList.saveFirstOrNull()?.let {
val storeData = storeUserSettings.aniList.saveFirstOrNull()
val currentTokens = storeData?.let {
OauthTokens(
accessToken = it.accessToken ?: return@let null,
refreshToken = it.refreshToken,
idToken = it.idToken
)
}

return if (currentTokens != null && currentTokens.accessToken != oldAccessToken) {
val nowMinus10Minutes = Clock.System.now().minus(10.minutes).epochSeconds
val requiresRefresh = lastRefresh <= nowMinus10Minutes || nowMinus10Minutes > (storeData?.expires ?: 0)

return if (currentTokens != null && currentTokens.accessToken != oldAccessToken && !requiresRefresh) {
currentTokens
} else {
val refreshToken = storeUserSettings.aniListRefreshToken.firstOrNull()
val refreshToken = storeUserSettings.aniListRefreshToken.saveFirstOrNull()
val newTokens = refreshCall(refreshToken ?: "")
storeUserSettings.setAniListTokens(
access = newTokens.access_token,
refresh = newTokens.refresh_token,
id = newTokens.id_token
id = newTokens.id_token,
expires = (newTokens.expires_in ?: newTokens.refresh_token_expires_in)?.let {
Clock.System.now().epochSeconds + it
}?.toInt()
)
lastRefresh = Clock.System.now().epochSeconds.toInt()

OauthTokens(
accessToken = newTokens.access_token,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import dev.datlag.aniflow.trace.TraceStateMachine
import dev.datlag.aniflow.ui.navigation.Component
import dev.datlag.aniflow.ui.navigation.ContentHolderComponent
import io.ktor.utils.io.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

interface HomeComponent : ContentHolderComponent {
val airingState: StateFlow<AiringTodayStateMachine.State>
val trendingState: StateFlow<TrendingAnimeStateMachine.State>
val popularSeasonState: StateFlow<SeasonState>
val popularNextSeasonState: StateFlow<SeasonState>
val traceState: StateFlow<TraceStateMachine.State>
val traceState: Flow<TraceStateMachine.State>

fun details(medium: Medium)
fun trace(channel: ByteArray)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private fun MainView(component: HomeComponent, modifier: Modifier = Modifier) {
val imagePicker = rememberImagePickerState {
it?.let(component::trace)
}
val traceState by component.traceState.collectAsStateWithLifecycle()
val traceState by component.traceState.collectAsStateWithLifecycle(TraceStateMachine.State.Waiting)

LaunchedEffect(listState, traceState) {
FABConfig.state.value = FABConfig.Scan(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ import dev.datlag.aniflow.ui.navigation.Component
import dev.datlag.aniflow.ui.navigation.screen.medium.MediumScreenComponent
import dev.datlag.tooling.compose.ioDispatcher
import dev.datlag.tooling.decompose.ioScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.*
import org.kodein.di.DI
import org.kodein.di.instance

Expand Down Expand Up @@ -66,12 +63,8 @@ class HomeScreenComponent(
)

private val traceStateMachine by di.instance<TraceStateMachine>()
override val traceState: StateFlow<TraceStateMachine.State> = traceStateMachine.state.flowOn(
override val traceState: Flow<TraceStateMachine.State> = traceStateMachine.state.flowOn(
context = ioDispatcher()
).stateIn(
scope = ioScope(),
started = SharingStarted.WhileSubscribed(),
initialValue = TraceStateMachine.State.Waiting
)

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,10 @@ class MediumScreenComponent(
userSettings.setAniListTokens(
access = it.access_token,
refresh = it.refresh_token,
id = it.id_token
id = it.id_token,
expires = (it.expires_in ?: it.refresh_token_expires_in)?.let { time ->
Clock.System.now().epochSeconds + time
}?.toInt()
)
}

Expand Down
1 change: 1 addition & 0 deletions settings/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ kotlin {

implementation(libs.serialization.protobuf)
implementation(libs.tooling)
implementation(libs.datetime)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package dev.datlag.aniflow.settings
import androidx.datastore.core.DataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.datetime.Clock

class DataStoreUserSettings(
private val dataStore: DataStore<UserSettings>
) : Settings.PlatformUserSettings {
override val aniList: Flow<UserSettings.AniList> = dataStore.data.map { it.aniList }
override val aniListRefreshToken: Flow<String?> = aniList.map { it.refreshToken }
override val isAniListLoggedIn: Flow<Boolean> = aniList.map { it.accessToken != null }
override val isAniListLoggedIn: Flow<Boolean> = aniList.map {
it.accessToken != null && Clock.System.now().epochSeconds < (it.expires ?: 0)
}

override suspend fun setAniListAccessToken(token: String) {
dataStore.updateData {
Expand Down Expand Up @@ -41,13 +44,19 @@ class DataStoreUserSettings(
}
}

override suspend fun setAniListTokens(access: String, refresh: String?, id: String?) {
override suspend fun setAniListTokens(
access: String,
refresh: String?,
id: String?,
expires: Int?
) {
dataStore.updateData {
it.copy(
aniList = it.aniList.copy(
accessToken = access,
refreshToken = refresh,
idToken = id
idToken = id,
expires = expires
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ data object Settings {
suspend fun setAniListAccessToken(token: String)
suspend fun setAniListRefreshToken(token: String)
suspend fun setAniListIdToken(token: String)
suspend fun setAniListTokens(access: String, refresh: String?, id: String?)
suspend fun setAniListTokens(
access: String,
refresh: String?,
id: String?,
expires: Int?
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ data class UserSettings(
@ProtoNumber(1) val aniList: AniList = AniList(
accessToken = null,
refreshToken = null,
idToken = null
idToken = null,
expires = null
)
) {
@Serializable
data class AniList(
@ProtoNumber(1) val accessToken: String?,
@ProtoNumber(2) val refreshToken: String?,
@ProtoNumber(3) val idToken: String?,
@ProtoNumber(4) val expires: Int?
)
}

0 comments on commit 451b45f

Please sign in to comment.