initial checkin
[m6w6/seekat] / lib / API / Deferred.php
1 <?php
2
3 namespace seekat\API;
4
5 use seekat\API;
6 use http\Client;
7 use http\Client\Request;
8 use http\Client\Response;
9
10 class Deferred extends \React\Promise\Deferred implements \SplObserver {
11
12 /**
13 * The endpoint
14 * @var \seekat\API
15 */
16 private $api;
17
18 /**
19 * The HTTP client
20 * @var \http\Client
21 */
22 private $client;
23
24 /**
25 * The executed request
26 * @var \http\Client\Request
27 */
28 private $request;
29
30 /**
31 * The promised response
32 * @var \http\Client\Response
33 */
34 private $response;
35
36 /**
37 * Create a deferred promise for the response of $request
38 *
39 * @var \seekat\API $api The endpoint of the request
40 * @var \http\Client $client The HTTP client to send the request
41 * @var \http\Client\Request The request to execute
42 */
43 function __construct(API $api, Client $client, Request $request) {
44 $this->api = $api;
45 $this->client = $client;
46 $this->request = $request;
47
48 $client->attach($this);
49 $client->enqueue($request);
50
51 parent::__construct(function($resolve, $reject) {
52 return $this->cancel($resolve, $reject);
53 });
54 }
55
56 /**
57 * Progress observer
58 *
59 * Import the response's data on success and resolve the promise.
60 *
61 * @var \SplSubject $client The observed HTTP client
62 * @var \http\Client\Request The request which generated the update
63 * @var object $progress The progress information
64 */
65 function update(\SplSubject $client, Request $request = null, $progress = null) {
66 if ($request !== $this->request) {
67 return;
68 }
69
70 $this->notify((object) compact("client", "request", "progress"));
71
72 if ($progress->info === "finished") {
73 $this->response = $this->client->getResponse();
74 $this->complete(
75 [$this, "resolve"],
76 [$this, "reject"]
77 );
78 }
79 }
80
81 /**
82 * Completion callback
83 * @param callable $resolve
84 * @param callable $reject
85 */
86 private function complete(callable $resolve, callable $reject) {
87 $this->client->detach($this);
88
89 if ($this->response) {
90 try {
91 $resolve($this->api->import($this->response));
92 } catch (\Exception $e) {
93 $reject($e);
94 }
95 } else {
96 $reject($this->client->getTransferInfo($this->request)["error"]);
97 }
98
99 $this->client->dequeue($this->request);
100 }
101
102 /**
103 * Cancellation callback
104 * @param callable $resolve
105 * @param callable $reject
106 */
107 private function cancel(callable $resolve, callable $reject) {
108 /* did we finish in the meantime? */
109 if ($this->response) {
110 $this->complete($resolve, $reject);
111 } else {
112 $this->client->detach($this);
113 $this->client->dequeue($this->request);
114 $reject("Cancelled");
115 }
116 }
117 }