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