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