Test Failed
Branch feature/decoupled (5e8293)
by Webysther
02:49
created

Http   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 174
rs 10
c 0
b 0
f 0
wmc 12

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getMirror() 0 3 1
A getJson() 0 17 3
A getPoolErrors() 0 3 1
A useMirrors() 0 5 1
B pool() 0 35 2
A getRequest() 0 8 2
A __construct() 0 6 1
A getBaseUri() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Packagist Mirror.
7
 *
8
 * For the full license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webs\Mirror;
13
14
use GuzzleHttp\Client;
15
use GuzzleHttp\Pool;
16
use GuzzleHttp\Psr7\Request;
17
use stdClass;
18
use Exception;
19
use Generator;
20
use Closure;
21
22
/**
23
 * Middleware to http operations.
24
 *
25
 * @author Webysther Nunes <[email protected]>
26
 */
27
class Http
28
{
29
    use Gzip;
30
31
    /**
32
     * @var Client
33
     */
34
    protected $client;
35
36
    /**
37
     * @var Mirror
38
     */
39
    protected $mirror;
40
41
    /**
42
     * @var array
43
     */
44
    protected $poolErrors;
45
46
    /**
47
     * @var array
48
     */
49
    protected $config = [
50
        'base_uri' => '',
51
        'headers' => ['Accept-Encoding' => 'gzip'],
52
        'decode_content' => false,
53
        'timeout' => 30,
54
        'connect_timeout' => 15,
55
    ];
56
57
    /**
58
     * @var int
59
     */
60
    protected $maxConnections;
61
62
    /**
63
     * @var int
64
     */
65
    protected $connections;
66
67
    /**
68
     * @var bool
69
     */
70
    protected $usingMirrors = false;
71
72
    /**
73
     * @param Mirror $mirror
74
     * @param int    $maxConnections
75
     */
76
    public function __construct(Mirror $mirror, int $maxConnections)
77
    {
78
        $this->config['base_uri'] = $mirror->getMaster();
79
        $this->client = new Client($this->config);
80
        $this->maxConnections = $maxConnections;
81
        $this->mirror = $mirror;
82
    }
83
84
    /**
85
     * @return string
86
     */
87
    public function getBaseUri():string
88
    {
89
        return $this->config['base_uri'];
90
    }
91
92
    /**
93
     * Client get with transparent gz decode.
94
     *
95
     * @see Client::get
96
     */
97
    public function getJson(string $uri):stdClass
98
    {
99
        $response = $this->client->get($uri);
100
101
        // Maybe 4xx or 5xx
102
        if ($response->getStatusCode() >= 400) {
103
            throw new Exception("Error download $uri", 1);
104
        }
105
106
        $json = $this->decode((string) $response->getBody());
107
        $decoded = json_decode($json);
108
109
        if (json_last_error() !== JSON_ERROR_NONE) {
110
            throw new Exception("Response not a json: $json", 1);
111
        }
112
113
        return $decoded;
114
    }
115
116
    /**
117
     * Create a new get request.
118
     *
119
     * @param string $uri
120
     *
121
     * @return Request
122
     */
123
    public function getRequest(string $uri):Request
124
    {
125
        $base = $this->getBaseUri();
126
        if ($this->usingMirrors) {
127
            $base = $this->mirrors->getNext();
0 ignored issues
show
Bug introduced by
The property mirrors does not exist on Webs\Mirror\Http. Did you mean mirror?
Loading history...
128
        }
129
130
        return new Request('GET', $base.'/'.$uri);
131
    }
132
133
    /**
134
     * @param Generator $requests
135
     * @param Closure   $success
136
     * @param Closure   $complete
137
     *
138
     * @return Http
139
     */
140
    public function pool(Generator $requests, Closure $success, Closure $complete):Http
141
    {
142
        $this->connections = $this->maxConnections;
143
        if ($this->usingMirrors) {
144
            $mirrors = $this->mirror->getAll()->count();
145
            $this->connections = $this->maxConnections * $mirrors;
146
        }
147
148
        $fulfilled = function ($response, $path) use ($success, $complete) {
149
            $body = (string) $response->getBody();
150
            $success($body, $path);
151
            $complete();
152
        };
153
154
        $rejected = function ($reason, $path) use ($complete) {
155
            $this->poolErrors[$path] = $reason;
156
            $complete();
157
        };
158
159
        $this->poolErrors = [];
160
        $pool = new Pool(
161
            $this->client,
162
            $requests,
163
            [
164
                'concurrency' => $this->connections,
165
                'fulfilled' => $fulfilled,
166
                'rejected' => $rejected,
167
            ]
168
        );
169
        $pool->promise()->wait();
170
171
        // Reset to use only max connections for one mirror
172
        $this->usingMirrors = false;
173
174
        return $this;
175
    }
176
177
    /**
178
     * @return Http
179
     */
180
    public function useMirrors():Http
181
    {
182
        $this->usingMirrors = true;
183
184
        return $this;
185
    }
186
187
    /**
188
     * @return array
189
     */
190
    public function getPoolErrors():array
191
    {
192
        return $this->poolErrors;
193
    }
194
195
    /**
196
     * @return Mirror
197
     */
198
    public function getMirror():Mirror
199
    {
200
        return $this->mirror;
201
    }
202
}
203