PluginProbe
DecaLog / 4.4.0
DecaLog v4.4.0
3.0.2 3.1.0 3.10.0 3.2.0 3.3.0 3.4.0 3.4.1 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.6.3 3.7.0 3.7.1 3.8.0 3.9.0 3.9.1 4.0.0 4.1.0 4.2.0 4.3.0 4.3.1 4.4.0 4.5.0 All 75 releases
decalog / includes / libraries / http / client-common / PluginClient.php

PluginClient.php in DecaLog 4.4.0, at includes/libraries/http/client-common/PluginClient.php

130 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Http\Client\Common;
6
7 use Http\Client\Exception as HttplugException;
8 use Http\Client\HttpAsyncClient;
9 use Http\Client\HttpClient;
10 use Http\Client\Promise\HttpFulfilledPromise;
11 use Http\Client\Promise\HttpRejectedPromise;
12 use Http\Promise\Promise;
13 use Psr\Http\Client\ClientInterface;
14 use Psr\Http\Message\RequestInterface;
15 use Psr\Http\Message\ResponseInterface;
16 use Symfony\Component\OptionsResolver\OptionsResolver;
17
18 /**
19 * The client managing plugins and providing a decorator around HTTP Clients.
20 *
21 * @author Joel Wurtz <joel.wurtz@gmail.com>
22 */
23 final class PluginClient implements HttpClient, HttpAsyncClient
24 {
25 /**
26 * An HTTP async client.
27 *
28 * @var HttpAsyncClient
29 */
30 private $client;
31
32 /**
33 * The plugin chain.
34 *
35 * @var Plugin[]
36 */
37 private $plugins;
38
39 /**
40 * A list of options.
41 *
42 * @var array
43 */
44 private $options;
45
46 /**
47 * @param ClientInterface|HttpAsyncClient $client An HTTP async client
48 * @param Plugin[] $plugins A plugin chain
49 * @param array{'max_restarts'?: int} $options
50 */
51 public function __construct($client, array $plugins = [], array $options = [])
52 {
53 if ($client instanceof HttpAsyncClient) {
54 $this->client = $client;
55 } elseif ($client instanceof ClientInterface) {
56 $this->client = new EmulatedHttpAsyncClient($client);
57 } else {
58 throw new \TypeError(
59 sprintf('%s::__construct(): Argument #1 ($client) must be of type %s|%s, %s given', self::class, ClientInterface::class, HttpAsyncClient::class, get_debug_type($client))
60 );
61 }
62
63 $this->plugins = $plugins;
64 $this->options = $this->configure($options);
65 }
66
67 /**
68 * {@inheritdoc}
69 */
70 public function sendRequest(RequestInterface $request): ResponseInterface
71 {
72 // If the client doesn't support sync calls, call async
73 if (!$this->client instanceof ClientInterface) {
74 return $this->sendAsyncRequest($request)->wait();
75 }
76
77 // Else we want to use the synchronous call of the underlying client,
78 // and not the async one in the case we have both an async and sync call
79 $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) {
80 try {
81 return new HttpFulfilledPromise($this->client->sendRequest($request));
82 } catch (HttplugException $exception) {
83 return new HttpRejectedPromise($exception);
84 }
85 });
86
87 return $pluginChain($request)->wait();
88 }
89
90 /**
91 * {@inheritdoc}
92 */
93 public function sendAsyncRequest(RequestInterface $request)
94 {
95 $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) {
96 return $this->client->sendAsyncRequest($request);
97 });
98
99 return $pluginChain($request);
100 }
101
102 /**
103 * Configure the plugin client.
104 */
105 private function configure(array $options = []): array
106 {
107 $resolver = new OptionsResolver();
108 $resolver->setDefaults([
109 'max_restarts' => 10,
110 ]);
111
112 $resolver->setAllowedTypes('max_restarts', 'int');
113
114 return $resolver->resolve($options);
115 }
116
117 /**
118 * Create the plugin chain.
119 *
120 * @param Plugin[] $plugins A plugin chain
121 * @param callable $clientCallable Callable making the HTTP call
122 *
123 * @return callable(RequestInterface): Promise
124 */
125 private function createPluginChain(array $plugins, callable $clientCallable): callable
126 {
127 return new PluginChain($plugins, $clientCallable, $this->options);
128 }
129 }
130