SauceNaoAPI/src/commonMain/kotlin/dev/inmo/saucenaoapi/utils/RequestQuotaManager.kt

102 lines
3.1 KiB
Kotlin
Raw Normal View History

2020-12-02 08:39:54 +00:00
package dev.inmo.saucenaoapi.utils
2019-10-12 06:30:02 +00:00
2022-05-14 07:44:44 +00:00
import com.soywiz.klock.DateTime
2020-12-02 08:39:54 +00:00
import dev.inmo.saucenaoapi.additional.LONG_TIME_RECALCULATING_MILLIS
import dev.inmo.saucenaoapi.additional.SHORT_TIME_RECALCULATING_MILLIS
import dev.inmo.saucenaoapi.exceptions.TooManyRequestsException
import dev.inmo.saucenaoapi.exceptions.TooManyRequestsLongException
import dev.inmo.saucenaoapi.models.Header
import dev.inmo.saucenaoapi.models.LimitsState
2019-10-12 06:30:02 +00:00
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlin.math.max
2019-10-12 06:30:02 +00:00
import kotlin.math.min
2019-12-13 18:29:12 +00:00
internal class RequestQuotaManager (
scope: CoroutineScope
2022-05-14 07:43:28 +00:00
) {
2019-10-12 06:30:02 +00:00
private var longQuota = 1
private var shortQuota = 1
private var longMaxQuota = 1
private var shortMaxQuota = 1
2019-12-13 18:29:12 +00:00
val limitsState: LimitsState
get() = LimitsState(
shortMaxQuota,
longMaxQuota,
shortQuota,
longQuota
)
2019-10-12 06:30:02 +00:00
private val quotaActions = Channel<suspend () -> Unit>(Channel.UNLIMITED)
private val quotaJob = scope.launch {
for (callback in quotaActions) {
callback()
}
2022-05-14 07:43:28 +00:00
}.also {
it.invokeOnCompletion {
quotaActions.close(it)
}
2019-10-12 06:30:02 +00:00
}
private suspend fun updateQuota(
newLongQuota: Int,
newShortQuota: Int,
newMaxLongQuota: Int?,
newMaxShortQuota: Int?,
timeManager: TimeManager
) {
2019-10-12 06:30:02 +00:00
quotaActions.send(
suspend {
longMaxQuota = newMaxLongQuota ?: longMaxQuota
shortMaxQuota = newMaxShortQuota ?: shortMaxQuota
2019-10-12 06:30:02 +00:00
longQuota = min(newLongQuota, longMaxQuota)
shortQuota = min(newShortQuota, shortMaxQuota)
2019-10-12 06:30:02 +00:00
when {
2019-12-13 16:45:10 +00:00
longQuota < 1 -> (timeManager.getMostOldestInLongPeriod() ?: DateTime.now()) + LONG_TIME_RECALCULATING_MILLIS
shortQuota < 1 -> (timeManager.getMostOldestInShortPeriod() ?: DateTime.now()) + SHORT_TIME_RECALCULATING_MILLIS
2019-10-12 06:30:02 +00:00
else -> null
} ?.also {
2019-12-13 16:45:10 +00:00
delay((it - DateTime.now()).millisecondsLong)
shortQuota = max(shortQuota, 1)
longQuota = max(longQuota, 1)
2019-10-12 06:30:02 +00:00
}
Unit
}
)
}
suspend fun updateQuota(header: Header, timeManager: TimeManager) = updateQuota(
header.longRemaining,
header.shortRemaining,
header.longLimit,
header.shortLimit,
timeManager
)
2019-12-13 18:21:12 +00:00
suspend fun happenTooManyRequests(timeManager: TimeManager, e: TooManyRequestsException) = updateQuota(
if (e is TooManyRequestsLongException) 0 else 1,
0,
null,
null,
timeManager
)
2019-10-12 06:30:02 +00:00
suspend fun getQuota() {
2022-05-14 07:43:28 +00:00
val job = Job()
lateinit var callback: suspend () -> Unit
callback = suspend {
if (longQuota > 0 && shortQuota > 0) {
job.complete()
} else {
quotaActions.send(callback)
2019-10-12 06:30:02 +00:00
}
}
2022-05-14 07:43:28 +00:00
quotaActions.trySend(callback)
return job.join()
2019-10-12 06:30:02 +00:00
}
}