Blame | Last modification | View Log | RSS feed
<?phpnamespace React\Promise\Timer;use React\EventLoop\LoopInterface;use React\Promise\CancellablePromiseInterface;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 || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \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;};}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 timerif ($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 || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {$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');});}