304ec363bf1d7acdbf59ecf80b2e418c12b217a8
[m6w6/seekat] / lib / API / Call / Deferred.php
1 <?php
2
3 namespace seekat\API\Call;
4
5 use http\{
6 Client, Client\Request, Client\Response
7 };
8 use Psr\Log\LoggerInterface;
9 use seekat\API;
10
11 final class Deferred
12 {
13 /**
14 * The response importer
15 *
16 * @var Result
17 */
18 private $result;
19
20 /**
21 * The HTTP client
22 *
23 * @var Client
24 */
25 private $client;
26
27 /**
28 * Request cache
29 *
30 * @var callable
31 */
32 private $cache;
33
34 /**
35 * @var LoggerInterface
36 */
37 private $logger;
38
39 /**
40 * The executed request
41 *
42 * @var Request
43 */
44 private $request;
45
46 /**
47 * The promised response
48 *
49 * @var Response
50 */
51 private $response;
52
53 /**
54 * @var mixed
55 */
56 private $promise;
57
58 /**
59 * @var \Closure
60 */
61 private $resolve;
62
63 /**
64 * @var \Closure
65 */
66 private $reject;
67
68 /**
69 * @var \Closure
70 */
71 private $update;
72
73 /**
74 * Create a deferred promise for the response of $request
75 *
76 * @param API $api The endpoint of the request
77 * @param Request $request The request to execute
78 * @param Cache\Service $cache
79 */
80 function __construct(API $api, Request $request, Cache\Service $cache = null) {
81 $this->request = $request;
82 $this->client = $api->getClient();
83 $this->logger = $api->getLogger();
84 $this->result = new Result($api);
85 $this->cache = new Cache($cache);
86
87 $future = $api->getFuture();
88 $context = $future->createContext(function() {
89 if ($this->response) {
90 /* we did finish in the meantime */
91 $this->complete();
92 } else {
93 $this->client->dequeue($this->request);
94 ($this->reject)("Cancelled");
95 }
96 });
97 $this->promise = $future->getPromise($context);
98 $this->resolve = API\Future\resolver($future, $context);
99 $this->reject = API\Future\rejecter($future, $context);
100 }
101
102 function __invoke() {
103 if ($this->cache->load($this->request, $cached)) {
104 $this->logger->info("deferred -> cached", [
105 "method" => $this->request->getRequestMethod(),
106 "url" => $this->request->getRequestUrl(),
107 ]);
108
109 $this->response = $cached;
110 $this->complete();
111 } else {
112 $this->client->enqueue($this->request, function(Response $response) use($cached) {
113 if ($response->getResponseCode() == 304) {
114 $this->response = $cached;
115 } else {
116 $this->response = $response;
117 }
118 $this->complete();
119 return true;
120 });
121 $this->logger->info("deferred -> enqueued", [
122 "method" => $this->request->getRequestMethod(),
123 "url" => $this->request->getRequestUrl(),
124 ]);
125 /* start off */
126 $this->client->once();
127 }
128
129 return $this->promise;
130 }
131
132 /**
133 * Completion callback
134 */
135 private function complete() {
136 if ($this->response) {
137 try {
138 $api = ($this->result)($this->response);
139
140 $this->cache->save($this->request, $this->response);
141
142 ($this->resolve)($api);
143 } catch (\Throwable $e) {
144 ($this->reject)($e);
145 }
146 } else {
147 ($this->reject)($this->client->getTransferInfo($this->request)->error);
148 }
149 }
150
151 }