diff options
Diffstat (limited to 'vendor/react/promise-timer/src')
-rw-r--r-- | vendor/react/promise-timer/src/TimeoutException.php | 35 | ||||
-rw-r--r-- | vendor/react/promise-timer/src/functions.php | 330 | ||||
-rw-r--r-- | vendor/react/promise-timer/src/functions_include.php | 7 |
3 files changed, 372 insertions, 0 deletions
diff --git a/vendor/react/promise-timer/src/TimeoutException.php b/vendor/react/promise-timer/src/TimeoutException.php new file mode 100644 index 0000000..7f03ba0 --- /dev/null +++ b/vendor/react/promise-timer/src/TimeoutException.php @@ -0,0 +1,35 @@ +<?php + +namespace React\Promise\Timer; + +use RuntimeException; + +class TimeoutException extends RuntimeException +{ + /** @var float */ + private $timeout; + + /** + * @param float $timeout + * @param string|null $message + * @param int|null $code + * @param null|\Exception|\Throwable $previous + */ + public function __construct($timeout, $message = '', $code = 0, $previous = null) + { + // Preserve compatibility with our former nullable signature, but avoid invalid arguments for the parent constructor: + parent::__construct((string) $message, (int) $code, $previous); + + $this->timeout = (float) $timeout; + } + + /** + * Get the timeout value in seconds. + * + * @return float + */ + public function getTimeout() + { + return $this->timeout; + } +} diff --git a/vendor/react/promise-timer/src/functions.php b/vendor/react/promise-timer/src/functions.php new file mode 100644 index 0000000..b72bf36 --- /dev/null +++ b/vendor/react/promise-timer/src/functions.php @@ -0,0 +1,330 @@ +<?php + +namespace React\Promise\Timer; + +use React\EventLoop\Loop; +use React\EventLoop\LoopInterface; +use React\Promise\Promise; +use React\Promise\PromiseInterface; + +/** + * 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. + * + * This function takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use. You can use a `null` value here in order to + * use the [default loop](https://github.com/reactphp/event-loop#loop). This value + * SHOULD NOT be given unless you're sure you want to explicitly use a given event + * loop instance. + * + * A common use case for handling only resolved values looks like this: + * + * ```php + * $promise = accessSomeRemoteResource(); + * React\Promise\Timer\timeout($promise, 10.0)->then(function ($value) { + * // the operation finished within 10.0 seconds + * }); + * ``` + * + * A more complete example could look like this: + * + * ```php + * $promise = accessSomeRemoteResource(); + * React\Promise\Timer\timeout($promise, 10.0)->then( + * function ($value) { + * // the operation finished within 10.0 seconds + * }, + * function ($error) { + * if ($error instanceof React\Promise\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 v3](https://github.com/reactphp/promise): + * + * ```php + * React\Promise\Timer\timeout($promise, 10.0)->then(function ($value) { + * // the operation finished within 10.0 seconds + * })->catch(function (React\Promise\Timer\TimeoutException $error) { + * // the operation has failed due to a timeout + * })->catch(function (Throwable $error) { + * // the input operation has failed due to some other error + * }); + * ``` + * + * As discussed above, the [`timeout()`](#timeout) function will take care of + * the underlying operation if it takes *too long*. In this case, you can be + * sure the resulting promise will always be rejected with a + * [`TimeoutException`](#timeoutexception). On top of this, the function will + * try to *cancel* the underlying operation. Responsibility for this + * cancellation logic is left up to the underlying operation. + * + * - 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 + * + * On top of this, the returned promise is implemented in such a way that it can + * be cancelled when it is still pending. Cancelling a pending promise will + * cancel the underlying operation. As discussed above, responsibility for this + * cancellation logic is left up to the underlying operation. + * + * ```php + * $promise = accessSomeRemoteResource(); + * $timeout = React\Promise\Timer\timeout($promise, 10.0); + * + * $timeout->cancel(); + * ``` + * + * For more details on the promise cancellation, please refer to the + * [Promise documentation](https://github.com/reactphp/promise#cancellablepromiseinterface). + * + * 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); + * + * React\Promise\Timer\timeout($promise, 10)->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). + * + * @param PromiseInterface<mixed, \Throwable|mixed> $promise + * @param float $time + * @param ?LoopInterface $loop + * @return PromiseInterface<mixed, TimeoutException|\Throwable|mixed> + */ +function timeout(PromiseInterface $promise, $time, LoopInterface $loop = null) +{ + // cancelling this promise will only try to cancel the input promise, + // thus leaving responsibility to the input promise. + $canceller = null; + if (\method_exists($promise, 'cancel')) { + // 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; + }; + } + + if ($loop === null) { + $loop = Loop::get(); + } + + 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 (\method_exists($promise, 'cancel')) { + $promise->cancel(); + } + $promise = null; + }); + }, $canceller); +} + +/** + * Create a new promise that resolves in `$time` seconds. + * + * ```php + * React\Promise\Timer\sleep(1.5)->then(function () { + * echo 'Thanks for waiting!' . 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. + * + * This function takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use. You can use a `null` value here in order to + * use the [default loop](https://github.com/reactphp/event-loop#loop). This value + * SHOULD NOT be given unless you're sure you want to explicitly use a given event + * loop instance. + * + * The returned promise is implemented in such a way that it can be cancelled + * when it is still pending. Cancelling a pending promise will reject its value + * with a `RuntimeException` and clean up any pending timers. + * + * ```php + * $timer = React\Promise\Timer\sleep(2.0); + * + * $timer->cancel(); + * ``` + * + * @param float $time + * @param ?LoopInterface $loop + * @return PromiseInterface<void, \RuntimeException> + */ +function sleep($time, LoopInterface $loop = null) +{ + if ($loop === null) { + $loop = Loop::get(); + } + + $timer = null; + 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 ($resolve) { + $resolve(null); + }); + }, 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'); + }); +} + +/** + * [Deprecated] Create a new promise that resolves in `$time` seconds with the `$time` as the fulfillment value. + * + * ```php + * React\Promise\Timer\resolve(1.5)->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. + * + * This function takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use. You can use a `null` value here in order to + * use the [default loop](https://github.com/reactphp/event-loop#loop). This value + * SHOULD NOT be given unless you're sure you want to explicitly use a given event + * loop instance. + * + * The returned promise is implemented in such a way that it can be cancelled + * when it is still pending. Cancelling a pending promise will reject its value + * with a `RuntimeException` and clean up any pending timers. + * + * ```php + * $timer = React\Promise\Timer\resolve(2.0); + * + * $timer->cancel(); + * ``` + * + * @param float $time + * @param ?LoopInterface $loop + * @return PromiseInterface<float, \RuntimeException> + * @deprecated 1.8.0 See `sleep()` instead + * @see sleep() + */ +function resolve($time, LoopInterface $loop = null) +{ + return sleep($time, $loop)->then(function() use ($time) { + return $time; + }); +} + +/** + * [Deprecated] Create a new promise which rejects in `$time` seconds with a `TimeoutException`. + * + * ```php + * React\Promise\Timer\reject(2.0)->then(null, function (React\Promise\Timer\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 takes an optional `LoopInterface|null $loop` parameter that can be used to + * pass the event loop instance to use. You can use a `null` value here in order to + * use the [default loop](https://github.com/reactphp/event-loop#loop). This value + * SHOULD NOT be given unless you're sure you want to explicitly use a given event + * loop instance. + * + * The returned promise is implemented in such a way that it can be cancelled + * when it is still pending. Cancelling a pending promise will reject its value + * with a `RuntimeException` and clean up any pending timers. + * + * ```php + * $timer = React\Promise\Timer\reject(2.0); + * + * $timer->cancel(); + * ``` + * + * @param float $time + * @param LoopInterface $loop + * @return PromiseInterface<void, TimeoutException|\RuntimeException> + * @deprecated 1.8.0 See `sleep()` instead + * @see sleep() + */ +function reject($time, LoopInterface $loop = null) +{ + return sleep($time, $loop)->then(function () use ($time) { + throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds'); + }); +} diff --git a/vendor/react/promise-timer/src/functions_include.php b/vendor/react/promise-timer/src/functions_include.php new file mode 100644 index 0000000..1d5673a --- /dev/null +++ b/vendor/react/promise-timer/src/functions_include.php @@ -0,0 +1,7 @@ +<?php + +namespace React\Promise\Timer; + +if (!function_exists('React\\Promise\\Timer\\timeout')) { + require __DIR__ . '/functions.php'; +} |