Completed
Push — master ( dacea8...f619ab )
by Marcel
01:16
created

FixedWindowLimiter::getAdditionalData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace BeyondCode\FixedWindowLimiter;
4
5
use Carbon\CarbonInterval;
6
use Illuminate\Support\Facades\Redis;
7
use Illuminate\Redis\Connections\Connection;
8
9
class FixedWindowLimiter
10
{
11
    /** @var int */
12
    private $timeWindow;
13
14
    /** @var int */
15
    private $limit;
16
17
    public function __construct(CarbonInterval $timeWindow, int $limit)
18
    {
19
        $this->timeWindow = $timeWindow->totalSeconds;
0 ignored issues
show
Documentation Bug introduced by
The property $timeWindow was declared of type integer, but $timeWindow->totalSeconds is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
20
21
        $this->limit = $limit;
22
    }
23
24
    public static function create(CarbonInterval $timeWindow, int $limit): self
25
    {
26
        return new static($timeWindow, $limit);
27
    }
28
    
29
    public function attempt(string $resource): bool
30
    {
31
        $key = $this->buildKey($resource);
32
33
        $hits = $this->getConnection()->hincrby($key, 'attempts', 1);
34
35
        if ($hits === 1) {
36
            $this->getConnection()->expire($key, $this->timeWindow);
37
        }
38
39
        return $hits <= $this->limit;
40
    }
41
42
    public function getUsage(string $resource): int
43
    {
44
        $usage = (int)$this->getConnection()->hget($this->buildKey($resource), 'attempts');
45
46
        return min($this->limit, $usage);
47
    }
48
49
    public function getRemaining(string $resource): int
50
    {
51
        $remaining = $this->limit - $this->getUsage($resource);
52
53
        return max(0, $remaining);
54
    }
55
56
    private function getConnection(): Connection
57
    {
58
        return Redis::connection(config('limiter.connection'));
59
    }
60
61
    private function buildKey(string $resource): string
62
    {
63
        return config('limiter.prefix') . $resource;
64
    }
65
66
    public function getRealUsage(string $resource): int
67
    {
68
        return (int)$this->getConnection()->hget($this->buildKey($resource), 'attempts');
69
    }
70
71
    public function reset(string $resource, array $additionalData = [])
72
    {
73
        $key = $this->buildKey($resource);
74
75
        $this->getConnection()->hset($key, 'attempts', 0);
76
77
        foreach ($additionalData as $field => $value) {
78
            $this->getConnection()->hset($key, $field, $value);
79
        }
80
81
        $this->getConnection()->expire($key, $this->timeWindow);
82
    }
83
84
    public function getAdditionalData(string $resource, string $key)
85
    {
86
        return $this->getConnection()->hget($this->buildKey($resource), $key);
87
    }
88
}
89