1package com.example.http
2
3import java.util.concurrent.ConcurrentHashMap
4import java.util.concurrent.atomic.AtomicLong
5import java.util.concurrent.locks.ReentrantLock
6import kotlin.time.Duration.Companion.seconds
7
8
9class RateLimiter(private val capacity: Int, private val refillRate: Int, private val timeWindowSeconds: Int) {
10
11private val tokens = ConcurrentHashMap<String, AtomicLong>()
12private val lastRefillTime = ConcurrentHashMap<String, AtomicLong>()
13private val lock = ReentrantLock()
14
15
16private fun getTokenCount(key: String): AtomicLong {
17return tokens.computeIfAbsent(key) { AtomicLong(capacity.toLong()) }
18}
19
20
21private fun getLastRefillTime(key: String): AtomicLong {
22return lastRefillTime.computeIfAbsent(key) { AtomicLong(System.currentTimeMillis()) }
23}
24
25
26private fun refillTokens(key: String) {
27lock.lock()
28try {
29val currentTime = System.currentTimeMillis()
30val elapsedTimeMs = currentTime - getLastRefillTime(key).get()
31val tokensToRefill = (elapsedTimeMs / 1000.0 * refillRate).toInt().coerceAtMost(capacity - getTokenCount(key).get())
32
33if (tokensToRefill > 0) {
34getTokenCount(key).addAndGet(tokensToRefill.toLong())
35getLastRefillTime(key).set(currentTime)
36}
37} finally {
38lock.unlock()
39}
40}
41
42
43fun tryConsume(key: String): Boolean {
44refillTokens(key)
45val currentTokens = getTokenCount(key)
46if (currentTokens.get() > 0) {
47return currentTokens.decrementAndGet() >= 0
48}
49return false
50}
51
52
53fun isRateLimited(key: String): Boolean {
54return !tryConsume(key)
55}
56}
57
58
59class RateLimiterMiddleware(private val limiter: RateLimiter) {
60
61
62fun handle(request: HttpRequest): HttpResponse {
63val clientIdentifier = request.headers["X-Client-ID"] ?: "anonymous"
64
65if (limiter.isRateLimited(clientIdentifier)) {
66return HttpResponse.tooManyRequests("Rate limit exceeded for client: $clientIdentifier")
67}
68
69
70return HttpResponse.ok("Request processed successfully.")
71}
72}
73
74
75data class HttpRequest(val method: String, val path: String, val headers: Map<String, String>)
76
77sealed class HttpResponse(val statusCode: Int, val body: String) {
78data class Ok(val responseBody: String) : HttpResponse(200, responseBody)
79data class TooManyRequests(val errorMessage: String) : HttpResponse(429, errorMessage)
80
81companion object {
82fun ok(body: String): HttpResponse = Ok(body)
83fun tooManyRequests(message: String): HttpResponse = TooManyRequests(message)
84}
85}
86
87fun main() {
88
89val rateLimiter = RateLimiter(capacity = 10, refillRate = 5, timeWindowSeconds = 60)
90val middleware = RateLimiterMiddleware(rateLimiter)
91
92
93val request1 = HttpRequest("GET", "/api/data", mapOf("X-Client-ID" to "user1"))
94val request2 = HttpRequest("GET", "/api/data", mapOf("X-Client-ID" to "user1"))
95val request3 = HttpRequest("GET", "/api/data", mapOf("X-Client-ID" to "user2"))
96
97println("Request 1: ${middleware.handle(request1)}")
98println("Request 2: ${middleware.handle(request2)}")
99println("Request 3: ${middleware.handle(request3)}")
100
101
102for (i in 1..12) {
103val req = HttpRequest("GET", "/api/data", mapOf("X-Client-ID" to "user1"))
104println("Burst Request ${i}: ${middleware.handle(req)}")
105}
106
107
108Thread.sleep(2000)
109println("Request after delay: ${middleware.handle(request1)}")
110}