init
This commit is contained in:
2
vendor/react/promise-timer/.gitignore
vendored
Executable file
2
vendor/react/promise-timer/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
/vendor
|
||||
/composer.lock
|
||||
26
vendor/react/promise-timer/.travis.yml
vendored
Executable file
26
vendor/react/promise-timer/.travis.yml
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
# - 5.3 # requires old distro, see below
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- hhvm # ignore errors, see below
|
||||
|
||||
# lock distro so new future defaults will not break the build
|
||||
dist: trusty
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.3
|
||||
dist: precise
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
|
||||
install:
|
||||
- composer install --no-interaction
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit --coverage-text
|
||||
63
vendor/react/promise-timer/CHANGELOG.md
vendored
Executable file
63
vendor/react/promise-timer/CHANGELOG.md
vendored
Executable file
@@ -0,0 +1,63 @@
|
||||
# Changelog
|
||||
|
||||
## 1.5.1 (2019-03-27)
|
||||
|
||||
* Fix: Typo in readme
|
||||
(#35 by @aak74)
|
||||
|
||||
* Improvement: Only include functions file when functions aren't defined
|
||||
(#36 by @Niko9911)
|
||||
|
||||
## 1.5.0 (2018-06-13)
|
||||
|
||||
* Feature: Improve memory consumption by cleaning up garbage references to pending promise without canceller.
|
||||
(#34 by @clue)
|
||||
|
||||
## 1.4.0 (2018-06-11)
|
||||
|
||||
* Feature: Improve memory consumption by cleaning up garbage references.
|
||||
(#33 by @clue)
|
||||
|
||||
## 1.3.0 (2018-04-24)
|
||||
|
||||
* Feature: Improve memory consumption by cleaning up unneeded references.
|
||||
(#32 by @clue)
|
||||
|
||||
## 1.2.1 (2017-12-22)
|
||||
|
||||
* README improvements
|
||||
(#28 by @jsor)
|
||||
|
||||
* Improve test suite by adding forward compatiblity with PHPUnit 6 and
|
||||
fix test suite forward compatibility with upcoming EventLoop releases
|
||||
(#30 and #31 by @clue)
|
||||
|
||||
## 1.2.0 (2017-08-08)
|
||||
|
||||
* Feature: Only start timers if input Promise is still pending and
|
||||
return a settled output promise if the input is already settled.
|
||||
(#25 by @clue)
|
||||
|
||||
* Feature: Cap minimum timer interval at 1µs across all versions
|
||||
(#23 by @clue)
|
||||
|
||||
* Feature: Forward compatibility with EventLoop v1.0 and v0.5
|
||||
(#27 by @clue)
|
||||
|
||||
* Improve test suite by adding PHPUnit to require-dev and
|
||||
lock Travis distro so new defaults will not break the build
|
||||
(#24 and #26 by @clue)
|
||||
|
||||
## 1.1.1 (2016-12-27)
|
||||
|
||||
* Improve test suite to use PSR-4 autoloader and proper namespaces.
|
||||
(#21 by @clue)
|
||||
|
||||
## 1.1.0 (2016-02-29)
|
||||
|
||||
* Feature: Support promise cancellation for all timer primitives
|
||||
(#18 by @clue)
|
||||
|
||||
## 1.0.0 (2015-09-29)
|
||||
|
||||
* First tagged release
|
||||
21
vendor/react/promise-timer/LICENSE
vendored
Executable file
21
vendor/react/promise-timer/LICENSE
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Christian Lück
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
372
vendor/react/promise-timer/README.md
vendored
Executable file
372
vendor/react/promise-timer/README.md
vendored
Executable file
@@ -0,0 +1,372 @@
|
||||
# PromiseTimer
|
||||
|
||||
[](https://travis-ci.org/reactphp/promise-timer)
|
||||
|
||||
A trivial implementation of timeouts for `Promise`s, built on top of [ReactPHP](https://reactphp.org/).
|
||||
|
||||
**Table of contents**
|
||||
|
||||
* [Usage](#usage)
|
||||
* [timeout()](#timeout)
|
||||
* [Timeout cancellation](#timeout-cancellation)
|
||||
* [Cancellation handler](#cancellation-handler)
|
||||
* [Input cancellation](#input-cancellation)
|
||||
* [Output cancellation](#output-cancellation)
|
||||
* [Collections](#collections)
|
||||
* [resolve()](#resolve)
|
||||
* [Resolve cancellation](#resolve-cancellation)
|
||||
* [reject()](#reject)
|
||||
* [Reject cancellation](#reject-cancellation)
|
||||
* [TimeoutException](#timeoutexception)
|
||||
* [Install](#install)
|
||||
* [Tests](#tests)
|
||||
* [License](#license)
|
||||
|
||||
## Usage
|
||||
|
||||
This lightweight library consists only of a few simple functions.
|
||||
All functions reside under the `React\Promise\Timer` namespace.
|
||||
|
||||
The below examples assume you use an import statement similar to this:
|
||||
|
||||
```php
|
||||
use React\Promise\Timer;
|
||||
|
||||
Timer\timeout(…);
|
||||
```
|
||||
|
||||
Alternatively, you can also refer to them with their fully-qualified name:
|
||||
|
||||
```php
|
||||
\React\Promise\Timer\timeout(…);
|
||||
```
|
||||
|
||||
### timeout()
|
||||
|
||||
The `timeout(PromiseInterface $promise, $time, LoopInterface $loop)` function
|
||||
can be used to *cancel* operations that take *too long*.
|
||||
You need to pass in an input `$promise` that represents a pending operation and timeout parameters.
|
||||
It returns a new `Promise` with the following resolution behavior:
|
||||
|
||||
* If the input `$promise` resolves before `$time` seconds, resolve the resulting promise with its fulfillment value.
|
||||
* If the input `$promise` rejects before `$time` seconds, reject the resulting promise with its rejection value.
|
||||
* If the input `$promise` does not settle before `$time` seconds, *cancel* the operation and reject the resulting promise with a [`TimeoutException`](#timeoutexception).
|
||||
|
||||
Internally, the given `$time` value will be used to start a timer that will
|
||||
*cancel* the pending operation once it triggers.
|
||||
This implies that if you pass a really small (or negative) value, it will still
|
||||
start a timer and will thus trigger at the earliest possible time in the future.
|
||||
|
||||
If the input `$promise` is already settled, then the resulting promise will
|
||||
resolve or reject immediately without starting a timer at all.
|
||||
|
||||
A common use case for handling only resolved values looks like this:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
Timer\timeout($promise, 10.0, $loop)->then(function ($value) {
|
||||
// the operation finished within 10.0 seconds
|
||||
});
|
||||
```
|
||||
|
||||
A more complete example could look like this:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
Timer\timeout($promise, 10.0, $loop)->then(
|
||||
function ($value) {
|
||||
// the operation finished within 10.0 seconds
|
||||
},
|
||||
function ($error) {
|
||||
if ($error instanceof Timer\TimeoutException) {
|
||||
// the operation has failed due to a timeout
|
||||
} else {
|
||||
// the input operation has failed due to some other error
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Or if you're using [react/promise v2.2.0](https://github.com/reactphp/promise) or up:
|
||||
|
||||
```php
|
||||
Timer\timeout($promise, 10.0, $loop)
|
||||
->then(function ($value) {
|
||||
// the operation finished within 10.0 seconds
|
||||
})
|
||||
->otherwise(function (Timer\TimeoutException $error) {
|
||||
// the operation has failed due to a timeout
|
||||
})
|
||||
->otherwise(function ($error) {
|
||||
// the input operation has failed due to some other error
|
||||
})
|
||||
;
|
||||
```
|
||||
|
||||
#### Timeout cancellation
|
||||
|
||||
As discussed above, the [`timeout()`](#timeout) function will *cancel* the
|
||||
underlying operation if it takes *too long*.
|
||||
This means that you can be sure the resulting promise will then be rejected
|
||||
with a [`TimeoutException`](#timeoutexception).
|
||||
|
||||
However, what happens to the underlying input `$promise` is a bit more tricky:
|
||||
Once the timer fires, we will try to call
|
||||
[`$promise->cancel()`](https://github.com/reactphp/promise#cancellablepromiseinterfacecancel)
|
||||
on the input `$promise` which in turn invokes its [cancellation handler](#cancellation-handler).
|
||||
|
||||
This means that it's actually up the input `$promise` to handle
|
||||
[cancellation support](https://github.com/reactphp/promise#cancellablepromiseinterface).
|
||||
|
||||
* A common use case involves cleaning up any resources like open network sockets or
|
||||
file handles or terminating external processes or timers.
|
||||
|
||||
* If the given input `$promise` does not support cancellation, then this is a NO-OP.
|
||||
This means that while the resulting promise will still be rejected, the underlying
|
||||
input `$promise` may still be pending and can hence continue consuming resources.
|
||||
|
||||
See the following chapter for more details on the cancellation handler.
|
||||
|
||||
#### Cancellation handler
|
||||
|
||||
For example, an implementation for the above operation could look like this:
|
||||
|
||||
```php
|
||||
function accessSomeRemoteResource()
|
||||
{
|
||||
return new Promise(
|
||||
function ($resolve, $reject) use (&$socket) {
|
||||
// this will be called once the promise is created
|
||||
// a common use case involves opening any resources and eventually resolving
|
||||
$socket = createSocket();
|
||||
$socket->on('data', function ($data) use ($resolve) {
|
||||
$resolve($data);
|
||||
});
|
||||
},
|
||||
function ($resolve, $reject) use (&$socket) {
|
||||
// this will be called once calling `cancel()` on this promise
|
||||
// a common use case involves cleaning any resources and then rejecting
|
||||
$socket->close();
|
||||
$reject(new \RuntimeException('Operation cancelled'));
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
In this example, calling `$promise->cancel()` will invoke the registered cancellation
|
||||
handler which then closes the network socket and rejects the `Promise` instance.
|
||||
|
||||
If no cancellation handler is passed to the `Promise` constructor, then invoking
|
||||
its `cancel()` method it is effectively a NO-OP.
|
||||
This means that it may still be pending and can hence continue consuming resources.
|
||||
|
||||
For more details on the promise cancellation, please refer to the
|
||||
[Promise documentation](https://github.com/reactphp/promise#cancellablepromiseinterface).
|
||||
|
||||
#### Input cancellation
|
||||
|
||||
Irrespective of the timeout handling, you can also explicitly `cancel()` the
|
||||
input `$promise` at any time.
|
||||
This means that the `timeout()` handling does not affect cancellation of the
|
||||
input `$promise`, as demonstrated in the following example:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
$timeout = Timer\timeout($promise, 10.0, $loop);
|
||||
|
||||
$promise->cancel();
|
||||
```
|
||||
|
||||
The registered [cancellation handler](#cancellation-handler) is responsible for
|
||||
handling the `cancel()` call:
|
||||
|
||||
* A described above, a common use involves resource cleanup and will then *reject*
|
||||
the `Promise`.
|
||||
If the input `$promise` is being rejected, then the timeout will be aborted
|
||||
and the resulting promise will also be rejected.
|
||||
* If the input `$promise` is still pending, then the timout will continue
|
||||
running until the timer expires.
|
||||
The same happens if the input `$promise` does not register a
|
||||
[cancellation handler](#cancellation-handler).
|
||||
|
||||
#### Output cancellation
|
||||
|
||||
Similarily, you can also explicitly `cancel()` the resulting promise like this:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
$timeout = Timer\timeout($promise, 10.0, $loop);
|
||||
|
||||
$timeout->cancel();
|
||||
```
|
||||
|
||||
Note how this looks very similar to the above [input cancellation](#input-cancellation)
|
||||
example. Accordingly, it also behaves very similar.
|
||||
|
||||
Calling `cancel()` on the resulting promise will merely try
|
||||
to `cancel()` the input `$promise`.
|
||||
This means that we do not take over responsibility of the outcome and it's
|
||||
entirely up to the input `$promise` to handle cancellation support.
|
||||
|
||||
The registered [cancellation handler](#cancellation-handler) is responsible for
|
||||
handling the `cancel()` call:
|
||||
|
||||
* As described above, a common use involves resource cleanup and will then *reject*
|
||||
the `Promise`.
|
||||
If the input `$promise` is being rejected, then the timeout will be aborted
|
||||
and the resulting promise will also be rejected.
|
||||
* If the input `$promise` is still pending, then the timout will continue
|
||||
running until the timer expires.
|
||||
The same happens if the input `$promise` does not register a
|
||||
[cancellation handler](#cancellation-handler).
|
||||
|
||||
To re-iterate, note that calling `cancel()` on the resulting promise will merely
|
||||
try to cancel the input `$promise` only.
|
||||
It is then up to the cancellation handler of the input promise to settle the promise.
|
||||
If the input promise is still pending when the timeout occurs, then the normal
|
||||
[timeout cancellation](#timeout-cancellation) handling will trigger, effectively rejecting
|
||||
the output promise with a [`TimeoutException`](#timeoutexception).
|
||||
|
||||
This is done for consistency with the [timeout cancellation](#timeout-cancellation)
|
||||
handling and also because it is assumed this is often used like this:
|
||||
|
||||
```php
|
||||
$timeout = Timer\timeout(accessSomeRemoteResource(), 10.0, $loop);
|
||||
|
||||
$timeout->cancel();
|
||||
```
|
||||
|
||||
As described above, this example works as expected and cleans up any resources
|
||||
allocated for the input `$promise`.
|
||||
|
||||
Note that if the given input `$promise` does not support cancellation, then this
|
||||
is a NO-OP.
|
||||
This means that while the resulting promise will still be rejected after the
|
||||
timeout, the underlying input `$promise` may still be pending and can hence
|
||||
continue consuming resources.
|
||||
|
||||
#### Collections
|
||||
|
||||
If you want to wait for multiple promises to resolve, you can use the normal promise primitives like this:
|
||||
|
||||
```php
|
||||
$promises = array(
|
||||
accessSomeRemoteResource(),
|
||||
accessSomeRemoteResource(),
|
||||
accessSomeRemoteResource()
|
||||
);
|
||||
|
||||
$promise = \React\Promise\all($promises);
|
||||
|
||||
Timer\timeout($promise, 10, $loop)->then(function ($values) {
|
||||
// *all* promises resolved
|
||||
});
|
||||
```
|
||||
|
||||
The applies to all promise collection primitives alike, i.e. `all()`, `race()`, `any()`, `some()` etc.
|
||||
|
||||
For more details on the promise primitives, please refer to the
|
||||
[Promise documentation](https://github.com/reactphp/promise#functions).
|
||||
|
||||
### resolve()
|
||||
|
||||
The `resolve($time, LoopInterface $loop)` function can be used to create a new Promise that
|
||||
resolves in `$time` seconds with the `$time` as the fulfillment value.
|
||||
|
||||
```php
|
||||
Timer\resolve(1.5, $loop)->then(function ($time) {
|
||||
echo 'Thanks for waiting ' . $time . ' seconds' . PHP_EOL;
|
||||
});
|
||||
```
|
||||
|
||||
Internally, the given `$time` value will be used to start a timer that will
|
||||
resolve the promise once it triggers.
|
||||
This implies that if you pass a really small (or negative) value, it will still
|
||||
start a timer and will thus trigger at the earliest possible time in the future.
|
||||
|
||||
#### Resolve cancellation
|
||||
|
||||
You can explicitly `cancel()` the resulting timer promise at any time:
|
||||
|
||||
```php
|
||||
$timer = Timer\resolve(2.0, $loop);
|
||||
|
||||
$timer->cancel();
|
||||
```
|
||||
|
||||
This will abort the timer and *reject* with a `RuntimeException`.
|
||||
|
||||
### reject()
|
||||
|
||||
The `reject($time, LoopInterface $loop)` function can be used to create a new Promise
|
||||
which rejects in `$time` seconds with a `TimeoutException`.
|
||||
|
||||
```php
|
||||
Timer\reject(2.0, $loop)->then(null, function (TimeoutException $e) {
|
||||
echo 'Rejected after ' . $e->getTimeout() . ' seconds ' . PHP_EOL;
|
||||
});
|
||||
```
|
||||
|
||||
Internally, the given `$time` value will be used to start a timer that will
|
||||
reject the promise once it triggers.
|
||||
This implies that if you pass a really small (or negative) value, it will still
|
||||
start a timer and will thus trigger at the earliest possible time in the future.
|
||||
|
||||
This function complements the [`resolve()`](#resolve) function
|
||||
and can be used as a basic building block for higher-level promise consumers.
|
||||
|
||||
#### Reject cancellation
|
||||
|
||||
You can explicitly `cancel()` the resulting timer promise at any time:
|
||||
|
||||
```php
|
||||
$timer = Timer\reject(2.0, $loop);
|
||||
|
||||
$timer->cancel();
|
||||
```
|
||||
|
||||
This will abort the timer and *reject* with a `RuntimeException`.
|
||||
|
||||
### TimeoutException
|
||||
|
||||
The `TimeoutException` extends PHP's built-in `RuntimeException`.
|
||||
|
||||
The `getTimeout()` method can be used to get the timeout value in seconds.
|
||||
|
||||
## Install
|
||||
|
||||
The recommended way to install this library is [through Composer](https://getcomposer.org).
|
||||
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
|
||||
|
||||
This project follows [SemVer](https://semver.org/).
|
||||
This will install the latest supported version:
|
||||
|
||||
```bash
|
||||
$ composer require react/promise-timer:^1.5
|
||||
```
|
||||
|
||||
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
|
||||
|
||||
This project aims to run on any platform and thus does not require any PHP
|
||||
extensions and supports running on legacy PHP 5.3 through current PHP 7+ and
|
||||
HHVM.
|
||||
It's *highly recommended to use PHP 7+* for this project.
|
||||
|
||||
## Tests
|
||||
|
||||
To run the test suite, you first need to clone this repo and then install all
|
||||
dependencies [through Composer](https://getcomposer.org):
|
||||
|
||||
```bash
|
||||
$ composer install
|
||||
```
|
||||
|
||||
To run the test suite, go to the project root and run:
|
||||
|
||||
```bash
|
||||
$ php vendor/bin/phpunit
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT, see [LICENSE file](LICENSE).
|
||||
28
vendor/react/promise-timer/composer.json
vendored
Executable file
28
vendor/react/promise-timer/composer.json
vendored
Executable file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "react/promise-timer",
|
||||
"description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
|
||||
"keywords": ["Promise", "timeout", "timer", "event-loop", "ReactPHP", "async"],
|
||||
"homepage": "https://github.com/reactphp/promise-timer",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@lueck.tv"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": { "React\\Promise\\Timer\\": "src/" },
|
||||
"files": [ "src/functions_include.php" ]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "React\\Tests\\Promise\\Timer\\": "tests/" }
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3",
|
||||
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
|
||||
"react/promise": "^2.7.0 || ^1.2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.4 || ^5.7 || ^4.8.35"
|
||||
}
|
||||
}
|
||||
19
vendor/react/promise-timer/phpunit.xml.dist
vendored
Executable file
19
vendor/react/promise-timer/phpunit.xml.dist
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Promise Timer Test Suite">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./src/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
22
vendor/react/promise-timer/src/TimeoutException.php
vendored
Executable file
22
vendor/react/promise-timer/src/TimeoutException.php
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace React\Promise\Timer;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class TimeoutException extends RuntimeException
|
||||
{
|
||||
private $timeout;
|
||||
|
||||
public function __construct($timeout, $message = null, $code = null, $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
public function getTimeout()
|
||||
{
|
||||
return $this->timeout;
|
||||
}
|
||||
}
|
||||
81
vendor/react/promise-timer/src/functions.php
vendored
Executable file
81
vendor/react/promise-timer/src/functions.php
vendored
Executable file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace React\Promise\Timer;
|
||||
|
||||
use React\Promise\CancellablePromiseInterface;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Promise\PromiseInterface;
|
||||
use React\Promise\Promise;
|
||||
|
||||
function timeout(PromiseInterface $promise, $time, LoopInterface $loop)
|
||||
{
|
||||
// cancelling this promise will only try to cancel the input promise,
|
||||
// thus leaving responsibility to the input promise.
|
||||
$canceller = null;
|
||||
if ($promise instanceof CancellablePromiseInterface) {
|
||||
// pass promise by reference to clean reference after cancellation handler
|
||||
// has been invoked once in order to avoid garbage references in call stack.
|
||||
$canceller = function () use (&$promise) {
|
||||
$promise->cancel();
|
||||
$promise = null;
|
||||
};
|
||||
}
|
||||
|
||||
return new Promise(function ($resolve, $reject) use ($loop, $time, $promise) {
|
||||
$timer = null;
|
||||
$promise = $promise->then(function ($v) use (&$timer, $loop, $resolve) {
|
||||
if ($timer) {
|
||||
$loop->cancelTimer($timer);
|
||||
}
|
||||
$timer = false;
|
||||
$resolve($v);
|
||||
}, function ($v) use (&$timer, $loop, $reject) {
|
||||
if ($timer) {
|
||||
$loop->cancelTimer($timer);
|
||||
}
|
||||
$timer = false;
|
||||
$reject($v);
|
||||
});
|
||||
|
||||
// promise already resolved => no need to start timer
|
||||
if ($timer === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// start timeout timer which will cancel the input promise
|
||||
$timer = $loop->addTimer($time, function () use ($time, &$promise, $reject) {
|
||||
$reject(new TimeoutException($time, 'Timed out after ' . $time . ' seconds'));
|
||||
|
||||
// try to invoke cancellation handler of input promise and then clean
|
||||
// reference in order to avoid garbage references in call stack.
|
||||
if ($promise instanceof CancellablePromiseInterface) {
|
||||
$promise->cancel();
|
||||
}
|
||||
$promise = null;
|
||||
});
|
||||
}, $canceller);
|
||||
}
|
||||
|
||||
function resolve($time, LoopInterface $loop)
|
||||
{
|
||||
return new Promise(function ($resolve) use ($loop, $time, &$timer) {
|
||||
// resolve the promise when the timer fires in $time seconds
|
||||
$timer = $loop->addTimer($time, function () use ($time, $resolve) {
|
||||
$resolve($time);
|
||||
});
|
||||
}, function () use (&$timer, $loop) {
|
||||
// cancelling this promise will cancel the timer, clean the reference
|
||||
// in order to avoid garbage references in call stack and then reject.
|
||||
$loop->cancelTimer($timer);
|
||||
$timer = null;
|
||||
|
||||
throw new \RuntimeException('Timer cancelled');
|
||||
});
|
||||
}
|
||||
|
||||
function reject($time, LoopInterface $loop)
|
||||
{
|
||||
return resolve($time, $loop)->then(function ($time) {
|
||||
throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');
|
||||
});
|
||||
}
|
||||
7
vendor/react/promise-timer/src/functions_include.php
vendored
Executable file
7
vendor/react/promise-timer/src/functions_include.php
vendored
Executable file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace React\Promise\Timer;
|
||||
|
||||
if (!function_exists('React\\Promise\\Timer\\timeout')) {
|
||||
require __DIR__ . '/functions.php';
|
||||
}
|
||||
10
vendor/react/promise-timer/tests/CallableStub.php
vendored
Executable file
10
vendor/react/promise-timer/tests/CallableStub.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Promise\Timer;
|
||||
|
||||
class CallableStub
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
}
|
||||
}
|
||||
79
vendor/react/promise-timer/tests/FunctionRejectTest.php
vendored
Executable file
79
vendor/react/promise-timer/tests/FunctionRejectTest.php
vendored
Executable file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Promise\Timer;
|
||||
|
||||
use React\Promise\Timer;
|
||||
|
||||
class FunctionRejectTest extends TestCase
|
||||
{
|
||||
public function testPromiseIsPendingWithoutRunningLoop()
|
||||
{
|
||||
$promise = Timer\reject(0.01, $this->loop);
|
||||
|
||||
$this->expectPromisePending($promise);
|
||||
}
|
||||
|
||||
public function testPromiseExpiredIsPendingWithoutRunningLoop()
|
||||
{
|
||||
$promise = Timer\reject(-1, $this->loop);
|
||||
|
||||
$this->expectPromisePending($promise);
|
||||
}
|
||||
|
||||
public function testPromiseWillBeRejectedOnTimeout()
|
||||
{
|
||||
$promise = Timer\reject(0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
}
|
||||
|
||||
public function testPromiseExpiredWillBeRejectedOnTimeout()
|
||||
{
|
||||
$promise = Timer\reject(-1, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
}
|
||||
|
||||
public function testCancellingPromiseWillRejectTimer()
|
||||
{
|
||||
$promise = Timer\reject(0.01, $this->loop);
|
||||
|
||||
$promise->cancel();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToRejectDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = Timer\reject(0.01, $this->loop);
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testCancellingPromiseDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = Timer\reject(0.01, $this->loop);
|
||||
$promise->cancel();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
}
|
||||
101
vendor/react/promise-timer/tests/FunctionResolveTest.php
vendored
Executable file
101
vendor/react/promise-timer/tests/FunctionResolveTest.php
vendored
Executable file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Promise\Timer;
|
||||
|
||||
use React\Promise\Timer;
|
||||
|
||||
class FunctionResolveTest extends TestCase
|
||||
{
|
||||
public function testPromiseIsPendingWithoutRunningLoop()
|
||||
{
|
||||
$promise = Timer\resolve(0.01, $this->loop);
|
||||
|
||||
$this->expectPromisePending($promise);
|
||||
}
|
||||
|
||||
public function testPromiseExpiredIsPendingWithoutRunningLoop()
|
||||
{
|
||||
$promise = Timer\resolve(-1, $this->loop);
|
||||
|
||||
$this->expectPromisePending($promise);
|
||||
}
|
||||
|
||||
public function testPromiseWillBeResolvedOnTimeout()
|
||||
{
|
||||
$promise = Timer\resolve(0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->expectPromiseResolved($promise);
|
||||
}
|
||||
|
||||
public function testPromiseExpiredWillBeResolvedOnTimeout()
|
||||
{
|
||||
$promise = Timer\resolve(-1, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->expectPromiseResolved($promise);
|
||||
}
|
||||
|
||||
public function testWillStartLoopTimer()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addTimer')->with($this->equalTo(0.01));
|
||||
|
||||
Timer\resolve(0.01, $loop);
|
||||
}
|
||||
|
||||
public function testCancellingPromiseWillCancelLoopTimer()
|
||||
{
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$timer = $this->getMockBuilder(interface_exists('React\EventLoop\TimerInterface') ? 'React\EventLoop\TimerInterface' : 'React\EventLoop\Timer\TimerInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addTimer')->will($this->returnValue($timer));
|
||||
|
||||
$promise = Timer\resolve(0.01, $loop);
|
||||
|
||||
$loop->expects($this->once())->method('cancelTimer')->with($this->equalTo($timer));
|
||||
|
||||
$promise->cancel();
|
||||
}
|
||||
|
||||
public function testCancellingPromiseWillRejectTimer()
|
||||
{
|
||||
$promise = Timer\resolve(0.01, $this->loop);
|
||||
|
||||
$promise->cancel();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToResolveDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = Timer\resolve(0.01, $this->loop);
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testCancellingPromiseDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = Timer\resolve(0.01, $this->loop);
|
||||
$promise->cancel();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
}
|
||||
286
vendor/react/promise-timer/tests/FunctionTimeoutTest.php
vendored
Executable file
286
vendor/react/promise-timer/tests/FunctionTimeoutTest.php
vendored
Executable file
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Promise\Timer;
|
||||
|
||||
use React\Promise\Timer;
|
||||
use React\Promise;
|
||||
|
||||
class FunctionTimeoutTest extends TestCase
|
||||
{
|
||||
public function testResolvedWillResolveRightAway()
|
||||
{
|
||||
$promise = Promise\resolve();
|
||||
|
||||
$promise = Timer\timeout($promise, 3, $this->loop);
|
||||
|
||||
$this->expectPromiseResolved($promise);
|
||||
}
|
||||
|
||||
public function testResolvedExpiredWillResolveRightAway()
|
||||
{
|
||||
$promise = Promise\resolve();
|
||||
|
||||
$promise = Timer\timeout($promise, -1, $this->loop);
|
||||
|
||||
$this->expectPromiseResolved($promise);
|
||||
}
|
||||
|
||||
public function testResolvedWillNotStartTimer()
|
||||
{
|
||||
$promise = Promise\resolve();
|
||||
|
||||
Timer\timeout($promise, 3, $this->loop);
|
||||
|
||||
$time = microtime(true);
|
||||
$this->loop->run();
|
||||
$time = microtime(true) - $time;
|
||||
|
||||
$this->assertLessThan(0.5, $time);
|
||||
}
|
||||
|
||||
public function testRejectedWillRejectRightAway()
|
||||
{
|
||||
$promise = Promise\reject();
|
||||
|
||||
$promise = Timer\timeout($promise, 3, $this->loop);
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
}
|
||||
|
||||
public function testRejectedWillNotStartTimer()
|
||||
{
|
||||
$promise = Promise\reject();
|
||||
|
||||
Timer\timeout($promise, 3, $this->loop);
|
||||
|
||||
$time = microtime(true);
|
||||
$this->loop->run();
|
||||
$time = microtime(true) - $time;
|
||||
|
||||
$this->assertLessThan(0.5, $time);
|
||||
}
|
||||
|
||||
public function testPendingWillRejectOnTimeout()
|
||||
{
|
||||
$promise = $this->getMockBuilder('React\Promise\PromiseInterface')->getMock();
|
||||
|
||||
$promise = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
}
|
||||
|
||||
public function testPendingCancellableWillBeCancelledThroughFollowerOnTimeout()
|
||||
{
|
||||
$cancellable = $this->getMockBuilder('React\Promise\CancellablePromiseInterface')->getMock();
|
||||
$cancellable->expects($this->once())->method('cancel');
|
||||
|
||||
$promise = $this->getMockBuilder('React\Promise\CancellablePromiseInterface')->getMock();
|
||||
$promise->expects($this->once())->method('then')->willReturn($cancellable);
|
||||
|
||||
Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
}
|
||||
|
||||
public function testCancelTimeoutWithoutCancellationhandlerWillNotCancelTimerAndWillNotReject()
|
||||
{
|
||||
$promise = new \React\Promise\Promise(function () { });
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
|
||||
$timer = $this->getMockBuilder('React\EventLoop\Timer\TimerInterface')->getMock();
|
||||
$loop->expects($this->once())->method('addTimer')->will($this->returnValue($timer));
|
||||
$loop->expects($this->never())->method('cancelTimer');
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $loop);
|
||||
|
||||
$timeout->cancel();
|
||||
|
||||
$this->expectPromisePending($timeout);
|
||||
}
|
||||
|
||||
public function testResolvedPromiseWillNotStartTimer()
|
||||
{
|
||||
$promise = new \React\Promise\Promise(function ($resolve) { $resolve(true); });
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->never())->method('addTimer');
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $loop);
|
||||
|
||||
$this->expectPromiseResolved($timeout);
|
||||
}
|
||||
|
||||
public function testRejectedPromiseWillNotStartTimer()
|
||||
{
|
||||
$promise = Promise\reject(new \RuntimeException());
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$loop->expects($this->never())->method('addTimer');
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $loop);
|
||||
|
||||
$this->expectPromiseRejected($timeout);
|
||||
}
|
||||
|
||||
public function testCancelTimeoutWillCancelGivenPromise()
|
||||
{
|
||||
$promise = new \React\Promise\Promise(function () { }, $this->expectCallableOnce());
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$timeout->cancel();
|
||||
}
|
||||
|
||||
public function testCancelGivenPromiseWillReject()
|
||||
{
|
||||
$promise = new \React\Promise\Promise(function () { }, function ($resolve, $reject) { $reject(); });
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$promise->cancel();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
$this->expectPromiseRejected($timeout);
|
||||
}
|
||||
|
||||
public function testCancelTimeoutWillRejectIfGivenPromiseWillReject()
|
||||
{
|
||||
$promise = new \React\Promise\Promise(function () { }, function ($resolve, $reject) { $reject(); });
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$timeout->cancel();
|
||||
|
||||
$this->expectPromiseRejected($promise);
|
||||
$this->expectPromiseRejected($timeout);
|
||||
}
|
||||
|
||||
public function testCancelTimeoutWillResolveIfGivenPromiseWillResolve()
|
||||
{
|
||||
$promise = new \React\Promise\Promise(function () { }, function ($resolve, $reject) { $resolve(); });
|
||||
|
||||
$timeout = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$timeout->cancel();
|
||||
|
||||
$this->expectPromiseResolved($promise);
|
||||
$this->expectPromiseResolved($timeout);
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToResolveBeforeTimeoutDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = Timer\resolve(0.01, $this->loop);
|
||||
|
||||
$promise = Timer\timeout($promise, 1.0, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToRejectBeforeTimeoutDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = Timer\reject(0.01, $this->loop);
|
||||
|
||||
$promise = Timer\timeout($promise, 1.0, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToTimeoutDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = new \React\Promise\Promise(function () { }, function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
|
||||
$promise = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToTimeoutWithoutCancellerDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = new \React\Promise\Promise(function () { });
|
||||
|
||||
$promise = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testWaitingForPromiseToTimeoutWithNoOpCancellerDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = new \React\Promise\Promise(function () { }, function () {
|
||||
// no-op
|
||||
});
|
||||
|
||||
$promise = Timer\timeout($promise, 0.01, $this->loop);
|
||||
|
||||
$this->loop->run();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
|
||||
public function testCancellingPromiseDoesNotLeaveGarbageCycles()
|
||||
{
|
||||
if (class_exists('React\Promise\When')) {
|
||||
$this->markTestSkipped('Not supported on legacy Promise v1 API');
|
||||
}
|
||||
|
||||
gc_collect_cycles();
|
||||
|
||||
$promise = new \React\Promise\Promise(function () { }, function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
|
||||
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
$promise = Timer\timeout($promise, 0.01, $loop);
|
||||
$promise->cancel();
|
||||
unset($promise);
|
||||
|
||||
$this->assertEquals(0, gc_collect_cycles());
|
||||
}
|
||||
}
|
||||
61
vendor/react/promise-timer/tests/TestCase.php
vendored
Executable file
61
vendor/react/promise-timer/tests/TestCase.php
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Promise\Timer;
|
||||
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
use React\EventLoop\Factory;
|
||||
|
||||
class TestCase extends BaseTestCase
|
||||
{
|
||||
protected $loop;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->loop = Factory::create();
|
||||
}
|
||||
|
||||
protected function expectCallableOnce()
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
|
||||
$mock
|
||||
->expects($this->once())
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function expectCallableNever()
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
|
||||
$mock
|
||||
->expects($this->never())
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://github.com/reactphp/react/blob/master/tests/React/Tests/Socket/TestCase.php (taken from reactphp/react)
|
||||
*/
|
||||
protected function createCallableMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\Tests\Promise\Timer\CallableStub')->getMock();
|
||||
}
|
||||
|
||||
protected function expectPromiseRejected($promise)
|
||||
{
|
||||
return $promise->then($this->expectCallableNever(), $this->expectCallableOnce());
|
||||
}
|
||||
|
||||
protected function expectPromiseResolved($promise)
|
||||
{
|
||||
return $promise->then($this->expectCallableOnce(), $this->expectCallableNever());
|
||||
}
|
||||
|
||||
protected function expectPromisePending($promise)
|
||||
{
|
||||
return $promise->then($this->expectCallableNever(), $this->expectCallableNever());
|
||||
}
|
||||
}
|
||||
15
vendor/react/promise-timer/tests/TimeoutExceptionTest.php
vendored
Executable file
15
vendor/react/promise-timer/tests/TimeoutExceptionTest.php
vendored
Executable file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Promise\Timer;
|
||||
|
||||
use React\Promise\Timer\TimeoutException;
|
||||
|
||||
class TimeoutExceptionTest extends TestCase
|
||||
{
|
||||
public function testAccessTimeout()
|
||||
{
|
||||
$e = new TimeoutException(10);
|
||||
|
||||
$this->assertEquals(10, $e->getTimeout());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user