update to PHP-8.1
[m6w6/seekat] / lib / API / Call / Cache.php
1 <?php
2
3 namespace seekat\API\Call;
4
5 use http\Client\Request;
6 use http\Client\Response;
7 use Psr\Log\LoggerInterface;
8 use seekat\API\Call\Cache\Control;
9 use seekat\API\Call\Cache\Service;
10 use seekat\API\Call\Cache\Service\Hollow;
11
12
13 final class Cache {
14 public function __construct(
15 private readonly LoggerInterface $logger,
16 private readonly Service $cache = new Hollow
17 ) {
18 }
19
20 /**
21 * Save call data
22 * @param Request $request
23 * @param Response $response
24 * @return bool
25 */
26 public function save(Request $request, Response $response) : bool {
27 $ctl = new Control($request);
28 if (!$ctl->isValid()) {
29 $this->logger->warning("cache -> save = invalid key", compact("ctl"));
30 return false;
31 }
32
33 $time = time();
34 if ($time - 1 <= $response->getHeader("X-Cache-Time")) {
35 $this->logger->info("cache -> save = no", compact("time"));
36 return true;
37 }
38 $response->setHeader("X-Cache-Time", $time);
39
40 $this->logger->info("cache -> save = yes", compact("time"));
41 return $this->cache->store($ctl->getKey(), $response);
42 }
43
44 /**
45 * Attempt to load call data
46 * @param Request $request
47 * @param Response $response out param
48 * @return bool
49 */
50 public function load(Request $request, Response &$response = null) : bool {
51 $ctl = new Control($request);
52 if (!$ctl->isValid()) {
53 $this->logger->warning("cache -> load = invalid key", compact("ctl"));
54 return false;
55 }
56
57 if (!$this->cache->fetch($ctl->getKey(), $response)) {
58 $this->logger->info("cache -> load = no");
59 return false;
60 }
61 if ($ctl->isStale($response)) {
62 if (($lmod = $response->getHeader("Last-Modified"))) {
63 $request->setOptions(["lastmodified" => strtotime($lmod)]);
64 }
65 if (($etag = $response->getHeader("ETag"))) {
66 $request->setOptions(["etag" => $etag]);
67 }
68 $this->logger->info("cache -> load = stale");
69 return false;
70 }
71 $response->setHeader("X-Cache-Hit", $response->getHeader("X-Cache-Hit") + 1);
72 $this->logger->info("cache -> load = yes");
73 return true;
74 }
75
76 /**
77 * Update call data
78 * @param Request $request
79 * @param Response $response
80 * @return bool
81 */
82 public function update(Request $request, Response &$response) : bool {
83 $ctl = new Control($request);
84 if (!$ctl->isValid()) {
85 $this->logger->warning("cache -> update = invalid key", compact("ctl"));
86 return false;
87 }
88
89 if ($response->getResponseCode() !== 304) {
90 $this->logger->info("cache -> update = yes");
91 return $this->save($request, $response);
92 }
93
94 /** @var Response $cached */
95 if (!$this->cache->fetch($ctl->getKey(), $cached)) {
96 $this->logger->info("cache -> update = yes; no-exist");
97 return $this->save($request, $response);
98 }
99
100 if ($response->getHeader("ETag") !== $cached->getHeader("ETag")) {
101 $this->logger->info("cache -> update = yes; etag");
102 return $this->save($request, $response);
103 }
104
105 $response = $cached;
106 $response->setHeader("X-Cache-Update", $cached->getHeader("X-Cache-Update") + 1);
107
108 $this->logger->info("cache -> update = yes; touch");
109 return $this->save($request, $response);
110 }
111 }