Minor dependency updates
[yaffs-website] / vendor / guzzlehttp / guzzle / src / RetryMiddleware.php
1 <?php
2 namespace GuzzleHttp;
3
4 use GuzzleHttp\Promise\PromiseInterface;
5 use GuzzleHttp\Promise\RejectedPromise;
6 use GuzzleHttp\Psr7;
7 use Psr\Http\Message\RequestInterface;
8 use Psr\Http\Message\ResponseInterface;
9
10 /**
11  * Middleware that retries requests based on the boolean result of
12  * invoking the provided "decider" function.
13  */
14 class RetryMiddleware
15 {
16     /** @var callable  */
17     private $nextHandler;
18
19     /** @var callable */
20     private $decider;
21
22     /**
23      * @param callable $decider     Function that accepts the number of retries,
24      *                              a request, [response], and [exception] and
25      *                              returns true if the request is to be
26      *                              retried.
27      * @param callable $nextHandler Next handler to invoke.
28      * @param callable $delay       Function that accepts the number of retries
29      *                              and [response] and returns the number of
30      *                              milliseconds to delay.
31      */
32     public function __construct(
33         callable $decider,
34         callable $nextHandler,
35         callable $delay = null
36     ) {
37         $this->decider = $decider;
38         $this->nextHandler = $nextHandler;
39         $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
40     }
41
42     /**
43      * Default exponential backoff delay function.
44      *
45      * @param $retries
46      *
47      * @return int
48      */
49     public static function exponentialDelay($retries)
50     {
51         return (int) pow(2, $retries - 1);
52     }
53
54     /**
55      * @param RequestInterface $request
56      * @param array            $options
57      *
58      * @return PromiseInterface
59      */
60     public function __invoke(RequestInterface $request, array $options)
61     {
62         if (!isset($options['retries'])) {
63             $options['retries'] = 0;
64         }
65
66         $fn = $this->nextHandler;
67         return $fn($request, $options)
68             ->then(
69                 $this->onFulfilled($request, $options),
70                 $this->onRejected($request, $options)
71             );
72     }
73
74     private function onFulfilled(RequestInterface $req, array $options)
75     {
76         return function ($value) use ($req, $options) {
77             if (!call_user_func(
78                 $this->decider,
79                 $options['retries'],
80                 $req,
81                 $value,
82                 null
83             )) {
84                 return $value;
85             }
86             return $this->doRetry($req, $options, $value);
87         };
88     }
89
90     private function onRejected(RequestInterface $req, array $options)
91     {
92         return function ($reason) use ($req, $options) {
93             if (!call_user_func(
94                 $this->decider,
95                 $options['retries'],
96                 $req,
97                 null,
98                 $reason
99             )) {
100                 return \GuzzleHttp\Promise\rejection_for($reason);
101             }
102             return $this->doRetry($req, $options);
103         };
104     }
105
106     private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
107     {
108         $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
109
110         return $this($request, $options);
111     }
112 }