-
-
Notifications
You must be signed in to change notification settings - Fork 451
/
HttpTransport.php
116 lines (97 loc) · 3.24 KB
/
HttpTransport.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
declare(strict_types=1);
namespace Sentry\Transport;
use Http\Client\HttpAsyncClient;
use Http\Message\RequestFactory;
use Http\Promise\Promise;
use Sentry\Event;
use Sentry\Options;
use Sentry\Util\JSON;
/**
* This transport sends the events using an HTTP client.
*
* @author Stefano Arlandini <sarlandini@alice.it>
*/
final class HttpTransport implements AsyncTransportInterface
{
/**
* @var Options The Sentry client configuration
*/
private $config;
/**
* @var HttpAsyncClient The HTTP client
*/
private $httpClient;
/**
* @var RequestFactory The PSR-7 request factory
*/
private $requestFactory;
/**
* @var Promise[] The list of pending requests
*/
private $pendingRequests = [];
/**
* Constructor.
*
* @param Options $config The Sentry client configuration
* @param HttpAsyncClient $httpClient The HTTP client
* @param RequestFactory $requestFactory The PSR-7 request factory
*/
public function __construct(Options $config, HttpAsyncClient $httpClient, RequestFactory $requestFactory)
{
$this->config = $config;
$this->httpClient = $httpClient;
$this->requestFactory = $requestFactory;
// By calling the cleanupPendingRequests function from a shutdown function
// registered inside another shutdown function we can be confident that it
// will be executed last
register_shutdown_function('register_shutdown_function', \Closure::fromCallable([$this, 'await']));
}
/**
* Destructor. Ensures that all pending requests ends before destroying this
* object instance.
*/
public function __destruct()
{
$this->await();
}
/**
* {@inheritdoc}
*/
public function send(Event $event): ?string
{
$request = $this->requestFactory->createRequest(
'POST',
sprintf('/api/%d/store/', $this->config->getProjectId()),
['Content-Type' => 'application/json'],
JSON::encode($event)
);
$promise = $this->httpClient->sendAsyncRequest($request);
// This function is defined in-line so it doesn't show up for type-hinting
$cleanupPromiseCallback = function ($responseOrException) use ($promise) {
$index = array_search($promise, $this->pendingRequests, true);
if (false !== $index) {
unset($this->pendingRequests[$index]);
}
return $responseOrException;
};
$promise->then($cleanupPromiseCallback, $cleanupPromiseCallback);
$this->pendingRequests[] = $promise;
return $event->getId();
}
/**
* Cleanups the pending requests by forcing them to be sent. Any error that
* occurs will be ignored.
*/
public function await(): void
{
while ($pendingRequest = array_pop($this->pendingRequests)) {
try {
$pendingRequest->wait();
} catch (\Throwable $exception) {
// Do nothing because an exception thrown from a destructor
// can't be catched in PHP (see http://php.net/manual/en/language.oop5.decon.php#language.oop5.decon.destructor)
}
}
}
}