Skip to content

Commit

Permalink
Don't throw MALTokenExpired whenever we fail to refresh MAL token
Browse files Browse the repository at this point in the history
Also cleanup

(cherry picked from commit 0f4de03)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt
  • Loading branch information
AntsyLich authored and cuong-tran committed Feb 19, 2024
1 parent 9d00784 commit bd5b8b7
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -36,27 +35,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
.header("User-Agent", "Komikku 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", "Komikku v${BuildConfig.VERSION_NAME} (${BuildConfig.APPLICATION_ID})")
.build()

return chain.proceed(newRequest)
}

return response
return chain.proceed(authRequest)
}

/**
Expand All @@ -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")
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit bd5b8b7

Please sign in to comment.