| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
1
|
|
|
1
|
|
277375
|
use v5.40; |
|
|
1
|
|
|
|
|
4
|
|
|
2
|
1
|
|
|
1
|
|
8
|
use feature 'class'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
252
|
|
|
3
|
1
|
|
|
1
|
|
9
|
no warnings 'experimental::class'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
634
|
|
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
class Algorithm::RateLimiter::TokenBucket v1.0.0 { |
|
6
|
|
|
|
|
|
|
field $limit : param : reader //= 0; # Bytes per second, 0 = unlimited |
|
7
|
|
|
|
|
|
|
field $tokens : reader = $limit; |
|
8
|
|
|
|
|
|
|
field $max_burst = $limit * 2; # Allow some burst, but not too much |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# |
|
11
|
|
|
|
|
|
|
method set_limit ($new_limit) { |
|
12
|
|
|
|
|
|
|
$limit = $new_limit; |
|
13
|
|
|
|
|
|
|
$max_burst = $limit * 2; |
|
14
|
|
|
|
|
|
|
} |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
method tick ($delta) { |
|
17
|
|
|
|
|
|
|
return if !$limit; |
|
18
|
|
|
|
|
|
|
$tokens += $limit * $delta; |
|
19
|
|
|
|
|
|
|
$tokens = $max_burst if $tokens > $max_burst; |
|
20
|
|
|
|
|
|
|
} |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
method consume ($amount) { |
|
23
|
|
|
|
|
|
|
return $amount if !$limit; |
|
24
|
|
|
|
|
|
|
my $allowed = ( $amount > $tokens ) ? $tokens : $amount; |
|
25
|
|
|
|
|
|
|
$allowed = 0 if $allowed < 0; |
|
26
|
|
|
|
|
|
|
$tokens -= $allowed; |
|
27
|
|
|
|
|
|
|
int $allowed; |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
method available () { $limit ? int($tokens) : 1_000_000_000 } # Near enough to infinity for a network transfer |
|
30
|
|
|
|
|
|
|
}; |
|
31
|
|
|
|
|
|
|
1; |