@@ -19,7 +19,7 @@ class RateLimit(config: RateLimitConfig) extends Directive0 with Json4sSupport {
19
19
private implicit val serialization : Serialization = native.Serialization
20
20
private implicit val formats : Formats = DefaultFormats + JsonSerializers .RpcErrorJsonSerializer
21
21
22
- protected def getCurrentTimeNanos : Long = System .nanoTime()
22
+ private [ this ] lazy val minInterval = config.minRequestInterval.toSeconds
23
23
24
24
private [this ] lazy val lru = {
25
25
val nanoDuration = config.minRequestInterval.toNanos
@@ -35,26 +35,30 @@ class RateLimit(config: RateLimitConfig) extends Directive0 with Json4sSupport {
35
35
.build[RemoteAddress , NotUsed ]()
36
36
}
37
37
38
+ private [this ] def isBelowRateLimit (ip : RemoteAddress ): Boolean = {
39
+ var exists = true
40
+ lru.get(
41
+ ip,
42
+ () => {
43
+ exists = false
44
+ NotUsed
45
+ }
46
+ )
47
+ exists
48
+ }
49
+
50
+ // Override this to test
51
+ protected def getCurrentTimeNanos : Long = System .nanoTime()
52
+
38
53
// Such algebras prevent if-elseif-else boilerplate in the JsonRPCServer code
39
54
// It is also guaranteed that:
40
55
// 1) no IP address is extracted unless config.enabled is true
41
56
// 2) no LRU is created unless config.enabled is true
42
57
// 3) cache is accessed only once (using get)
43
58
override def tapply (f : Unit => Route ): Route = {
44
59
if (config.enabled) {
45
- val minInterval = config.minRequestInterval.toSeconds
46
60
extractClientIP { ip =>
47
- var exists = true
48
- // We can avoid using var
49
- // But in this case we access our LRU twice.
50
- lru.get(
51
- ip,
52
- () => {
53
- exists = false
54
- NotUsed
55
- }
56
- )
57
- if (exists) {
61
+ if (isBelowRateLimit(ip)) {
58
62
val err = JsonRpcError .RateLimitError (minInterval)
59
63
complete((StatusCodes .TooManyRequests , err))
60
64
} else {
0 commit comments