HttplugAsyncClient::waitForResponses()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 10
cc 2
nc 2
nop 0
crap 2
1
<?php
2
declare(strict_types=1);
3
4
namespace TechDeCo\ElasticApmAgent\Client;
5
6
use Http\Client\HttpAsyncClient;
7
use Http\Discovery\Exception as DiscoveryException;
8
use Http\Discovery\HttpAsyncClientDiscovery;
9
use Http\Discovery\MessageFactoryDiscovery;
10
use Http\Message\MessageFactory;
11
use Psr\Http\Message\RequestInterface;
12
use Psr\Log\LoggerInterface;
13
use TechDeCo\ElasticApmAgent\Client;
14
use TechDeCo\ElasticApmAgent\ClientConfiguration;
15
use TechDeCo\ElasticApmAgent\Exception\ClientException;
16
use TechDeCo\ElasticApmAgent\Request\Error;
17
use TechDeCo\ElasticApmAgent\Request\Transaction;
18
use Throwable;
19
use function assert;
20
use function count;
21
use function json_encode;
22
use function register_shutdown_function;
23
24
final class HttplugAsyncClient implements Client
25
{
26
    /**
27
     * @var ClientConfiguration
28
     */
29
    private $config;
30
31
    /**
32
     * @var HttpAsyncClient
33
     */
34
    private $httpClient;
35
36
    /**
37
     * @var MessageFactory
38
     */
39
    private $httpMessageFactory;
40
41
    /**
42
     * @var PromiseCollection
43
     */
44
    private $promises;
45
46
    /**
47
     * @var LoggerInterface
48
     */
49
    private $logger;
50
51
    /**
52
     * @throws DiscoveryException\NotFoundException
53
     */
54 10
    public function __construct(
55
        LoggerInterface $logger,
56
        ClientConfiguration $config,
57
        ?HttpAsyncClient $httpClient,
58
        ?MessageFactory $httpMessageFactory
59
    ) {
60 10
        $this->logger             = $logger;
61 10
        $this->config             = $config;
62 10
        $this->httpClient         = $httpClient ?? HttpAsyncClientDiscovery::find();
63 10
        $this->httpMessageFactory = $httpMessageFactory ?? MessageFactoryDiscovery::find();
64 10
        $this->promises           = new PromiseCollection($logger);
65
66 10
        register_shutdown_function([$this, 'waitForResponses']);
67 10
    }
68
69
    /**
70
     * @throws ClientException
71
     */
72 9
    public function sendTransaction(Transaction $transaction): void
73
    {
74 9
        $encoded = json_encode($transaction);
75 9
        assert($encoded !== false);
76
77 9
        $request = $this->httpMessageFactory->createRequest(
78 9
            'POST',
79 9
            $this->config->getTransactionsEndpoint(),
80 9
            [],
81 9
            $encoded
82
        );
83
84 9
        $this->sendRequest($request);
85 8
    }
86
87
    /**
88
     * @throws ClientException
89
     */
90 1
    public function sendError(Error $error): void
91
    {
92 1
        $encoded = json_encode($error);
93 1
        assert($encoded !== false);
94
95 1
        $request = $this->httpMessageFactory->createRequest(
96 1
            'POST',
97 1
            $this->config->getErrorsEndpoint(),
98 1
            [],
99 1
            $encoded
100
        );
101
102 1
        $this->sendRequest($request);
103 1
    }
104
105
    /**
106
     * @throws ClientException
107
     */
108 10
    private function sendRequest(RequestInterface $request): void
109
    {
110 10
        $requestCount = count($this->promises) + 1;
111
112
        try {
113 10
            $request = $request->withHeader('Content-Type', 'application/json');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $request. This often makes code more readable.
Loading history...
114 10
            if ($this->config->needsAuthentication()) {
115 10
                $this->logger->debug('Adding authentication token to request');
116 10
                $request = $request->withHeader('Authorization', 'Bearer ' . $this->config->getToken());
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $request. This often makes code more readable.
Loading history...
117
            }
118
119 10
            $this->logger->debug('Sending asynchronous request #' . $requestCount);
120 10
            $this->promises->add($this->httpClient->sendAsyncRequest($request));
121 1
        } catch (Throwable $e) {
122 1
            $this->logger->error('Encountered error while sending asynchronous request #' . $requestCount, [
123 1
                'exception' => $e,
124 1
                'message' => $e->getMessage(),
125
            ]);
126 1
            throw new ClientException('Could not send request due to configuration error', 0, $e);
127
        }
128 9
    }
129
130
    /**
131
     * @throws ClientException
132
     */
133 4
    public function waitForResponses(): void
134
    {
135 4
        $exceptionList = $this->promises->resolveAll();
136
137 4
        if (! empty($exceptionList)) {
138 3
            throw ClientException::fromException('Encountered errors while resolving requests', ...$exceptionList);
139
        }
140 1
    }
141
}
142