diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt index 92877ca..d6c79cb 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/Main.kt @@ -19,12 +19,14 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.sessions.* import io.ktor.server.websocket.* +import kotlinx.coroutines.delay import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import space.mori.chzzk_bot.common.services.UserService import space.mori.chzzk_bot.webserver.routes.* import space.mori.chzzk_bot.webserver.utils.CachedGuilds import space.mori.chzzk_bot.webserver.utils.DiscordGuildCache +import space.mori.chzzk_bot.webserver.utils.DiscordRatelimits import space.mori.chzzk_bot.webserver.utils.Guild import java.time.Duration @@ -287,21 +289,41 @@ data class DiscordGuildListAPI( ) suspend fun getDiscordUser(accessToken: String): DiscordMeAPI? { + while(!DiscordRatelimits.getRateLimit()) { + delay(DiscordRatelimits.getRateReset()) + } + val response: HttpResponse = applicationHttpClient.get("https://discord.com/api/oauth2/@me") { headers { append(HttpHeaders.Authorization, "Bearer $accessToken") } } + val rateLimit = response.headers["X-RateLimit-Limit"]?.toIntOrNull() + val remaining = response.headers["X-RateLimit-Remaining"]?.toIntOrNull() + val resetAfter = response.headers["X-RateLimit-Reset-After"]?.toDoubleOrNull()?.toLong() + + DiscordRatelimits.setRateLimit(rateLimit, remaining, resetAfter) + return response.body() } suspend fun getUserGuilds(accessToken: String): List { + while(!DiscordRatelimits.getRateLimit()) { + delay(DiscordRatelimits.getRateReset()) + } + val response = applicationHttpClient.get("https://discord.com/api/users/@me/guilds") { headers { append(HttpHeaders.Authorization, "Bearer $accessToken") } } + val rateLimit = response.headers["X-RateLimit-Limit"]?.toIntOrNull() + val remaining = response.headers["X-RateLimit-Remaining"]?.toIntOrNull() + val resetAfter = response.headers["X-RateLimit-Reset-After"]?.toDoubleOrNull()?.toLong() + + DiscordRatelimits.setRateLimit(rateLimit, remaining, resetAfter) + return response.body>() } \ No newline at end of file diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordGuildCache.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordGuildCache.kt index 010b3b7..7ced5d4 100644 --- a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordGuildCache.kt +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordGuildCache.kt @@ -41,12 +41,21 @@ object DiscordGuildCache { } } + val rateLimit = result.headers["X-RateLimit-Limit"]?.toIntOrNull() + val remaining = result.headers["X-RateLimit-Remaining"]?.toIntOrNull() + val resetAfter = result.headers["X-RateLimit-Reset-After"]?.toDoubleOrNull()?.toLong() + + DiscordRatelimits.setRateLimit(rateLimit, remaining, resetAfter) + return result.body>() } private suspend fun fetchAllGuilds() { var lastGuildId: String? = null while (true) { + while(!DiscordRatelimits.getRateLimit()) { + delay(DiscordRatelimits.getRateReset()) + } val guilds = fetchGuilds(lastGuildId) if (guilds.isEmpty()) { break diff --git a/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordRatelimits.kt b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordRatelimits.kt new file mode 100644 index 0000000..1e0d612 --- /dev/null +++ b/webserver/src/main/kotlin/space/mori/chzzk_bot/webserver/utils/DiscordRatelimits.kt @@ -0,0 +1,25 @@ +package space.mori.chzzk_bot.webserver.utils + +object DiscordRatelimits { + private var rateLimit = RateLimit(0, 0, 0L) + + fun getRateLimit(): Boolean { + return rateLimit.remainin != 0 + } + + fun getRateReset() = rateLimit.resetAfter + + private fun setRateLimit(rateLimit: RateLimit) { + this.rateLimit = rateLimit + } + + fun setRateLimit(limit: Int?, remaining: Int?, resetAfter: Long?) { + return setRateLimit(RateLimit(limit ?: 0, remaining ?: 0, resetAfter ?: 0L)) + } +} + +data class RateLimit( + val limit: Int, + val remainin: Int, + val resetAfter: Long, +) \ No newline at end of file