Skip to content

Commit a521fe8

Browse files
committed
Initial commit
0 parents  commit a521fe8

13 files changed

Lines changed: 367 additions & 0 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor
2+
/composer.lock

.travis.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
language: php
2+
php:
3+
- 5.3
4+
- 5.6
5+
- hhvm
6+
install:
7+
- composer install --prefer-source --no-interaction
8+
script:
9+
- phpunit --coverage-text

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 Christian Lück
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is furnished
10+
to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# clue/promise-timeout [![Build Status](https://travis-ci.org/clue/php-promise-timeout.svg?branch=master)](https://travis-ci.org/clue/php-promise-timeout)
2+
3+
A trivial implementation of timeouts for `Promise`s, built on top of [React PHP](http://reactphp.org/).
4+
5+
> Note: This project is in early alpha stage! Feel free to report any issues you encounter.
6+
7+
## Install
8+
9+
The recommended way to install this library is [through composer](http://getcomposer.org). [New to composer?](http://getcomposer.org/doc/00-intro.md)
10+
11+
```JSON
12+
{
13+
"require": {
14+
"clue/promise-timeout": "dev-master"
15+
}
16+
}
17+
```
18+
19+
## License
20+
21+
MIT

composer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "clue/promise-timeout",
3+
"description": "Trivial timeout implementation for Promises",
4+
"keywords": ["Promise", "timeout", "event-loop", "ReactPHP", "async"],
5+
"homepage": "https://github.com/clue/php-promise-timeout",
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Christian Lück",
10+
"email": "christian@lueck.tv"
11+
}
12+
],
13+
"autoload": {
14+
"psr-4": { "Clue\\Promise\\Timeout\\": "src/" },
15+
"files": [ "src/functions.php" ]
16+
},
17+
"require": {
18+
"php": ">=5.3",
19+
"react/event-loop": "~0.4.0|~0.3.0",
20+
"react/promise": "~2.0|~1.0"
21+
}
22+
}

phpunit.xml.dist

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit bootstrap="tests/bootstrap.php"
4+
colors="true"
5+
convertErrorsToExceptions="true"
6+
convertNoticesToExceptions="true"
7+
convertWarningsToExceptions="true"
8+
>
9+
<testsuites>
10+
<testsuite name="Promise Timeout Test Suite">
11+
<directory>./tests/</directory>
12+
</testsuite>
13+
</testsuites>
14+
<filter>
15+
<whitelist>
16+
<directory>./src/</directory>
17+
</whitelist>
18+
</filter>
19+
</phpunit>

src/TimeoutException.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Clue\Promise\Timeout;
4+
5+
use RuntimeException;
6+
7+
class TimeoutException extends RuntimeException
8+
{
9+
private $timeout;
10+
11+
public function __construct($timeout, $message = null, $code = null, $previous = null)
12+
{
13+
parent::__construct($message, $code, $previous);
14+
15+
$this->timeout = $timeout;
16+
}
17+
18+
public function getTimeout()
19+
{
20+
return $this->timeout;
21+
}
22+
}

src/functions.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Clue\Promise\Timeout;
4+
5+
use React\Promise\Deferred;
6+
use React\Promise\CancellablePromiseInterface;
7+
use React\EventLoop\LoopInterface;
8+
use React\Promise\PromiseInterface;
9+
10+
function await(PromiseInterface $promise, $time, LoopInterface $loop)
11+
{
12+
$deferred = new Deferred();
13+
14+
$timer = $loop->addTimer($time, function () use ($time, $promise, $deferred) {
15+
$deferred->reject(new TimeoutException($time, 'Timed out after ' . $time . ' seconds'));
16+
17+
if ($promise instanceof CancellablePromiseInterface) {
18+
$promise->cancel();
19+
}
20+
});
21+
22+
$promise->then(function ($v) use ($timer, $loop, $deferred) {
23+
$loop->cancelTimer($timer);
24+
$deferred->resolve($v);
25+
}, function ($v) use ($timer, $loop, $deferred) {
26+
$loop->cancelTimer($timer);
27+
$deferred->reject($v);
28+
});
29+
30+
return $deferred->promise();
31+
}
32+
33+
function resolve($time, LoopInterface $loop)
34+
{
35+
$deferred = new Deferred();
36+
37+
$timer = $loop->addTimer($time, function () use ($time, $deferred) {
38+
$deferred->resolve($time);
39+
});
40+
41+
return $deferred->promise();
42+
}
43+
44+
function reject($time, LoopInterface $loop)
45+
{
46+
return resolve($time, $loop)->then(function ($time) {
47+
throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');
48+
});
49+
}

tests/FunctionAwaitTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
use Clue\Promise\Timeout;
4+
use React\Promise;
5+
6+
class FunctionAwaitTest extends TestCase
7+
{
8+
public function testResolvedWillResolveRightAway()
9+
{
10+
$promise = Promise\resolve();
11+
12+
$promise = Timeout\await($promise, 3, $this->loop);
13+
14+
$this->expectPromiseResolved($promise);
15+
}
16+
17+
public function testResolvedWillNotStartTimer()
18+
{
19+
$promise = Promise\resolve();
20+
21+
Timeout\await($promise, 3, $this->loop);
22+
23+
$time = microtime(true);
24+
$this->loop->run();
25+
$time = microtime(true) - $time;
26+
27+
$this->assertLessThan(0.5, $time);
28+
}
29+
30+
public function testRejectedWillRejectRightAway()
31+
{
32+
$promise = Promise\reject();
33+
34+
$promise = Timeout\await($promise, 3, $this->loop);
35+
36+
$this->expectPromiseRejected($promise);
37+
}
38+
39+
public function testRejectedWillNotStartTimer()
40+
{
41+
$promise = Promise\reject();
42+
43+
Timeout\await($promise, 3, $this->loop);
44+
45+
$time = microtime(true);
46+
$this->loop->run();
47+
$time = microtime(true) - $time;
48+
49+
$this->assertLessThan(0.5, $time);
50+
}
51+
52+
public function testPendingWillRejectOnTimeout()
53+
{
54+
$promise = $this->getMock('React\Promise\PromiseInterface');
55+
56+
$promise = Timeout\await($promise, 0.01, $this->loop);
57+
58+
$this->loop->run();
59+
60+
$this->expectPromiseRejected($promise);
61+
}
62+
63+
public function testPendingCancellableWillBeCancelledOnTimeout()
64+
{
65+
if (!interface_exists('React\Promise\CancellablePromiseInterface', true)) {
66+
$this->markTestSkipped('Your (outdated?) Promise API does not support cancellable promises');
67+
}
68+
69+
$promise = $this->getMock('React\Promise\CancellablePromiseInterface');
70+
$promise->expects($this->once())->method('cancel');
71+
72+
73+
Timeout\await($promise, 0.01, $this->loop);
74+
75+
$this->loop->run();
76+
}
77+
}

tests/FunctionRejectTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
use Clue\Promise\Timeout;
4+
5+
class FunctionRejectTest extends TestCase
6+
{
7+
public function testPromiseIsPendingWithoutRunningLoop()
8+
{
9+
$promise = Timeout\reject(0.01, $this->loop);
10+
11+
$this->expectPromisePending($promise);
12+
}
13+
14+
public function testPromiseWillBeRejectedOnTimeout()
15+
{
16+
$promise = Timeout\reject(0.01, $this->loop);
17+
18+
$this->loop->run();
19+
20+
$this->expectPromiseRejected($promise);
21+
}
22+
}

0 commit comments

Comments
 (0)