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