Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace React\Promise\Timer;
4
 
5
use React\EventLoop\LoopInterface;
6
use React\Promise\CancellablePromiseInterface;
7
use React\Promise\PromiseInterface;
8
use React\Promise\Promise;
9
 
10
function timeout(PromiseInterface $promise, $time, LoopInterface $loop)
11
{
12
    // cancelling this promise will only try to cancel the input promise,
13
    // thus leaving responsibility to the input promise.
14
    $canceller = null;
15
    if ($promise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {
16
        // pass promise by reference to clean reference after cancellation handler
17
        // has been invoked once in order to avoid garbage references in call stack.
18
        $canceller = function () use (&$promise) {
19
            $promise->cancel();
20
            $promise = null;
21
        };
22
    }
23
 
24
    return new Promise(function ($resolve, $reject) use ($loop, $time, $promise) {
25
        $timer = null;
26
        $promise = $promise->then(function ($v) use (&$timer, $loop, $resolve) {
27
            if ($timer) {
28
                $loop->cancelTimer($timer);
29
            }
30
            $timer = false;
31
            $resolve($v);
32
        }, function ($v) use (&$timer, $loop, $reject) {
33
            if ($timer) {
34
                $loop->cancelTimer($timer);
35
            }
36
            $timer = false;
37
            $reject($v);
38
        });
39
 
40
        // promise already resolved => no need to start timer
41
        if ($timer === false) {
42
            return;
43
        }
44
 
45
        // start timeout timer which will cancel the input promise
46
        $timer = $loop->addTimer($time, function () use ($time, &$promise, $reject) {
47
            $reject(new TimeoutException($time, 'Timed out after ' . $time . ' seconds'));
48
 
49
            // try to invoke cancellation handler of input promise and then clean
50
            // reference in order to avoid garbage references in call stack.
51
            if ($promise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {
52
                $promise->cancel();
53
            }
54
            $promise = null;
55
        });
56
    }, $canceller);
57
}
58
 
59
function resolve($time, LoopInterface $loop)
60
{
61
    return new Promise(function ($resolve) use ($loop, $time, &$timer) {
62
        // resolve the promise when the timer fires in $time seconds
63
        $timer = $loop->addTimer($time, function () use ($time, $resolve) {
64
            $resolve($time);
65
        });
66
    }, function () use (&$timer, $loop) {
67
        // cancelling this promise will cancel the timer, clean the reference
68
        // in order to avoid garbage references in call stack and then reject.
69
        $loop->cancelTimer($timer);
70
        $timer = null;
71
 
72
        throw new \RuntimeException('Timer cancelled');
73
    });
74
}
75
 
76
function reject($time, LoopInterface $loop)
77
{
78
    return resolve($time, $loop)->then(function ($time) {
79
        throw new TimeoutException($time, 'Timer expired after ' . $time . ' seconds');
80
    });
81
}