namespace seekat\API\Call;
-use AsyncInterop\Promise;
-use http\{
- Client, Client\Request, Client\Response
-};
+use http\{Client, Client\Request, Client\Response};
use Psr\Log\LoggerInterface;
use seekat\API;
-final class Deferred
-{
- /**
- * The response importer
- *
- * @var Result
- */
- private $result;
-
- /**
- * The HTTP client
- *
- * @var Client
- */
- private $client;
-
- /**
- * Request cache
- *
- * @var callable
- */
- private $cache;
-
- /**
- * @var LoggerInterface
- */
- private $logger;
-
- /**
- * The executed request
- *
- * @var Request
- */
- private $request;
+final class Deferred {
+ private Result $result;
+ private Client $client;
+ private LoggerInterface $logger;
+ private Cache $cache;
/**
* The promised response
- *
- * @var Response
- */
- private $response;
-
- /**
- * @var Promise
- */
- private $promise;
-
- /**
- * @var \Closure
- */
- private $resolve;
-
- /**
- * @var \Closure
*/
- private $reject;
+ private ?Response $response = null;
/**
- * @var \Closure
+ * @var mixed
*/
- private $update;
+ private object $promise;
+ private \Closure $resolve;
+ private \Closure $reject;
/**
* Create a deferred promise for the response of $request
*
* @param API $api The endpoint of the request
* @param Request $request The request to execute
- * @param Cache\Service $cache
*/
- function __construct(API $api, Request $request, Cache\Service $cache = null) {
- $this->request = $request;
+ function __construct(API $api, private readonly Request $request) {
+ $this->result = new Result($api);
$this->client = $api->getClient();
$this->logger = $api->getLogger();
- $this->result = new Result($api);
- $this->cache = new Cache($cache);
+ $this->cache = new Cache($this->logger, $api->getCache());
$future = $api->getFuture();
$context = $future->createContext(function() {
}
});
$this->promise = $future->getPromise($context);
- $this->resolve = API\Future\resolver($future, $context);
- $this->reject = API\Future\rejecter($future, $context);
+ $this->resolve = $future->resolver($context);
+ $this->reject = $future->rejecter($context);
}
- function __invoke() : Promise {
- if ($this->cache->load($this->request, $cached)) {
- $this->logger->info("deferred -> cached", [
- "method" => $this->request->getRequestMethod(),
- "url" => $this->request->getRequestUrl(),
- ]);
+ function __invoke() {
+ if (!$this->cached($cached)) {
+ $this->refresh($cached);
+ }
- $this->response = $cached;
- $this->complete();
+ return $this->promise;
+ }
+
+ /**
+ * Peek into cache
+ *
+ * @param Response $cached
+ * @return bool
+ */
+ private function cached(Response &$cached = null) : bool {
+ $fresh = $this->cache->load($this->request, $cachedResponse);
+
+ if (!$cachedResponse) {
+ return false;
} else {
- $this->client->enqueue($this->request, function(Response $response) use($cached) {
- if ($response->getResponseCode() == 304) {
- $this->response = $cached;
- } else {
- $this->response = $response;
- }
- $this->complete();
- return true;
- });
- $this->logger->info("deferred -> enqueued", [
+ $cached = $cachedResponse;
+
+ $this->logger->info("deferred -> cached", [
"method" => $this->request->getRequestMethod(),
"url" => $this->request->getRequestUrl(),
]);
- /* start off */
- $this->client->once();
+
+
+ if (!$fresh) {
+ $this->logger->info("cached -> stale", [
+ "method" => $this->request->getRequestMethod(),
+ "url" => $this->request->getRequestUrl(),
+ ]);
+ return false;
+ }
}
- return $this->promise;
+ $this->response = $cached;
+ $this->complete("cached");
+ return true;
+ }
+
+ private function refresh(Response $cached = null) : void {
+ $this->client->enqueue($this->request, function(Response $response) use($cached) {
+ $this->response = $response;
+ $this->complete();
+ return true;
+ });
+
+ $this->logger->info(($cached ? "stale" : "deferred") . " -> enqueued", [
+ "method" => $this->request->getRequestMethod(),
+ "url" => $this->request->getRequestUrl(),
+ ]);
+
+ /* start off */
+ $this->client->once();
}
/**
* Completion callback
*/
- private function complete() {
- if ($this->response) {
- try {
- $api = ($this->result)($this->response);
+ private function complete(string $by = "enqueued") : void {
+ $this->logger->info("complete -> $by");
- $this->cache->save($this->request, $this->response);
+ if ($this->response) {
+ $this->logger->info("$by -> response", [
+ "url" => $this->request->getRequestUrl(),
+ "info" => $this->response->getInfo(),
+ ]);
- ($this->resolve)($api);
+ try {
+ $this->cache->update($this->request, $this->response);
+ ($this->resolve)(($this->result)($this->response));
} catch (\Throwable $e) {
+ $this->logger->warning("$by -> cache", ["exception" => $e]);
($this->reject)($e);
}
} else {
- ($this->reject)($this->client->getTransferInfo($this->request)->error);
+ $info = $this->client->getTransferInfo($this->request);
+
+ $this->logger->warning("$by -> no response", [
+ "url" => $this->request->getRequestUrl(),
+ "info" => $info
+ ]);
+
+ ($this->reject)($info->error);
}
}