inital commit
[pharext/pharext.org] / app / Github / Fetch.php
1 <?php
2
3 namespace app\Github;
4
5 use http\Header;
6 use http\Params;
7 use http\Url;
8
9 abstract class Fetch
10 {
11 /**
12 * @var \app\Github\API
13 */
14 protected $api;
15
16 /**
17 * @var \merry\Config
18 */
19 protected $config;
20
21 /**
22 * @var array
23 */
24 protected $args;
25
26 /**
27 * @var int
28 */
29 protected $page = 1;
30
31 /**
32 * @var \http\Url
33 */
34 protected $url;
35
36 function __construct(API $api, array $args = []) {
37 $this->api = $api;
38 $this->config = $api->getConfig();
39 $this->args = $args;
40 $this->url = new Url("https://api.github.com/", null, 0);
41 if (isset($this->config->fetch->{$this}->per_page)) {
42 header("X-Fetch-{$this}: ".$this->config->fetch->{$this}->per_page, false);
43 $this->url->query = "per_page=" . $this->config->fetch->{$this}->per_page;
44 }
45 }
46
47 function setPage($page) {
48 $this->page = $page;
49 return $this;
50 }
51
52 function getPage() {
53 return $this->page;
54 }
55
56 function __toString() {
57 $parts = explode("\\", get_class($this));
58 return strtolower(end($parts));
59 }
60
61 function getStorage(&$ttl = null) {
62 if (isset($this->config->storage->cache->{$this}->ttl)) {
63 $ttl = $this->config->storage->cache->{$this}->ttl;
64 }
65 return $this->api->getCacheStorage();
66 }
67
68 abstract function getRequest();
69 abstract function getException($message, $code, $previous = null);
70 abstract function getCacheKey();
71
72 function parseLinks(Header $header) {
73 $params = new Params($header->value, ",", ";", "=",
74 Params::PARSE_RFC5988 | Params::PARSE_ESCAPED);
75 $links = [];
76 foreach ($params->params as $link => $param) {
77 // strip enclosing brackets
78 $links[$param["arguments"]["rel"]] = $link;
79 }
80 return $links;
81 }
82
83 function __invoke(callable $callback) {
84 $ttl = -1;
85 $key = $this->getCacheKey();
86 if (($cache = $this->api->getCacheStorage())
87 && $cache->get($key, $cached, $ttl)) {
88 call_user_func_array($callback, $cached);
89 } else {
90 $this->enqueue($callback);
91 }
92 return $this->api->getClient();
93 }
94
95 protected function wrap(callable $callback) {
96 return function($response) use($callback) {
97 $rc = $response->getResponseCode();
98
99 if ($rc !== 200) {
100 if ($response->getHeader("Content-Type", Header::class)->match("application/json", Header::MATCH_WORD)) {
101 $message = json_decode($response->getBody())->message;
102 } else {
103 $message = $response->getBody();
104 }
105 throw $this->getException($message, $rc);
106 }
107
108 $json = json_decode($response->getBody());
109 if (($link = $response->getHeader("Link", Header::class))) {
110 $links = $this->parseLinks($link);
111 } else {
112 $links = [];
113 }
114
115 if (isset($json->error)) {
116 throw $this->getException($json->error_description, $rc);
117 } elseif (($cache = $this->getStorage($ttl))) {
118 $cache->set($this->getCacheKey(), [$json, $links], $ttl);
119 }
120
121 $callback($json, $links);
122
123 return true;
124 };
125 }
126
127 function enqueue(callable $callback) {
128 $request = $this->getRequest();
129 $wrapper = $this->wrap($callback);
130 return $this->api->getClient()->enqueue($request, $wrapper);
131 }
132 }