Don't throw MALTokenExpired whenever we fail to refresh MAL token

Also cleanup
This commit is contained in:
AntsyLich 2024-01-30 02:22:29 +06:00
parent ddbe8efbc5
commit 0f4de03d7a
No known key found for this signature in database
2 changed files with 34 additions and 38 deletions

View file

@ -21,9 +21,8 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
}
val originalRequest = chain.request()
// Refresh access token if expired
if (oauth != null && oauth!!.isExpired()) {
setAuth(refreshToken(chain))
if (oauth?.isExpired() == true) {
refreshToken(chain)
}
if (oauth == null) {
@ -36,27 +35,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
.header("User-Agent", "Mihon v${BuildConfig.VERSION_NAME} (${BuildConfig.APPLICATION_ID})")
.build()
val response = chain.proceed(authRequest)
val tokenIsExpired = response.headers["www-authenticate"]
?.contains("The access token expired") ?: false
// Retry the request once with a new token in case it was not already refreshed
// by the is expired check before.
if (response.code == 401 && tokenIsExpired) {
response.close()
val newToken = refreshToken(chain)
setAuth(newToken)
val newRequest = originalRequest.newBuilder()
.addHeader("Authorization", "Bearer ${newToken.access_token}")
.header("User-Agent", "Mihon v${BuildConfig.VERSION_NAME} (${BuildConfig.APPLICATION_ID})")
.build()
return chain.proceed(newRequest)
}
return response
return chain.proceed(authRequest)
}
/**
@ -68,22 +47,37 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
myanimelist.saveOAuth(oauth)
}
private fun refreshToken(chain: Interceptor.Chain): OAuth {
private fun refreshToken(chain: Interceptor.Chain): OAuth = synchronized(this) {
if (tokenExpired) throw MALTokenExpired()
oauth?.takeUnless { it.isExpired() }?.let { return@synchronized it }
val response = try {
chain.proceed(MyAnimeListApi.refreshTokenRequest(oauth!!))
} catch (_: Throwable) {
throw MALTokenRefreshFailed()
}
if (response.code == 401) {
myanimelist.setAuthExpired()
throw MALTokenExpired()
}
return runCatching {
val oauthResponse = chain.proceed(MyAnimeListApi.refreshTokenRequest(oauth!!))
if (oauthResponse.code == 401) {
myanimelist.setAuthExpired()
}
if (oauthResponse.isSuccessful) {
with(json) { oauthResponse.parseAs<OAuth>() }
if (response.isSuccessful) {
with(json) { response.parseAs<OAuth>() }
} else {
oauthResponse.close()
response.close()
null
}
}
.getOrNull()
?: throw MALTokenExpired()
?.also {
this.oauth = it
myanimelist.saveOAuth(it)
}
?: throw MALTokenRefreshFailed()
}
}
class MALTokenRefreshFailed : IOException("MAL: Failed to refresh account token")
class MALTokenExpired : IOException("MAL: Login has expired")

View file

@ -5,14 +5,16 @@ import kotlinx.serialization.Serializable
@Serializable
data class OAuth(
val token_type: String,
val refresh_token: String,
val access_token: String,
val token_type: String,
val created_at: Long = System.currentTimeMillis(),
val expires_in: Long,
)
fun OAuth.isExpired() = System.currentTimeMillis() > created_at + (expires_in * 1000)
val created_at: Long = System.currentTimeMillis(),
) {
// Assumes expired a minute earlier
private val adjustedExpiresIn: Long = (expires_in - 60) * 1000
fun isExpired() = created_at + adjustedExpiresIn < System.currentTimeMillis()
}
fun Track.toMyAnimeListStatus() = when (status) {
MyAnimeList.READING -> "reading"