1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2024-06-03 00:15:27 +00:00
tgbotapi/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/bot/settings/limiters/PowLimiter.kt

71 lines
2.1 KiB
Kotlin
Raw Normal View History

2020-10-04 11:06:30 +00:00
package dev.inmo.tgbotapi.bot.settings.limiters
2019-01-24 02:35:38 +00:00
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
2019-04-13 02:21:19 +00:00
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
2019-01-24 02:35:38 +00:00
import kotlin.coroutines.*
2019-12-03 05:07:25 +00:00
import kotlin.math.pow
2019-01-24 02:35:38 +00:00
private sealed class RequestEvent
private class AddRequest(
val continuation: Continuation<Long>
) : RequestEvent()
private object CompleteRequest : RequestEvent()
@Serializable
data class PowLimiter(
private val minAwaitTime: Long = 0L,
private val maxAwaitTime: Long = 10000L,
private val powValue: Double = 4.0,
private val powK: Double = 0.0016
) : RequestLimiter {
2019-01-24 03:49:27 +00:00
@Transient
2019-12-03 05:07:25 +00:00
private val scope = CoroutineScope(Dispatchers.Default)
2019-01-24 03:49:27 +00:00
@Transient
2019-01-24 02:35:38 +00:00
private val eventsChannel = Channel<RequestEvent>(Channel.UNLIMITED)
2019-01-24 03:49:27 +00:00
@Transient
2019-01-24 02:35:38 +00:00
private val awaitTimeRange = minAwaitTime .. maxAwaitTime
init {
scope.launch {
var requestsInWork: Double = 0.0
for (event in eventsChannel) {
when (event) {
is AddRequest -> {
2019-12-03 05:07:25 +00:00
val awaitTime = (((requestsInWork.pow(powValue) * powK) * 1000L).toLong())
2019-01-24 02:35:38 +00:00
requestsInWork++
event.continuation.resume(
if (awaitTime in awaitTimeRange) {
awaitTime
} else {
if (awaitTime < minAwaitTime) {
minAwaitTime
} else {
maxAwaitTime
}
}
)
}
is CompleteRequest -> requestsInWork--
}
}
}
}
override suspend fun <T> limit(
block: suspend () -> T
): T {
val delayMillis = suspendCoroutine<Long> {
scope.launch { eventsChannel.send(AddRequest(it)) }
}
delay(delayMillis)
return try {
block()
} finally {
eventsChannel.send(CompleteRequest)
}
}
}