namespace seekat\API;
-use Exception;
-use http\ {
- Client,
- Client\Request,
- Client\Response
-};
-use React\Promise\Deferred;
+use http\Url;
+use React\Promise\ExtendedPromiseInterface;
use seekat\API;
-use SplObserver;
-use SplSubject;
+use seekat\Exception;
-class Call extends Deferred implements SplObserver
+class Call
{
/**
- * The endpoint
* @var API
*/
private $api;
/**
- * The HTTP client
- * @var Client
+ * @var string
*/
- private $client;
+ private $call;
- /**
- * The executed request
- * @var Request
- */
- private $request;
-
- /**
- * The promised response
- * @var Response
- */
- private $response;
-
- /**
- * Create a deferred promise for the response of $request
- *
- * @param API $api The endpoint of the request
- * @param Client $client The HTTP client to send the request
- * @param Request $request The request to execute
- */
- function __construct(API $api, Client $client, Request $request) {
+ function __construct(API $api, string $call) {
$this->api = $api;
- $this->client = $client;
- $this->request = $request;
-
- parent::__construct(function($resolve, $reject) {
- return $this->cancel($resolve, $reject);
- });
-
- $client->attach($this);
- $client->enqueue($request, function(Response $response) {
- $this->response = $response;
- $this->complete(
- [$this, "resolve"],
- [$this, "reject"]
- );
- return true;
- });
- /* start off */
- $client->once();
+ $this->call = $call;
}
- /**
- * Progress observer
- *
- * Import the response's data on success and resolve the promise.
- *
- * @param SplSubject $client The observed HTTP client
- * @param Request $request The request which generated the update
- * @param object $progress The progress information
- */
- function update(SplSubject $client, Request $request = null, $progress = null) {
- if ($request !== $this->request) {
- return;
- }
+ function __invoke(array $args) : ExtendedPromiseInterface {
+ $promise = $this->api->{$this->call}->get(...$args);
- $this->notify((object) compact("client", "request", "progress"));
- }
+ /* fetch resource, unless already localized, and try for {$method}_url */
+ if (!$this->api->exists($this->call)) {
+ $promise = $promise->otherwise(function ($error) use($args) {
+ if ($this->api->exists($this->call."_url", $url)) {
+ $url = new Url(uri_template($url, (array)current($args)));
+ return $this->api->withUrl($url)->get(...$args);
+ }
- /**
- * Completion callback
- * @param callable $resolve
- * @param callable $reject
- */
- private function complete(callable $resolve, callable $reject) {
- $this->client->detach($this);
+ $message = Exception\message($error);
+ $this->api->getLogger()->error("call($this->call): " . $message, [
+ "url" => (string) $this->api->getUrl()
+ ]);
- if ($this->response) {
- try {
- $resolve($this->api->import($this->response));
- } catch (Exception $e) {
- $reject($e);
- }
- } else {
- $reject($this->client->getTransferInfo($this->request)->error);
+ throw $error;
+ });
}
- }
- /**
- * Cancellation callback
- * @param callable $resolve
- * @param callable $reject
- */
- private function cancel(callable $resolve, callable $reject) {
- /* did we finish in the meantime? */
- if ($this->response) {
- $this->complete($resolve, $reject);
- } else {
- $this->client->detach($this);
- $this->client->dequeue($this->request);
- $reject("Cancelled");
- }
+ return $promise;
}
}