2020-12-02 08:39:54 +00:00
|
|
|
package dev.inmo.saucenaoapi.utils
|
2019-10-12 06:30:02 +00:00
|
|
|
|
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-12-12 18:47:52 +00:00
|
|
|
import com.soywiz.klock.DateTime
|
2019-10-12 06:30:02 +00:00
|
|
|
import kotlinx.coroutines.*
|
|
|
|
import kotlinx.coroutines.channels.Channel
|
|
|
|
import kotlin.coroutines.suspendCoroutine
|
2019-10-12 08:05:47 +00:00
|
|
|
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
|
2020-08-29 13:09:54 +00:00
|
|
|
) : SauceCloseable {
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-12 07:43:28 +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 {
|
2019-10-12 07:43:28 +00:00
|
|
|
longMaxQuota = newMaxLongQuota ?: longMaxQuota
|
|
|
|
shortMaxQuota = newMaxShortQuota ?: shortMaxQuota
|
2019-10-12 06:30:02 +00:00
|
|
|
|
2019-10-12 07:43:28 +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
|
2019-10-12 08:05:47 +00:00
|
|
|
} ?.also {
|
2019-12-13 16:45:10 +00:00
|
|
|
delay((it - DateTime.now()).millisecondsLong)
|
2019-10-12 08:05:47 +00:00
|
|
|
shortQuota = max(shortQuota, 1)
|
|
|
|
longQuota = max(longQuota, 1)
|
2019-10-12 06:30:02 +00:00
|
|
|
}
|
|
|
|
Unit
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-10-12 07:43:28 +00:00
|
|
|
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,
|
2019-10-12 07:43:28 +00:00
|
|
|
0,
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
timeManager
|
|
|
|
)
|
|
|
|
|
2019-10-12 06:30:02 +00:00
|
|
|
suspend fun getQuota() {
|
|
|
|
return suspendCoroutine {
|
|
|
|
lateinit var callback: suspend () -> Unit
|
|
|
|
callback = suspend {
|
|
|
|
if (longQuota > 0 && shortQuota > 0) {
|
|
|
|
it.resumeWith(Result.success(Unit))
|
|
|
|
} else {
|
|
|
|
quotaActions.send(callback)
|
|
|
|
}
|
|
|
|
}
|
2021-05-26 16:16:08 +00:00
|
|
|
quotaActions.trySend(callback)
|
2019-10-12 06:30:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun close() {
|
|
|
|
quotaJob.cancel()
|
|
|
|
quotaActions.close()
|
|
|
|
}
|
|
|
|
}
|