Skip to content
This repository was archived by the owner on Jan 6, 2024. It is now read-only.

Commit 1959427

Browse files
committed
Merge pull request #11 from joelwurtz/feature/async
Add async capability
2 parents c887235 + daa9b27 commit 1959427

9 files changed

+315
-53
lines changed

composer.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,22 @@
1717
"require": {
1818
"php": ">=5.5.0",
1919
"php-http/httplug": "dev-master",
20+
"php-http/httplug-async": "^0.1",
2021
"guzzlehttp/guzzle": "^6.0"
2122
},
2223
"require-dev": {
2324
"ext-curl": "*",
24-
"php-http/adapter-integration-tests": "^0.2@dev"
25+
"php-http/adapter-integration-tests": "dev-feature/async-test"
2526
},
27+
"repositories": [
28+
{
29+
"type": "vcs",
30+
"url": "https://github.com/joelwurtz/adapter-integration-tests"
31+
}
32+
],
2633
"provide": {
27-
"php-http/client-implementation": "1.0"
34+
"php-http/client-implementation": "1.0",
35+
"php-http/async-client-implementation": "1.0"
2836
},
2937
"autoload": {
3038
"psr-4": {

src/Guzzle6HttpAdapter.php

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,17 @@
1313
use GuzzleHttp\Client;
1414
use GuzzleHttp\ClientInterface;
1515
use GuzzleHttp\Exception as GuzzleExceptions;
16+
use GuzzleHttp\Promise\PromiseInterface;
1617
use Http\Client\Exception;
17-
use Http\Client\Exception\HttpException;
18-
use Http\Client\Exception\NetworkException;
1918
use Http\Client\Exception\RequestException;
20-
use Http\Client\Exception\TransferException;
19+
use Http\Client\HttpAsyncClient;
2120
use Http\Client\HttpClient;
2221
use Psr\Http\Message\RequestInterface;
2322

2423
/**
2524
* @author David de Boer <[email protected]>
2625
*/
27-
class Guzzle6HttpAdapter implements HttpClient
26+
class Guzzle6HttpAdapter implements HttpClient, HttpAsyncClient
2827
{
2928
/**
3029
* @var ClientInterface
@@ -44,42 +43,21 @@ public function __construct(ClientInterface $client = null)
4443
*/
4544
public function sendRequest(RequestInterface $request)
4645
{
47-
try {
48-
return $this->client->send($request);
49-
} catch (GuzzleExceptions\SeekException $e) {
50-
throw new RequestException($e->getMessage(), $request, $e);
51-
} catch (GuzzleExceptions\GuzzleException $e) {
52-
throw $this->handleException($e);
46+
$promise = $this->sendAsyncRequest($request);
47+
$promise->wait();
48+
49+
if ($promise->getState() == PromiseInterface::REJECTED) {
50+
throw $promise->getException();
5351
}
52+
53+
return $promise->getResponse();
5454
}
5555

5656
/**
57-
* Converts a Guzzle exception into an Httplug exception.
58-
*
59-
* @param GuzzleExceptions\GuzzleException $exception
60-
*
61-
* @return Exception
57+
* {@inheritdoc}
6258
*/
63-
private function handleException(GuzzleExceptions\GuzzleException $exception)
59+
public function sendAsyncRequest(RequestInterface $request)
6460
{
65-
if ($exception instanceof GuzzleExceptions\ConnectException) {
66-
return new NetworkException($exception->getMessage(), $exception->getRequest(), $exception);
67-
}
68-
69-
if ($exception instanceof GuzzleExceptions\RequestException) {
70-
// Make sure we have a response for the HttpException
71-
if ($exception->hasResponse()) {
72-
return new HttpException(
73-
$exception->getMessage(),
74-
$exception->getRequest(),
75-
$exception->getResponse(),
76-
$exception
77-
);
78-
}
79-
80-
return new RequestException($exception->getMessage(), $exception->getRequest(), $exception);
81-
}
82-
83-
return new TransferException($exception->getMessage(), 0, $exception);
61+
return new Guzzle6Promise($this->client->sendAsync($request), $request);
8462
}
8563
}

src/Guzzle6Promise.php

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
namespace Http\Adapter;
4+
5+
use GuzzleHttp\Exception as GuzzleExceptions;
6+
use GuzzleHttp\Promise\PromiseInterface;
7+
use Http\Client\Exception as HttplugException;
8+
use Http\Client\Promise;
9+
use Psr\Http\Message\RequestInterface;
10+
use Psr\Http\Message\ResponseInterface;
11+
12+
class Guzzle6Promise implements Promise
13+
{
14+
/**
15+
* @var \GuzzleHttp\Promise\PromiseInterface
16+
*/
17+
private $promise;
18+
19+
/**
20+
* @var string State of the promise
21+
*/
22+
private $state;
23+
24+
/**
25+
* @var ResponseInterface
26+
*/
27+
private $response;
28+
29+
/**
30+
* @var HttplugException
31+
*/
32+
private $exception;
33+
34+
/**
35+
* @var RequestInterface
36+
*/
37+
private $request;
38+
39+
public function __construct(PromiseInterface $promise, RequestInterface $request)
40+
{
41+
$this->request = $request;
42+
$this->state = self::PENDING;
43+
$this->promise = $promise->then(function ($response) {
44+
$this->response = $response;
45+
$this->state = self::FULFILLED;
46+
47+
return $response;
48+
}, function ($reason) use ($request) {
49+
if ($reason instanceof HttplugException) {
50+
$this->state = self::REJECTED;
51+
$this->exception = $reason;
52+
53+
throw $this->exception;
54+
}
55+
56+
if (!($reason instanceof GuzzleExceptions\GuzzleException)) {
57+
throw new \RuntimeException("Invalid reason");
58+
}
59+
60+
$this->state = self::REJECTED;
61+
$this->exception = $this->handleException($reason, $request);
62+
63+
throw $this->exception;
64+
});
65+
}
66+
67+
/**
68+
* {@inheritdoc}
69+
*/
70+
public function then(callable $onFulfilled = null, callable $onRejected = null)
71+
{
72+
return new static($this->promise->then($onFulfilled, $onRejected), $this->request);
73+
}
74+
75+
/**
76+
* {@inheritdoc}
77+
*/
78+
public function getState()
79+
{
80+
return $this->state;
81+
}
82+
83+
84+
/**
85+
* {@inheritdoc}
86+
*/
87+
public function getResponse()
88+
{
89+
if (self::FULFILLED !== $this->state) {
90+
throw new \LogicException("Response not available for the current state");
91+
}
92+
93+
return $this->response;
94+
}
95+
96+
/**
97+
* {@inheritdoc}
98+
*/
99+
public function getException()
100+
{
101+
if (self::REJECTED !== $this->state) {
102+
throw new \LogicException("Error not available for the current state");
103+
}
104+
105+
return $this->exception;
106+
}
107+
108+
/**
109+
* {@inheritdoc}
110+
*/
111+
public function wait()
112+
{
113+
$this->promise->wait(false);
114+
}
115+
116+
/**
117+
* Converts a Guzzle exception into an Httplug exception.
118+
*
119+
* @param GuzzleExceptions\GuzzleException $exception
120+
* @param RequestInterface $request
121+
*
122+
* @return HttplugException
123+
*/
124+
private function handleException(GuzzleExceptions\GuzzleException $exception, RequestInterface $request)
125+
{
126+
if ($exception instanceof GuzzleExceptions\SeekException) {
127+
return new HttplugException\RequestException($exception->getMessage(), $request, $exception);
128+
}
129+
130+
if ($exception instanceof GuzzleExceptions\ConnectException) {
131+
return new HttplugException\NetworkException($exception->getMessage(), $exception->getRequest(), $exception);
132+
}
133+
134+
if ($exception instanceof GuzzleExceptions\RequestException) {
135+
// Make sure we have a response for the HttpException
136+
if ($exception->hasResponse()) {
137+
return new HttplugException\HttpException(
138+
$exception->getMessage(),
139+
$exception->getRequest(),
140+
$exception->getResponse(),
141+
$exception
142+
);
143+
}
144+
145+
return new HttplugException\RequestException($exception->getMessage(), $exception->getRequest(), $exception);
146+
}
147+
148+
return new HttplugException\TransferException($exception->getMessage(), 0, $exception);
149+
}
150+
}
151+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Http Adapter package.
5+
*
6+
* (c) Eric GELOEN <[email protected]>
7+
*
8+
* For the full copyright and license information, please read the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Http\Adapter\Tests;
13+
14+
use GuzzleHttp\Handler\CurlHandler;
15+
16+
/**
17+
* @requires PHP 5.5
18+
*
19+
* @author GeLo <[email protected]>
20+
*/
21+
class Guzzle6CurlHttpAsyncAdapterTest extends Guzzle6HttpAsyncAdapterTest
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
protected function createHandler()
27+
{
28+
return new CurlHandler();
29+
}
30+
}

tests/Guzzle6HttpAdapterTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313

1414
use GuzzleHttp\Client;
1515
use Http\Adapter\Guzzle6HttpAdapter;
16+
use Http\Client\Tests\HttpClientTest;
1617

1718
/**
1819
* @author GeLo <[email protected]>
1920
*/
20-
abstract class Guzzle6HttpAdapterTest extends HttpAdapterTest
21+
abstract class Guzzle6HttpAdapterTest extends HttpClientTest
2122
{
2223
/**
2324
* {@inheritdoc}

tests/Guzzle6HttpAsyncAdapterTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Http Adapter package.
5+
*
6+
* (c) Eric GELOEN <[email protected]>
7+
*
8+
* For the full copyright and license information, please read the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Http\Adapter\Tests;
13+
14+
use GuzzleHttp\Client;
15+
use Http\Adapter\Guzzle6HttpAdapter;
16+
use Http\Client\Tests\HttpAsyncClientTest;
17+
18+
/**
19+
* @author GeLo <[email protected]>
20+
*/
21+
abstract class Guzzle6HttpAsyncAdapterTest extends HttpAsyncClientTest
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
protected function createHttpAsyncClient()
27+
{
28+
return new Guzzle6HttpAdapter(new Client(['handler' => $this->createHandler()]));
29+
}
30+
31+
/**
32+
* Returns a handler for the client
33+
*
34+
* @return object
35+
*/
36+
abstract protected function createHandler();
37+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Http Adapter package.
5+
*
6+
* (c) Eric GELOEN <[email protected]>
7+
*
8+
* For the full copyright and license information, please read the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Http\Adapter\Tests;
13+
14+
use GuzzleHttp\Handler\CurlMultiHandler;
15+
16+
/**
17+
* @author GeLo <[email protected]>
18+
*/
19+
class Guzzle6MultiCurlHttpAsyncAdapterTest extends Guzzle6HttpAsyncAdapterTest
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
protected function createHandler()
25+
{
26+
return new CurlMultiHandler();
27+
}
28+
}

0 commit comments

Comments
 (0)