feat: token lifetime stored

This commit is contained in:
rebelonion 2024-02-25 18:35:45 -06:00
parent d5c87c46aa
commit 8a922bd083
4 changed files with 69 additions and 22 deletions

View file

@ -111,6 +111,10 @@ class App : MultiDexApplication() {
logger("Novel Extensions: ${novelExtensionManager.installedExtensionsFlow.first()}") logger("Novel Extensions: ${novelExtensionManager.installedExtensionsFlow.first()}")
NovelSources.init(novelExtensionManager.installedExtensionsFlow) NovelSources.init(novelExtensionManager.installedExtensionsFlow)
} }
val commentsScope = CoroutineScope(Dispatchers.Default)
commentsScope.launch {
CommentsAPI.fetchAuthToken()
}
} }

View file

@ -37,7 +37,6 @@ suspend fun getUserId(context: Context, block: () -> Unit) {
if (MAL.token != null && !MAL.query.getUserData()) if (MAL.token != null && !MAL.query.getUserData())
snackString(context.getString(R.string.error_loading_mal_user_data)) snackString(context.getString(R.string.error_loading_mal_user_data))
} }
CommentsAPI.fetchAuthToken()
true true
} else { } else {
snackString(context.getString(R.string.error_loading_anilist_user_data)) snackString(context.getString(R.string.error_loading_anilist_user_data))

View file

@ -4,6 +4,7 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString import ani.dantotsu.snackString
import com.lagradost.nicehttp.NiceResponse
import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Requests
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@ -206,31 +207,63 @@ object CommentsAPI {
suspend fun fetchAuthToken() { suspend fun fetchAuthToken() {
if (authToken != null) return if (authToken != null) return
val MAX_RETRIES = 5
val tokenLifetime: Long = 1000 * 60 * 60 * 24 * 6 // 6 days
val tokenExpiry = PrefManager.getVal<Long>(PrefName.CommentTokenExpiry)
if (tokenExpiry < System.currentTimeMillis() + tokenLifetime) {
val commentResponse = PrefManager.getNullableVal<AuthResponse>(PrefName.CommentAuthResponse, null)
if (commentResponse != null) {
authToken = commentResponse.authToken
userId = commentResponse.user.id
isBanned = commentResponse.user.isBanned ?: false
isAdmin = commentResponse.user.isAdmin ?: false
isMod = commentResponse.user.isMod ?: false
totalVotes = commentResponse.user.totalVotes
return
}
}
val url = "$address/authenticate" val url = "$address/authenticate"
val token = PrefManager.getVal(PrefName.AnilistToken, null as String?) ?: return val token = PrefManager.getVal(PrefName.AnilistToken, null as String?) ?: return
repeat(MAX_RETRIES) { // Define MAX_RETRIES as a constant
try {
val json = authRequest(token, url)
if (json.code == 200) {
if (!json.text.startsWith("{")) throw IOException("Invalid response")
val parsed = try {
Json.decodeFromString<AuthResponse>(json.text)
} catch (e: Exception) {
snackString("Failed to login to comments API: ${e.printStackTrace()}")
return
}
PrefManager.setVal(PrefName.CommentAuthResponse, parsed)
PrefManager.setVal(PrefName.CommentTokenExpiry, System.currentTimeMillis() + tokenLifetime)
authToken = parsed.authToken
userId = parsed.user.id
isBanned = parsed.user.isBanned ?: false
isAdmin = parsed.user.isAdmin ?: false
isMod = parsed.user.isMod ?: false
totalVotes = parsed.user.totalVotes
return
} else if (json.code != 429) {
errorReason(json.code, json.text)
return
}
} catch (e: IOException) {
snackString("Failed to login to comments API")
return
}
// Wait for 1 minute before retrying
kotlinx.coroutines.delay(60000)
}
snackString("Failed to login after multiple attempts")
}
private suspend fun authRequest(token: String, url: String): NiceResponse {
val body: FormBody = FormBody.Builder() val body: FormBody = FormBody.Builder()
.add("token", token) .add("token", token)
.build() .build()
val request = requestBuilder() val request = requestBuilder()
val json = try { return request.post(url, requestBody = body)
request.post(url, requestBody = body)
} catch (e: IOException) {
snackString("Failed to login to comments API")
return
}
if (!json.text.startsWith("{")) return
val parsed = try {
Json.decodeFromString<AuthResponse>(json.text)
} catch (e: Exception) {
snackString("Failed to login to comments API: ${e.printStackTrace()}")
return
}
authToken = parsed.authToken
userId = parsed.user.id
isBanned = parsed.user.isBanned ?: false
isAdmin = parsed.user.isAdmin ?: false
isMod = parsed.user.isMod ?: false
totalVotes = parsed.user.totalVotes
} }
private fun headerBuilder(): Map<String, String> { private fun headerBuilder(): Map<String, String> {
@ -278,7 +311,11 @@ data class AuthResponse(
val authToken: String, val authToken: String,
@SerialName("user") @SerialName("user")
val user: User val user: User
) ) : java.io.Serializable {
companion object {
private const val serialVersionUID: Long = 1
}
}
@Serializable @Serializable
data class User( data class User(
@ -299,7 +336,11 @@ data class User(
val isMod: Boolean? = null, val isMod: Boolean? = null,
@SerialName("total_votes") @SerialName("total_votes")
val totalVotes: Int, val totalVotes: Int,
) ) : java.io.Serializable {
companion object {
private const val serialVersionUID: Long = 1
}
}
@Serializable @Serializable
data class CommentResponse( data class CommentResponse(

View file

@ -1,6 +1,7 @@
package ani.dantotsu.settings.saving package ani.dantotsu.settings.saving
import android.graphics.Color import android.graphics.Color
import ani.dantotsu.connections.comments.AuthResponse
import ani.dantotsu.connections.mal.MAL import ani.dantotsu.connections.mal.MAL
import ani.dantotsu.settings.saving.internal.Location import ani.dantotsu.settings.saving.internal.Location
import ani.dantotsu.settings.saving.internal.Pref import ani.dantotsu.settings.saving.internal.Pref
@ -154,6 +155,8 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
TagsListNonAdult(Pref(Location.Irrelevant, Set::class, setOf<String>())), TagsListNonAdult(Pref(Location.Irrelevant, Set::class, setOf<String>())),
MakeDefault(Pref(Location.Irrelevant, Boolean::class, true)), MakeDefault(Pref(Location.Irrelevant, Boolean::class, true)),
FirstComment(Pref(Location.Irrelevant, Boolean::class, true)), FirstComment(Pref(Location.Irrelevant, Boolean::class, true)),
CommentAuthResponse(Pref(Location.Irrelevant, AuthResponse::class, "")),
CommentTokenExpiry(Pref(Location.Irrelevant, Long::class, 0L)),
//Protected //Protected
DiscordToken(Pref(Location.Protected, String::class, "")), DiscordToken(Pref(Location.Protected, String::class, "")),