Passed
Push — master ( c11b4a...d77a2a )
by Clinton
02:24
created

Guzzler::setEtagTTL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace cvweiss;
4
5
class Guzzler
6
{
7
    private $curl;
8
    private $handler;
9
    private $client;
10
    private $concurrent = 0;
11
    private $maxConcurrent;
12
    private $usleep;
13
    private $lastHeaders = [];
14
    private $etagTTL = 86400;
15
16
    public function __construct($maxConcurrent = 10, $usleep = 100000, $userAgent = 'cvweiss/guzzler/', $curlOptions = [])
17
    {
18
	$curlOptions = $curlOptions == [] ? [CURLOPT_FRESH_CONNECT => false] : $curlOptions;
19
20
        $this->curl = new \GuzzleHttp\Handler\CurlMultiHandler();
21
        $this->handler = \GuzzleHttp\HandlerStack::create($this->curl);
22
        $this->client = new \GuzzleHttp\Client(['curl' => $curlOptions, 'connect_timeout' => 10, 'timeout' => 10, 'handler' => $this->handler, 'User-Agent' => $userAgent]);
23
        $this->maxConcurrent = max($maxConcurrent, 1);
24
        $this->usleep = max(0, min(1000000, (int) $usleep));
25
    }
26
27
    public function isSetDefault($arr, $key, $default)
28
    {
29
        return isset($arr[$key]) ? $arr[$key] : $default;
30
    }
31
32
    public function tick()
33
    {
34
        $ms = microtime();
35
        do {
36
            $this->curl->tick();
37
	    if ($this->concurrent >= $this->maxConcurrent) usleep(max(1, min(1000000, $this->usleep)));
38
        } while ($this->concurrent >= $this->maxConcurrent);
39
        return max(0, microtime() - $ms);
40
    }
41
42
    public function finish()
43
    {
44
        $ms = microtime();
45
        $this->curl->execute();
46
        return max(0, microtime() - $ms);
47
    }
48
49
    public function inc()
50
    {
51
        $this->concurrent++;
52
    }
53
54
    public function dec()
55
    {
56
        $this->concurrent--;
57
    }
58
59
    public function call($uri, $fulfilled, $rejected, $params = [], $setup = [], $callType = 'GET', $body = null)
60
    {
61
        $this->verifyCallable($fulfilled);
62
        $this->verifyCallable($rejected);
63
64
	while ($this->concurrent >= $this->maxConcurrent) $this->tick();
65
66
	$params['uri'] = $uri;
67
	$params['fulfilled'] = $fulfilled;
68
	$params['rejected'] = $rejected;
69
	$params['setup'] = $setup;
70
	$params['callType'] = $callType;
71
	$params['body'] = $body;
72
73
	$redis = $this->applyEtag($setup, $params);
74
75
        $guzzler = $this;
76
        $request = new \GuzzleHttp\Psr7\Request($callType, $uri, $setup, $body);
77
        $this->client->sendAsync($request)->then(
78
            function($response) use (&$guzzler, $fulfilled, &$params, $redis) {
79
                $guzzler->dec();
80
                $content = (string) $response->getBody();
81
                $this->lastHeaders = array_change_key_case($response->getHeaders());
82
		$this->applyEtagPost($this->lastHeaders, $params['uri'], $content, $redis);
83
                $fulfilled($guzzler, $params, $content);
84
            },
85
            function($connectionException) use (&$guzzler, &$rejected, &$params) {
86
                $guzzler->dec();
87
                $response = $connectionException->getResponse();
88
                $this->lastHeaders = $response == null ? [] : array_change_key_case($response->getHeaders());
89
                $params['content'] = method_exists($response, "getBody") ? (string) $response->getBody() : "";
90
                $rejected($guzzler, $params, $connectionException);
91
            });
92
        $this->inc();
93
    }
94
95
    protected function applyEtag(&$setup, $params)
96
    {
97
        $redis = isset($setup['etag']) ? $setup['etag'] : null;
98
        if ($redis !== null && $params['callType'] == 'GET') {
99
            $etag = $redis->get("guzzler:etags:" . $params['uri']);
100
            if ($etag != "") $setup['If-None-Match'] = $etag;
101
        }
102
        unset($setup['etag']);
103
	return $redis;
104
    }
105
106
    protected function applyEtagPost($headers, $uri, $content, $redis)
0 ignored issues
show
Unused Code introduced by
The parameter $content 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

106
    protected function applyEtagPost($headers, $uri, /** @scrutinizer ignore-unused */ $content, $redis)

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...
107
    {
108
        if (isset($headers['etag']) && $redis !== null) {
109
	    $redis->setex("guzzler:etags:$uri", $this->etagTTL, $headers['etag'][0]);
110
	}
111
    }
112
113
    public function verifyCallable($callable)
114
    {
115
        if (!is_callable($callable)) {
116
            throw new \InvalidArgumentException(print_r($callable, true) . " is not a callable function");
117
        }
118
    }
119
    
120
    public function getLastHeaders()
121
    {
122
        return $this->lastHeaders;
123
    }
124
125
    public function setEtagTTL($ttl)
126
    {
127
	$this->etagTTL = $ttl;
128
    }
129
}
130