From 64862a043854dac5eccd9cbcaa38058d6d0a8db5 Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Thu, 13 Apr 2023 08:19:30 +0200 Subject: [PATCH] Switch to async HTTP client internally It will still be converted to a dual async/sync one by `PluginClient`. --- composer.json | 2 +- .../Rector/Helpers/RecordingHttpClient.php | 27 +++++++++++-------- .../Rector/MockGrabyResponseRector.php | 4 +-- src/Extractor/HttpClient.php | 6 ++--- src/Graby.php | 8 +++--- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/composer.json b/composer.json index dfd91ace..d0130874 100644 --- a/composer.json +++ b/composer.json @@ -24,11 +24,11 @@ "j0k3r/httplug-ssrf-plugin": "^3.0", "j0k3r/php-readability": "^1.2.9", "monolog/monolog": "^1.18.0|^2.3", + "php-http/async-client-implementation": "^1.0", "php-http/client-common": "^2.5", "php-http/discovery": "^1.14", "php-http/httplug": "^2.2", "php-http/message": "^1.12", - "psr/http-client-implementation": "^1.0", "simplepie/simplepie": "^1.8", "smalot/pdfparser": "^2.0", "symfony/options-resolver": "^3.4|^4.4|^5.3|^6.0", diff --git a/maintenance/Rector/Helpers/RecordingHttpClient.php b/maintenance/Rector/Helpers/RecordingHttpClient.php index eb801e77..d468b868 100644 --- a/maintenance/Rector/Helpers/RecordingHttpClient.php +++ b/maintenance/Rector/Helpers/RecordingHttpClient.php @@ -2,36 +2,41 @@ namespace Maintenance\Graby\Rector\Helpers; -use Psr\Http\Client\ClientExceptionInterface; -use Psr\Http\Client\ClientInterface; +use Http\Client\HttpAsyncClient; +use Http\Promise\Promise; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -class RecordingHttpClient implements ClientInterface +class RecordingHttpClient implements HttpAsyncClient { /** * @var ResponseInterface[] */ private array $responses; - private ClientInterface $httpClient; + private HttpAsyncClient $httpClient; - public function __construct(ClientInterface $httpClient) + public function __construct(HttpAsyncClient $httpClient) { $this->httpClient = $httpClient; } /** - * Sends a PSR-7 request and returns a PSR-7 response. + * Sends a PSR-7 request in an asynchronous way. * - * @throws ClientExceptionInterface if an error happens while processing the request + * Exceptions related to processing the request are available from the returned Promise. + * + * @throws \Exception If processing the request is impossible (eg. bad configuration). + * + * @return Promise resolves a PSR-7 Response or fails with an Http\Client\Exception */ - public function sendRequest(RequestInterface $request): ResponseInterface + public function sendAsyncRequest(RequestInterface $request): Promise { - $response = $this->httpClient->sendRequest($request); - $this->responses[] = $response; + return $this->httpClient->sendAsyncRequest($request)->then(function (ResponseInterface $response): ResponseInterface { + $this->responses[] = $response; - return $response; + return $response; + }); } /** diff --git a/maintenance/Rector/MockGrabyResponseRector.php b/maintenance/Rector/MockGrabyResponseRector.php index fe9ec192..b3249099 100644 --- a/maintenance/Rector/MockGrabyResponseRector.php +++ b/maintenance/Rector/MockGrabyResponseRector.php @@ -7,7 +7,7 @@ use Graby\Graby; use Graby\HttpClient\Plugin\CookiePlugin; use Http\Client\Common\PluginClient; -use Http\Discovery\HttpClientDiscovery; +use Http\Discovery\HttpAsyncClientDiscovery; use Http\Message\CookieJar; use Maintenance\Graby\Rector\Helpers\RecordingHttpClient; use PhpParser\Comment; @@ -259,7 +259,7 @@ private function fetchResponses(string $url, array $config): array { // Wrap the same HTTP client internally created by Graby class with a proxy // that captures the returned responses. - $httpClient = new RecordingHttpClient(new PluginClient(HttpClientDiscovery::find(), [new CookiePlugin(new CookieJar())])); + $httpClient = new RecordingHttpClient(new PluginClient(HttpAsyncClientDiscovery::find(), [new CookiePlugin(new CookieJar())])); $graby = new Graby($config, $httpClient); $graby->fetchContent($url); diff --git a/src/Extractor/HttpClient.php b/src/Extractor/HttpClient.php index 27f0336a..c9ccb08d 100644 --- a/src/Extractor/HttpClient.php +++ b/src/Extractor/HttpClient.php @@ -12,8 +12,8 @@ use Http\Client\Common\Plugin\RedirectPlugin; use Http\Client\Common\PluginClient; use Http\Client\Exception\TransferException; +use Http\Client\HttpAsyncClient as Client; use Http\Discovery\Psr17FactoryDiscovery; -use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Log\LoggerInterface; @@ -32,9 +32,9 @@ class HttpClient private ?ContentExtractor $extractor; /** - * @param ClientInterface $client Http client + * @param Client $client Http client */ - public function __construct(ClientInterface $client, array $config = [], LoggerInterface $logger = null, ContentExtractor $extractor = null) + public function __construct(Client $client, array $config = [], LoggerInterface $logger = null, ContentExtractor $extractor = null) { $this->config = new HttpClientConfig($config); diff --git a/src/Graby.php b/src/Graby.php index cfef6084..57691156 100644 --- a/src/Graby.php +++ b/src/Graby.php @@ -9,11 +9,11 @@ use GuzzleHttp\Psr7\Uri; use GuzzleHttp\Psr7\UriResolver; use Http\Client\Common\PluginClient; -use Http\Discovery\HttpClientDiscovery; +use Http\Client\HttpAsyncClient as Client; +use Http\Discovery\HttpAsyncClientDiscovery; use Http\Message\CookieJar; use Monolog\Handler\StreamHandler; use Monolog\Logger; -use Psr\Http\Client\ClientInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Readability\Readability; @@ -35,7 +35,7 @@ class Graby private ?string $prefetchedContent = null; - public function __construct(array $config = [], ?ClientInterface $client = null, ConfigBuilder $configBuilder = null) + public function __construct(array $config = [], ?Client $client = null, ConfigBuilder $configBuilder = null) { $this->config = new GrabyConfig($config); @@ -75,7 +75,7 @@ public function __construct(array $config = [], ?ClientInterface $client = null, ); $this->httpClient = new HttpClient( - $client ?: new PluginClient(HttpClientDiscovery::find(), [new CookiePlugin(new CookieJar())]), + $client ?: new PluginClient(HttpAsyncClientDiscovery::find(), [new CookiePlugin(new CookieJar())]), $this->config->getHttpClient(), $this->logger, $this->extractor