Completed
Push — master ( cd17f3...38b66e )
by David
01:50 queued 12s
created

HttpClientPoolItem   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 152
Duplicated Lines 7.24 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 94%

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 3
dl 11
loc 152
ccs 47
cts 50
cp 0.94
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 11 11 3
A sendRequest() 0 19 3
A sendAsyncRequest() 0 19 2
A isDisabled() 0 17 4
A getSendingRequestCount() 0 4 1
A incrementRequestCount() 0 4 1
A decrementRequestCount() 0 4 1
A enable() 0 4 1
A disable() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Http\Client\Common\HttpClientPool;
6
7
use Http\Client\Common\FlexibleHttpClient;
8
use Http\Client\Exception;
9
use Http\Client\HttpAsyncClient;
10
use Http\Client\HttpClient;
11
use Psr\Http\Client\ClientInterface;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * A HttpClientPoolItem represent a HttpClient inside a Pool.
17
 *
18
 * It is disabled when a request failed and can be reenabled after a certain number of seconds.
19
 * It also keep tracks of the current number of open requests the client is currently being sending
20
 * (only usable for async method).
21
 *
22
 * This class is used internally in the client pools and is not supposed to be used anywhere else.
23
 *
24
 * @final
25
 *
26
 * @internal
27
 *
28
 * @author Joel Wurtz <[email protected]>
29
 */
30
class HttpClientPoolItem implements HttpClient, HttpAsyncClient
31
{
32
    /**
33
     * @var int Number of request this client is currently sending
34
     */
35
    private $sendingRequestCount = 0;
36
37
    /**
38
     * @var \DateTime|null Time when this client has been disabled or null if enable
39
     */
40
    private $disabledAt;
41
42
    /**
43
     * Number of seconds until this client is enabled again after an error.
44
     *
45
     * null: never reenable this client.
46
     *
47
     * @var int|null
48
     */
49
    private $reenableAfter;
50
51
    /**
52
     * @var FlexibleHttpClient A http client responding to async and sync request
53
     */
54
    private $client;
55
56
    /**
57
     * @param ClientInterface|HttpAsyncClient $client
58
     * @param int|null                        $reenableAfter Number of seconds until this client is enabled again after an error
59
     */
60 23 View Code Duplication
    public function __construct($client, int $reenableAfter = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
61
    {
62 23
        if (!$client instanceof ClientInterface && !$client instanceof HttpAsyncClient) {
63
            throw new \TypeError(
64
                sprintf('%s::__construct(): Argument #1 ($client) must be of type %s|%s, %s given', self::class, ClientInterface::class, HttpAsyncClient::class, get_debug_type($client))
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with sprintf('%s::__construct...et_debug_type($client)).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
65
            );
66
        }
67
68 23
        $this->client = new FlexibleHttpClient($client);
69 23
        $this->reenableAfter = $reenableAfter;
70 23
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75 13
    public function sendRequest(RequestInterface $request): ResponseInterface
76
    {
77 13
        if ($this->isDisabled()) {
78 1
            throw new Exception\RequestException('Cannot send the request as this client has been disabled', $request);
79
        }
80
81
        try {
82 13
            $this->incrementRequestCount();
83 13
            $response = $this->client->sendRequest($request);
84 5
            $this->decrementRequestCount();
85 8
        } catch (Exception $e) {
86 8
            $this->disable();
87 8
            $this->decrementRequestCount();
88
89 8
            throw $e;
90
        }
91
92 5
        return $response;
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 8
    public function sendAsyncRequest(RequestInterface $request)
99
    {
100 8
        if ($this->isDisabled()) {
101 1
            throw new Exception\RequestException('Cannot send the request as this client has been disabled', $request);
102
        }
103
104 8
        $this->incrementRequestCount();
105
106
        return $this->client->sendAsyncRequest($request)->then(function ($response) {
107 1
            $this->decrementRequestCount();
108
109 1
            return $response;
110
        }, function ($exception) {
111 2
            $this->disable();
112 2
            $this->decrementRequestCount();
113
114 2
            throw $exception;
115 8
        });
116
    }
117
118
    /**
119
     * Whether this client is disabled or not.
120
     *
121
     * If the client was disabled, calling this method checks if the client can
122
     * be reenabled and if so enables it.
123
     */
124 21
    public function isDisabled(): bool
125
    {
126 21
        if (null !== $this->reenableAfter && null !== $this->disabledAt) {
127
            // Reenable after a certain time
128 5
            $now = new \DateTime();
129
130 5
            if (($now->getTimestamp() - $this->disabledAt->getTimestamp()) >= $this->reenableAfter) {
131 5
                $this->enable();
132
133 5
                return false;
134
            }
135
136
            return true;
137
        }
138
139 21
        return null !== $this->disabledAt;
140
    }
141
142
    /**
143
     * Get current number of request that are currently being sent by the underlying HTTP client.
144
     */
145 2
    public function getSendingRequestCount(): int
146
    {
147 2
        return $this->sendingRequestCount;
148
    }
149
150
    /**
151
     * Increment the request count.
152
     */
153 21
    private function incrementRequestCount(): void
154
    {
155 21
        ++$this->sendingRequestCount;
156 21
    }
157
158
    /**
159
     * Decrement the request count.
160
     */
161 16
    private function decrementRequestCount(): void
162
    {
163 16
        --$this->sendingRequestCount;
164 16
    }
165
166
    /**
167
     * Enable the current client.
168
     */
169 5
    private function enable(): void
170
    {
171 5
        $this->disabledAt = null;
172 5
    }
173
174
    /**
175
     * Disable the current client.
176
     */
177 10
    private function disable(): void
178
    {
179 10
        $this->disabledAt = new \DateTime('now');
180 10
    }
181
}
182