Skip to content
This repository was archived by the owner on Dec 29, 2019. It is now read-only.

Commit ceaa705

Browse files
committed
Add first version of interface and a promise implementation
1 parent c6eeb5f commit ceaa705

File tree

3 files changed

+143
-1
lines changed

3 files changed

+143
-1
lines changed

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
}
1111
],
1212
"require": {
13-
"php": "^5.4 || ^7.0"
13+
"php": "^5.4 || ^7.0",
14+
"async-interop/promise": "^0.2.0",
15+
"psr/http-message": "^1.0",
16+
"php-http/httplug": "^1.1",
17+
"async-interop/event-loop": "^0.3.0"
1418
},
1519
"require-dev": {
1620
"phpspec/phpspec": "^2.4",

src/HttpAsyncClient.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Http\Client\Async;
4+
5+
use Interop\Async\Promise;
6+
use Psr\Http\Message\RequestInterface;
7+
8+
interface HttpAsyncClient
9+
{
10+
/**
11+
* Sends a PSR-7 request in an asynchronous way.
12+
*
13+
* Exceptions related to processing the request are available from the returned Promise.
14+
*
15+
* @param RequestInterface $request
16+
*
17+
* @return Promise An async interop Promise which resolves a PSR-7 Response or fails with an Http\Client\Exception.
18+
*
19+
* @throws \Exception If processing the request is impossible (eg. bad configuration).
20+
*/
21+
public function sendAsyncRequest(RequestInterface $request);
22+
}

src/Promise/Future.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
namespace Http\Client\Async\Promise;
4+
5+
use Http\Client\Exception;
6+
use Interop\Async\Loop;
7+
use Interop\Async\Promise;
8+
use Psr\Http\Message\ResponseInterface;
9+
10+
class Future implements Promise
11+
{
12+
const STATE_PENDING = 'pending';
13+
const STATE_SUCCEEDED = 'succeeded';
14+
const STATE_FAILED = 'failed';
15+
16+
/** @var array An array of callable which will be called when the promise is resolved */
17+
private $callbackQueue = [];
18+
19+
/** @var ResponseInterface response keeped in case of the promise is used after being resolved */
20+
private $response;
21+
22+
/** @var Exception exception which is keeped in case of the promise is used after being resolved */
23+
private $exception;
24+
25+
/** @var string Current state of the promise */
26+
private $state = self::STATE_PENDING;
27+
28+
/**
29+
* Resolve the promise with a success : PSR 7 Response
30+
*
31+
* @param ResponseInterface $response
32+
*
33+
* @throws \Exception
34+
*/
35+
public function success(ResponseInterface $response)
36+
{
37+
if ($this->state !== self::STATE_PENDING) {
38+
throw new \Exception('Promise already resolved');
39+
}
40+
41+
$this->state = self::STATE_SUCCEEDED;
42+
$this->response = $response;
43+
44+
foreach ($this->callbackQueue as $onResolved) {
45+
$this->resolve(function () use ($onResolved, $response) {
46+
$onResolved($response, null);
47+
});
48+
}
49+
}
50+
51+
/**
52+
* Resolve the promise with a failure : Http\Client\Exception
53+
*
54+
* @param Exception $exception
55+
*
56+
* @throws \Exception
57+
*/
58+
public function failure(Exception $exception)
59+
{
60+
if ($this->state !== self::STATE_PENDING) {
61+
throw new \Exception('Promise already resolved');
62+
}
63+
64+
$this->state = self::STATE_FAILED;
65+
$this->exception = $exception;
66+
67+
foreach ($this->callbackQueue as $onResolved) {
68+
$this->resolve(function () use ($onResolved, $exception) {
69+
$onResolved(null, $exception);
70+
});
71+
}
72+
}
73+
74+
/**
75+
* Internal resolution
76+
*
77+
* @param $callback
78+
*/
79+
private function resolve($callback) {
80+
try {
81+
$callback();
82+
// @Todo find a way to avoid using the loop as it force sync user to have an
83+
// event loop implementation
84+
} catch (\Throwable $exception) {
85+
Loop::defer(static function () use ($exception) {
86+
throw $exception;
87+
});
88+
} catch (\Exception $exception) {
89+
Loop::defer(static function () use ($exception) {
90+
throw $exception;
91+
});
92+
}
93+
}
94+
95+
/**
96+
* {@inheritdoc}
97+
*/
98+
public function when(callable $onResolved)
99+
{
100+
if ($this->state === self::STATE_PENDING) {
101+
$this->callbackQueue[] = $onResolved;
102+
}
103+
104+
if ($this->state === self::STATE_SUCCEEDED) {
105+
$this->resolve(function () use ($onResolved) {
106+
$onResolved($this->response, null);
107+
});
108+
}
109+
110+
if ($this->state === self::STATE_FAILED) {
111+
$this->resolve(function () use ($onResolved) {
112+
$onResolved(null, $this->exception);
113+
});
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)