tokenBucket   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 269
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 77
c 3
b 0
f 0
dl 0
loc 269
rs 9.84
wmc 32

17 Methods

Rating   Name   Duplication   Size   Complexity  
A capacity() 0 7 2
A fill() 0 3 1
A pour() 0 5 1
A leak() 0 11 4
A __construct() 0 3 1
A getLeakage() 0 3 1
A pause() 0 3 1
A timeNow() 0 3 1
A refill() 0 15 2
B setLeakRate() 0 41 10
A setTimeframe() 0 4 1
A getDrops() 0 6 2
A getTimeframe() 0 3 1
A getCapacity() 0 3 1
A getTokenData() 0 6 1
A setCapacity() 0 4 1
A full() 0 4 1
1
<?php
2
/**
3
 * ==================================
4
 * Responsible PHP API
5
 * ==================================
6
 *
7
 * @link Git https://github.com/vince-scarpa/responsibleAPI.git
8
 *
9
 * @api Responible API
10
 * @package responsible\core\throttle
11
 *
12
 * @author Vince scarpa <[email protected]>
13
 *
14
 */
15
namespace responsible\core\throttle;
16
17
class tokenBucket
18
{
19
    /**
20
     * [$capacity The Buckets limit]
21
     * @var integer
22
     */
23
    private $capacity;
24
25
    /**
26
     * [$drops How many drops in a bucket]
27
     * @var integer
28
     */
29
    private $drops = 0;
30
31
    /**
32
     * [$leakage Leak rate]
33
     * @var float
34
     */
35
    private $leakage;
36
37
    /**
38
     * [$lastAccess Timestamp of lat access]
39
     * @var integer
40
     */
41
    private $lastAccess;
42
43
    /**
44
     * [$timeframe The window timeframe]
45
     * @var integer|string
46
     */
47
    private $timeframe;
48
49
    /**
50
     * [$pauseAccess Pause access for a given period]
51
     * @var boolean
52
     */
53
    private $pauseAccess = false;
54
55
    /**
56
     * [__construct Set the last access this overridden if already accessed]
57
     */
58
    public function __construct()
59
    {
60
        $this->lastAccess = $this->timeNow();
61
    }
62
63
    /**
64
     * [capacity Check if the bucket can still be filled]
65
     * @return boolean
66
     */
67
    public function capacity()
68
    {
69
        if ($this->full()) {
70
            $this->leak();
71
        }
72
73
        return (floor($this->drops) < $this->capacity);
74
    }
75
76
    /**
77
     * [leak Create a leak in the bucket]
78
     * @return void
79
     */
80
    public function leak()
81
    {
82
        $now = $this->timeNow();
83
        $difference = $now - $this->lastAccess;
84
85
        if ($difference > 0 && $this->getLeakage() > 0) {
86
            $this->drops -= ($difference * $this->leakage);
87
            $this->lastAccess = $now;
88
89
            if ($this->drops < 0) {
90
                $this->drops = 0;
91
            }
92
        }
93
    }
94
95
    /**
96
     * [pour Pour drops in the bucket, essentially filling the bucket with drops]
97
     * @param  integer $drops
98
     * @param  integer $lastAccess
99
     * @return self
100
     */
101
    public function pour($drops, $lastAccess)
102
    {
103
        $this->fill($drops);
104
        $this->lastAccess = $lastAccess;
105
        return $this;
106
    }
107
108
    /**
109
     * [fill fill the bucket with drops]
110
     * @param integer $drops
111
     */
112
    public function fill($drops = 1)
113
    {
114
        $this->drops += $drops;
115
    }
116
117
    /**
118
     * [full Check if the bucket is full]
119
     * @return boolean
120
     */
121
    public function full()
122
    {
123
        $isFull = ceil($this->drops) >= $this->capacity;
124
        return $isFull;
125
    }
126
127
    /**
128
     * [refill Refill the bucket tokens]
129
     * @return array|boolean
130
     */
131
    public function refill($accessed)
132
    {
133
        $now = $this->timeNow();
134
        $difference = $now - $accessed;
135
136
        if (($difference + 1) > $this->getTimeframe()) {
137
            $this->drops = 0;
138
            $this->lastAccess = $now;
139
            return [
140
                'drops' => $this->drops,
141
                'time' => $this->lastAccess,
142
                'pauseAccess' => $this->pauseAccess,
143
            ];
144
        }
145
        return;
146
    }
147
148
    /**
149
     * [pause Pause access to the bucket]
150
     * @param  boolean $state
151
     */
152
    public function pause($state = false)
153
    {
154
        $this->pauseAccess = $state;
155
    }
156
157
    /**
158
     * [timeNow Create a timestamp of now]
159
     * @return integer
160
     */
161
    public function timeNow()
162
    {
163
        return (new \DateTime('now'))->getTimestamp();
164
    }
165
166
    /**
167
     * [setCapacity Set the buckets overall capacity]
168
     * @param integer $capacity
169
     * @return self
170
     */
171
    public function setCapacity($capacity)
172
    {
173
        $this->capacity = $capacity;
174
        return $this;
175
    }
176
177
    /**
178
     * [setLeakRate Set the buckets leak rate]
179
     * @param string|integer $leakRate
180
     * @return self
181
     */
182
    public function setLeakRate($leakRate = null)
183
    {
184
        $capacity = $this->getCapacity();
185
        $timeframe = $this->getTimeframe();
186
187
        if (!is_null($leakRate)) {
188
            if (is_string($leakRate)) {
189
                switch ($leakRate) {
190
                    case 'slow':
191
                        $this->leakage = ($capacity / $timeframe) / 4;
192
                        break;
193
194
                    case 'medium':
195
                        $this->leakage = (($capacity / $timeframe) / 2);
196
                        break;
197
198
                    case 'normal':
199
                    case 'default':
200
                        $this->leakage = ($capacity / $timeframe);
201
                        break;
202
203
                    case 'fast':
204
                        $this->leakage = 1;
205
                        break;
206
207
                    default:
208
                        $this->leakage = ($capacity / $timeframe);
209
                        break;
210
                }
211
            }
212
213
            if (is_numeric($leakRate)) {
214
                $nLeakRate = $leakRate;
215
                if ($nLeakRate < 0) {
216
                    $nLeakRate = 0;
217
                }
218
                $this->leakage = (float)$nLeakRate;
219
            }
220
        }
221
222
        return $this;
223
    }
224
225
    /**
226
     * [setTimeframe Set the buckets window access]
227
     * @param string|integer $timeframe
228
     */
229
    public function setTimeframe($timeframe)
230
    {
231
        $this->timeframe = $timeframe;
232
        return $this;
233
    }
234
235
    /**
236
     * [getCapacity Get capacity]
237
     * @return integer
238
     */
239
    public function getCapacity()
240
    {
241
        return $this->capacity;
242
    }
243
244
    /**
245
     * [getLeakage Get the buckets leak rate]
246
     * @return integer|float
247
     */
248
    public function getLeakage()
249
    {
250
        return $this->leakage;
251
    }
252
253
    /**
254
     * [getDrops Get the buckets current drops]
255
     * @param  boolean $leak
256
     * @return integer
257
     */
258
    public function getDrops($leak = true)
259
    {
260
        if ($leak) {
261
            $this->leak();
262
        }
263
        return $this->drops;
264
    }
265
266
    /**
267
     * [getTokenData Get the token data]
268
     * @return array
269
     */
270
    public function getTokenData()
271
    {
272
        return [
273
            'drops' => floor($this->getDrops()),
274
            'time' => $this->lastAccess,
275
            'pauseAccess' => $this->pauseAccess,
276
        ];
277
    }
278
279
    /**
280
     * [getTimeframe Get the buckets window timeframe]
281
     * @return string|integer
282
     */
283
    public function getTimeframe()
284
    {
285
        return $this->timeframe;
286
    }
287
}
288