Completed
Push — master ( d6870c...9a821e )
by Krishnaprasad
05:41 queued 02:32
created

FixedWindowThrottler::getTimeCacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * The MIT License (MIT)
4
 *
5
 * Copyright (c) 2015 Krishnaprasad MG <[email protected]>
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 */
25
26
namespace Sunspikes\Ratelimit\Throttle\Throttler;
27
28
use Sunspikes\Ratelimit\Cache\Exception\ItemNotFoundException;
29
30
final class FixedWindowThrottler extends AbstractWindowThrottler implements RetriableThrottlerInterface
31
{
32
    const CACHE_KEY_TIME = ':time';
33
    const CACHE_KEY_HITS = ':hits';
34
35
    /**
36
     * @var int|null
37
     */
38
    private $hitCount;
39
40
    /**
41
     * @inheritdoc
42
     */
43 12
    public function hit()
44
    {
45 12
        $this->setCachedHitCount($this->count() + 1);
46
47
        // Update the window start time if the previous window has passed, or no cached window exists
48
        try {
49 12
            if (($this->timeProvider->now() - $this->cache->get($this->getTimeCacheKey())) > $this->timeLimit) {
50 1
                $this->cache->set($this->getTimeCacheKey(), $this->timeProvider->now(), $this->cacheTtl);
51 1
            }
52 12
        } catch (ItemNotFoundException $exception) {
53 11
            $this->cache->set($this->getTimeCacheKey(), $this->timeProvider->now(), $this->cacheTtl);
54
        }
55
56 12
        return $this;
57
    }
58
59
    /**
60
     * @inheritdoc
61
     */
62 18
    public function count()
63
    {
64
        try {
65 18
            if (($this->timeProvider->now() - $this->cache->get($this->getTimeCacheKey())) > $this->timeLimit) {
66 5
                return 0;
67
            }
68
69 13
            return $this->getCachedHitCount();
70 12
        } catch (ItemNotFoundException $exception) {
71 12
            return 0;
72
        }
73
    }
74
75
    /**
76
     * @inheritdoc
77
     */
78 3
    public function clear()
79
    {
80 3
        $this->setCachedHitCount(0);
81 3
        $this->cache->set($this->getTimeCacheKey(), $this->timeProvider->now(), $this->cacheTtl);
82 3
    }
83
84
    /**
85
     * @inheritdoc
86
     */
87 7
    public function getRetryTimeout()
88
    {
89 7
        if ($this->check()) {
90 6
            return 0;
91
        }
92
93
        // Return the time until the current window ends
94
        // Try/catch for the ItemNotFoundException is not required, in that case $this->check() will return true
95 2
        $cachedTime = $this->cache->get($this->getTimeCacheKey());
96
97 2
        return self::SECOND_TO_MILLISECOND_MULTIPLIER * ($this->timeLimit - $this->timeProvider->now() + $cachedTime);
98
    }
99
100
    /**
101
     * @return int
102
     *
103
     * @throws ItemNotFoundException
104
     */
105 13
    private function getCachedHitCount()
106
    {
107 13
        if (null !== $this->hitCount) {
108 11
            return $this->hitCount;
109
        }
110
111 2
        return $this->cache->get($this->getHitsCacheKey());
112
    }
113
114
    /**
115
     * @param int $hitCount
116
     */
117 13
    private function setCachedHitCount($hitCount)
118
    {
119 13
        $this->hitCount = $hitCount;
120 13
        $this->cache->set($this->getHitsCacheKey(), $hitCount, $this->cacheTtl);
121 13
    }
122
123
    /**
124
     * @return string
125
     */
126 15
    private function getHitsCacheKey()
127
    {
128 15
        return $this->key.self::CACHE_KEY_HITS;
129
    }
130
131
    /**
132
     * @return string
133
     */
134 19
    private function getTimeCacheKey()
135
    {
136 19
        return $this->key.self::CACHE_KEY_TIME;
137
    }
138
}
139