Skip to content

Commit

Permalink
Don't use value class Reset with AtomicRef (#863)
Browse files Browse the repository at this point in the history
The use of value classes for the Reset class has already caused issues
implementing #855. However, it was isolated to native platforms.
Unfortunately, this behavior will become a compiler error soon, so we
need to change it. This can be achieved by simply using the backing
Instant instead of Reset with AtomicRef.

Related Issues:
#855
#69
Kotlin/kotlinx-atomicfu#291
https://youtrack.jetbrains.com/issue/KT-61584

Co-authored-by: lukellmann <[email protected]>
  • Loading branch information
DRSchlaubi and lukellmann authored Sep 3, 2023
1 parent ffa8390 commit 7ae3daf
Showing 1 changed file with 7 additions and 7 deletions.
14 changes: 7 additions & 7 deletions rest/src/commonMain/kotlin/ratelimit/AbstractRateLimiter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@ import dev.kord.rest.request.Request
import dev.kord.rest.request.RequestIdentifier
import dev.kord.rest.request.identifier
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.update
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.delay
import kotlinx.coroutines.sync.Mutex
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import mu.KLogger
import kotlin.time.Duration.Companion.minutes

public abstract class AbstractRateLimiter internal constructor(public val clock: Clock) : RequestRateLimiter {
internal abstract val logger: KLogger

private val autoBanRateLimiter = IntervalRateLimiter(limit = 25000, interval = 10.minutes)
private val globalSuspensionPoint = atomic(Reset(clock.now()))
private val globalSuspensionPoint = atomic(clock.now())
internal val buckets = ConcurrentHashMap<BucketKey, Bucket>()
private val routeBuckets = ConcurrentHashMap<RequestIdentifier, MutableSet<BucketKey>>()

internal val BucketKey.bucket get() = buckets.getOrPut(this) { Bucket(this) }
private val Request<*, *>.buckets get() = routeBuckets[identifier].orEmpty().map { it.bucket }
internal fun RequestIdentifier.addBucket(id: BucketKey) = routeBuckets.getOrPut(this) { mutableSetOf() }.add(id)

internal suspend fun Reset.await() {
val duration = value - clock.now()
private suspend fun Instant.await() {
val duration = this - clock.now()
if (duration.isNegative()) return
delay(duration)
}
Expand Down Expand Up @@ -67,7 +67,7 @@ public abstract class AbstractRateLimiter internal constructor(public val clock:
when (response) {
is RequestResponse.GlobalRateLimit -> {
logger.trace { "[RATE LIMIT]:[GLOBAL]:exhausted until ${response.reset.value}" }
globalSuspensionPoint.update { response.reset }
globalSuspensionPoint.value = response.reset.value
}
is RequestResponse.BucketRateLimit -> {
logger.trace { "[RATE LIMIT]:[BUCKET]:Bucket ${response.bucketKey.value} was exhausted until ${response.reset.value}" }
Expand All @@ -83,7 +83,7 @@ public abstract class AbstractRateLimiter internal constructor(public val clock:
}

internal inner class Bucket(val id: BucketKey) {
private val reset = atomic(Reset(clock.now()))
private val reset = atomic(clock.now())
private val mutex = Mutex()

suspend fun awaitAndLock() {
Expand All @@ -93,7 +93,7 @@ public abstract class AbstractRateLimiter internal constructor(public val clock:
}

fun updateReset(newValue: Reset) {
reset.update { newValue }
reset.value = newValue.value
}

fun unlock() = mutex.unlock()
Expand Down

0 comments on commit 7ae3daf

Please sign in to comment.