Completed
Pull Request — master (#355)
by
unknown
03:30
created

DefaultProfile::saveMinuteLimit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Picqer\Laravel\Exact;
4
5
use Illuminate\Support\Facades\Cache;
6
use Illuminate\Support\Str;
7
8
class DefaultProfile
9
{
10
    
11
    /**
12
     * @var string
13
     */
14
    protected $limit_cache_name = 'picqer_minute_limit';
15
    
16
    /**
17
     * @var string
18
     */
19
    protected $token_lock_name = 'picqer_exact_token_lock';
20
    
21
    /**
22
     * @var string
23
     */
24
    protected $token_history_name = 'picqer_exact_token_history';
25
    
26
    /**
27
     * @var string
28
     */
29
    protected $token_last_value = 'picqer_exact_token_last';
30
    
31
    /**
32
     * @var string
33
     */
34
    protected $limit_lock_name = 'picqer_exact_limit_lock';
35
    
36
    /**
37
     * @var
38
     */
39
    protected $acquiring_lock_tries = 0;
40
    
41
    /**
42
     * @param string $response_timestamp
43
     * @param string $refresh_token
44
     * @param string $access_token
45
     *
46
     * @return bool
47
     * @throws \Exception
48
     */
49
    public function handleNewTokens($response_timestamp, $refresh_token, $access_token)
50
    {
51
        $this->resetAcquiringLockTries();
52
        if($this->acquireLock($this->token_lock_name) === false) {
53
            throw new \Exception('Could not acquire lock..');
54
        }
55
        
56
        $refreshed = false;
57
        if($this->isNewRefreshToken($response_timestamp, $refresh_token)) {
58
            $this->saveNewTokens($response_timestamp, $refresh_token, $access_token);
59
            $this->saveTokenToHistory($response_timestamp, $refresh_token, $access_token);
60
            $this->saveLastToken($refresh_token);
61
    
62
            $refreshed = true;
63
        }
64
        
65
        $this->releaseLock($this->token_lock_name);
66
        
67
        return $refreshed;
68
    }
69
    
70
    /**
71
     * @param $fallback_token
72
     *
73
     * @return string
74
     * @throws \Exception
75
     */
76
    public function getLatestRefreshToken($fallback_token)
77
    {
78
        if($this->acquireLock($this->token_lock_name) === false) {
79
            throw new \Exception('Could not acquire lock..');
80
        }
81
        
82
        $return = Cache::get($this->token_last_value, $fallback_token);
83
        $this->releaseLock($this->token_lock_name);
84
        return $return;
85
    }
86
    
87
    /**
88
     * @param $response_timestamp
89
     * @param $refresh_token
90
     *
91
     * @return bool
92
     */
93
    protected function isNewRefreshToken($response_timestamp, $refresh_token)
94
    {
95
        $tokens = Cache::get($this->token_history_name, []);
96
        
97
        foreach($tokens as $token) {
98
            if($token['refresh_token'] === $refresh_token) {
99
                return false;
100
            }
101
            if($token['time'] > $response_timestamp) {
102
                return false;
103
            }
104
        }
105
        
106
        return true;
107
    }
108
    
109
    /**
110
     * @param $response_timestamp
111
     * @param $refresh_token
112
     * @param $access_token
113
     */
114
    protected function saveTokenToHistory($response_timestamp, $refresh_token, $access_token)
115
    {
116
        $history = Cache::get($this->token_history_name, []);
117
        
118
        $merged_history = array_merge($history, [
119
            [
120
                'refresh_token' => $refresh_token,
121
                'access_token'  => $access_token,
122
                'time'          => $response_timestamp,
123
            ]
124
        ]);
125
        
126
        Cache::put($this->token_history_name, $merged_history, date('Y-m-d H:i:s', strtotime('+2 minutes')));
0 ignored issues
show
Bug introduced by
date('Y-m-d H:i:s', strtotime('+2 minutes')) of type string is incompatible with the type DateInterval|DateTimeInterface|integer expected by parameter $ttl of Illuminate\Support\Facades\Cache::put(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

126
        Cache::put($this->token_history_name, $merged_history, /** @scrutinizer ignore-type */ date('Y-m-d H:i:s', strtotime('+2 minutes')));
Loading history...
127
    }
128
    
129
    /**
130
     * @param string $refresh_token
131
     */
132
    protected function saveLastToken($refresh_token)
133
    {
134
        Cache::put($this->token_last_value, $refresh_token, date('Y-m-d H:i:s', strtotime('+2 minutes')));
0 ignored issues
show
Bug introduced by
date('Y-m-d H:i:s', strtotime('+2 minutes')) of type string is incompatible with the type DateInterval|DateTimeInterface|integer expected by parameter $ttl of Illuminate\Support\Facades\Cache::put(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
        Cache::put($this->token_last_value, $refresh_token, /** @scrutinizer ignore-type */ date('Y-m-d H:i:s', strtotime('+2 minutes')));
Loading history...
135
    }
136
    
137
    /**
138
     * @param string $response_time
139
     * @param string $refresh_token
140
     * @param string $access_token
141
     *
142
     * @throws \Exception
143
     */
144
    protected function saveNewTokens($response_time, $refresh_token, $access_token)
0 ignored issues
show
Unused Code introduced by
The parameter $response_time is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

144
    protected function saveNewTokens(/** @scrutinizer ignore-unused */ $response_time, $refresh_token, $access_token)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $access_token is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

144
    protected function saveNewTokens($response_time, $refresh_token, /** @scrutinizer ignore-unused */ $access_token)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $refresh_token is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

144
    protected function saveNewTokens($response_time, /** @scrutinizer ignore-unused */ $refresh_token, $access_token)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
145
    {
146
        // save all received tokens so we can't
147
        // save an old token after the process paused
148
        
149
        // todo: implement method for saving your tokens :)
150
    }
151
    
152
    /**
153
     * @return int
154
     */
155
    public function getRemainingMinuteLimit()
156
    {
157
        return Cache::get($this->limit_cache_name, 6);
158
    }
159
    
160
    /**
161
     * @param int $limit
162
     *
163
     * @throws \Exception
164
     */
165
    public function handleMinuteLimit($limit)
166
    {
167
        $this->resetAcquiringLockTries();
168
        if($this->acquireLock($this->limit_lock_name) === false) {
169
            throw new \Exception('Could not acquire lock..');
170
        }
171
        
172
        Cache::put($this->limit_cache_name, $limit, date('Y-m-d H:i:s', strtotime('+2 minutes')));
0 ignored issues
show
Bug introduced by
date('Y-m-d H:i:s', strtotime('+2 minutes')) of type string is incompatible with the type DateInterval|DateTimeInterface|integer expected by parameter $ttl of Illuminate\Support\Facades\Cache::put(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

172
        Cache::put($this->limit_cache_name, $limit, /** @scrutinizer ignore-type */ date('Y-m-d H:i:s', strtotime('+2 minutes')));
Loading history...
173
    
174
        $this->releaseLock($this->limit_lock_name);
175
    }
176
    
177
    /**
178
     * @param string $limit
179
     *
180
     * @throws \Exception
181
     */
182
    protected function saveMinuteLimit($limit)
183
    {
184
        Cache::put($this->limit_cache_name, $limit, date('Y-m-d H:i:s', strtotime('+2 minutes')));
0 ignored issues
show
Bug introduced by
date('Y-m-d H:i:s', strtotime('+2 minutes')) of type string is incompatible with the type DateInterval|DateTimeInterface|integer expected by parameter $ttl of Illuminate\Support\Facades\Cache::put(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

184
        Cache::put($this->limit_cache_name, $limit, /** @scrutinizer ignore-type */ date('Y-m-d H:i:s', strtotime('+2 minutes')));
Loading history...
185
    }
186
    
187
    protected function resetAcquiringLockTries()
188
    {
189
        $this->acquiring_lock_tries = 0;
190
    }
191
    
192
    /**
193
     * @param string $key
194
     *
195
     * @return bool
196
     */
197
    protected function acquireLock($key)
198
    {
199
        if($this->acquiring_lock_tries >= 20) {
200
            return false;
201
        }
202
    
203
        $this->acquiring_lock_tries++;
204
        
205
        if(Cache::has($key)) {
206
            $this->sleepForLock();
207
            return $this->acquireLock($key);
208
        }
209
        
210
        $random_value = Str::random();
211
        Cache::put($key, $random_value, date('Y-m-d H:i:s', strtotime('+5 seconds')));
0 ignored issues
show
Bug introduced by
date('Y-m-d H:i:s', strtotime('+5 seconds')) of type string is incompatible with the type DateInterval|DateTimeInterface|integer expected by parameter $ttl of Illuminate\Support\Facades\Cache::put(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

211
        Cache::put($key, $random_value, /** @scrutinizer ignore-type */ date('Y-m-d H:i:s', strtotime('+5 seconds')));
Loading history...
212
        
213
        $this->sleepForLock();
214
        
215
        if(Cache::get($key) === $random_value) {
216
            return true;
217
        }
218
        
219
        return $this->acquireLock($key);
220
    }
221
    
222
    /**
223
     * @param string $key
224
     */
225
    protected function releaseLock($key)
226
    {
227
        Cache::forget($key);
228
    }
229
    
230
    /**
231
     * Sleep between 20 and 50 milliseconds
232
     */
233
    protected function sleepForLock()
234
    {
235
        usleep(rand(20000, 50000));
236
    }
237
    
238
}
239