Issues (2)

src/RateLimiter.php (2 issues)

1
<?php
2
3
namespace Asiadevmedia\GuzzleRateLimiter;
4
5
class RateLimiter
6
{
7
    const TIME_FRAME_MINUTE = 'minute';
8
    const TIME_FRAME_SECOND = 'second';
9
10
    /** @var int */
11
    protected $limit;
12
13
    /** @var string */
14
    protected $timeFrame;
15
16
    /** @var \Asiadevmedia\RateLimiter\Store */
0 ignored issues
show
The type Asiadevmedia\RateLimiter\Store was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
    protected $store;
18
19
    /** @var \Asiadevmedia\GuzzleRateLimiter\Deferrer */
20
    protected $deferrer;
21
22
    public function __construct(
23
        int $limit,
24
        string $timeFrame,
25
        Store $store,
26
        Deferrer $deferrer
27
    ) {
28
        $this->limit = $limit;
29
        $this->timeFrame = $timeFrame;
30
        $this->store = $store;
0 ignored issues
show
Documentation Bug introduced by
It seems like $store of type Asiadevmedia\GuzzleRateLimiter\Store is incompatible with the declared type Asiadevmedia\RateLimiter\Store of property $store.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
31
        $this->deferrer = $deferrer;
32
    }
33
34
    public function handle(callable $callback)
35
    {
36
        $delayUntilNextRequest = $this->delayUntilNextRequest();
37
38
        if ($delayUntilNextRequest > 0) {
39
            $this->deferrer->sleep($delayUntilNextRequest);
40
        }
41
42
        $this->store->push(
43
            $this->deferrer->getCurrentTime(),
44
            $this->limit
45
        );
46
47
        return $callback();
48
    }
49
50
    protected function delayUntilNextRequest(): int
51
    {
52
        $currentTimeFrameStart = $this->deferrer->getCurrentTime() - $this->timeFrameLengthInMilliseconds();
53
54
        $requestsInCurrentTimeFrame = array_values(array_filter(
55
            $this->store->get(),
56
            function (int $timestamp) use ($currentTimeFrameStart) {
57
                return $timestamp >= $currentTimeFrameStart;
58
            }
59
        ));
60
61
        if (count($requestsInCurrentTimeFrame) < $this->limit) {
62
            return 0;
63
        }
64
65
        $oldestRequestStartTimeRelativeToCurrentTimeFrame =
66
            $this->deferrer->getCurrentTime() - $requestsInCurrentTimeFrame[0];
67
68
        return $this->timeFrameLengthInMilliseconds() - $oldestRequestStartTimeRelativeToCurrentTimeFrame;
69
    }
70
71
    protected function timeFrameLengthInMilliseconds(): int
72
    {
73
        if ($this->timeFrame === self::TIME_FRAME_MINUTE) {
74
            return 60 * 1000;
75
        }
76
77
        return 1000;
78
    }
79
}
80