ThrottlingService   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 55
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 8
eloc 19
dl 0
loc 55
c 4
b 0
f 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A setAllowedRequestsPerSecond() 0 3 1
A validateRate() 0 23 5
A setIp() 0 3 1
A __construct() 0 2 1
1
<?php
2
3
namespace Gvera\Services;
4
5
use Exception;
6
use Gvera\Cache\Cache;
7
use Gvera\Cache\FilesCache;
8
use Gvera\Cache\RedisClientCache;
9
use Gvera\Exceptions\InvalidArgumentException;
10
use Gvera\Exceptions\ThrottledException;
11
12
class ThrottlingService
13
{
14
    const PREFIX_THROTTLING = 'gv_throttling_';
15
    /**
16
     * @var int
17
     * By default 4 requests per second.
18
     */
19
    private int $allowedRequestsPerSecond = 4;
20
    /**
21
     * @var string
22
     */
23
    private $ip;
24
25
    public function __construct()
26
    {
27
    }
28
29
    /**
30
     * @throws ThrottledException
31
     * @throws InvalidArgumentException
32
     * @throws Exception
33
     */
34
    public function validateRate()
35
    {
36
        if (!isset($this->ip)) {
37
            throw new \InvalidArgumentException('Unable to validate throttling without ip');
38
        }
39
        
40
        $cache = Cache::getCache();
41
42
        if (!is_a($cache, RedisClientCache::class)) {
43
            return;
44
        }
45
46
        $key = self::PREFIX_THROTTLING . $this->ip;
47
        if ($cache->exists($key)) {
48
            $last = $cache->load($key);
49
            $current = microtime(true);
50
            $sec =  abs($last - $current);
51
            if ($sec <= (1 / $this->allowedRequestsPerSecond)) {
52
                throw new ThrottledException('request not allowed', ['ip' => $this->ip]);
53
            }
54
        }
55
        
56
        $cache->save($key, microtime(true), 10);
57
    }
58
    
59
    public function setIp(string $ip)
60
    {
61
        $this->ip = $ip;
62
    }
63
    
64
    public function setAllowedRequestsPerSecond($rps)
65
    {
66
        $this->allowedRequestsPerSecond = $rps;
67
    }
68
}
69