Completed
Pull Request — master (#355)
by
unknown
02:53
created

DefaultProfile::handleNewTokens()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

150
    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 $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

150
    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 $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

150
    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...
151
    {
152
        // save all received tokens so we can't
153
        // save an old token after the process paused
154
        
155
        // todo: implement method for saving your tokens :)
156
    }
157
    
158
    /**
159
     * @return int
160
     */
161
    public function getRemainingMinuteLimit()
162
    {
163
        return Cache::get($this->limit_cache_name, 6);
164
    }
165
    
166
    /**
167
     * @param int $limit
168
     *
169
     * @throws \Exception
170
     */
171
    public function handleMinuteLimit($limit)
172
    {
173
        $this->resetAcquiringLockTries();
174
        if($this->acquireLock($this->limit_lock_name) === false) {
175
            throw new \Exception('Could not acquire lock..');
176
        }
177
        
178
        Cache::put($this->limit_cache_name, $limit, $this->getDateTimeCacheTTL());
179
    
180
        $this->releaseLock($this->limit_lock_name);
181
    }
182
    
183
    /**
184
     * @param string $limit
185
     *
186
     * @throws \Exception
187
     */
188
    protected function saveMinuteLimit($limit)
189
    {
190
        Cache::put($this->limit_cache_name, $limit, $this->getDateTimeCacheTTL());
191
    }
192
    
193
    protected function resetAcquiringLockTries()
194
    {
195
        $this->acquiring_lock_tries = 0;
196
    }
197
    
198
    /**
199
     * @param $key
200
     *
201
     * @return bool
202
     * @throws \Exception
203
     */
204
    protected function acquireLock($key)
205
    {
206
        if($this->acquiring_lock_tries >= 20) {
207
            return false;
208
        }
209
    
210
        $this->acquiring_lock_tries++;
211
        
212
        if(Cache::has($key)) {
213
            $this->sleepForLock();
214
            return $this->acquireLock($key);
215
        }
216
        
217
        $random_value = Str::random();
218
        Cache::put($key, $random_value, $this->getDateTimeCacheTTL(5));
219
        
220
        $this->sleepForLock();
221
        
222
        if(Cache::get($key) === $random_value) {
223
            return true;
224
        }
225
        
226
        return $this->acquireLock($key);
227
    }
228
    
229
    /**
230
     * @param string $key
231
     */
232
    protected function releaseLock($key)
233
    {
234
        Cache::forget($key);
235
    }
236
    
237
    /**
238
     * Sleep between 20 and 50 milliseconds
239
     */
240
    protected function sleepForLock()
241
    {
242
        usleep(rand(20000, 50000));
243
    }
244
    
245
    /**
246
     * @param int $seconds
247
     *
248
     * @return \DateTime
249
     * @throws \Exception
250
     */
251
    protected function getDateTimeCacheTTL($seconds = 120)
252
    {
253
        return (new DateTime())->add(new DateInterval('PT' . $seconds . 'S'));
254
    }
255
    
256
}
257