|
5 | 5 | namespace Glued\Controllers;
|
6 | 6 |
|
7 | 7 | use Glued\Lib\Sql;
|
| 8 | +use Glued\Lib\TsSql; |
8 | 9 | use Psr\Http\Message\ResponseInterface as Response;
|
9 | 10 | use Psr\Http\Message\ServerRequestInterface as Request;
|
10 | 11 | use Glued\Lib\Controllers\AbstractService;
|
| 12 | +use Selective\Transformer\ArrayTransformer; |
11 | 13 |
|
12 | 14 | class IfController extends AbstractService
|
13 | 15 | {
|
@@ -97,107 +99,72 @@ public function getActions(Request $request, Response $response, array $args = [
|
97 | 99 | return $response->withJson($data);
|
98 | 100 | }
|
99 | 101 |
|
100 |
| -} |
101 |
| - |
102 |
| - |
103 |
| -/* |
104 |
| - public function runs_r1(Request $request, Response $response, array $args = []): Response |
105 |
| - { |
106 |
| - $rp = $this->utils->getQueryParams($request) ?? []; |
107 |
| - $qs = (new \Glued\Lib\IfSql())->q['json:runs:all']; |
108 |
| - $qs = (new \Glued\Lib\QueryBuilder())->select($qs); |
109 |
| - $qs = $this->utils->mysqlQueryFromRequest($qs, $rp, 'c_data'); |
110 |
| - $r = $this->mysqli->execute_query($qs,array_values($rp)); |
111 |
| - $res['status'] = 'ok'; |
112 |
| - foreach ($r as $i) { |
113 |
| - $res['data'][] = $i; |
114 |
| - } |
115 |
| - return $response->withJson($res); |
116 |
| - } |
117 |
| -
|
118 |
| - public function hello_r1(Request $request, Response $response, array $args = []): Response |
| 102 | + /** |
| 103 | + * Abstract method to get data from upstream (must be implemented in child classes). |
| 104 | + * @return array |
| 105 | + * |
| 106 | + * @example Example implementation: |
| 107 | + * ```php |
| 108 | + * $data = logic_getting_upstream_data(); |
| 109 | + * return $data; |
| 110 | + * ``` |
| 111 | + */ |
| 112 | + abstract protected function getUpstream(): array; |
| 113 | + |
| 114 | + /** |
| 115 | + * Abstract method to save raw and transformed upstream data (must be implemented in child classes). |
| 116 | + * |
| 117 | + * @param array $upstreamData The upstream data to save. |
| 118 | + * @return bool True if saving succeeded, false otherwise. |
| 119 | + * |
| 120 | + * @example Example implementation: |
| 121 | + * ```php |
| 122 | + * $xf = new ArrayTransformer(); |
| 123 | + * $xf->registerFilter("prefix", function ($value) { return "{$this->uuids['if:deployment']}/$value"; }); |
| 124 | + * $xf->map("uuid", "uuid") |
| 125 | + * ->map("key1", "key2"); |
| 126 | + * $tsdb = new TsSql($this->pg, "some_table_tsdb", "external_unique_id"); |
| 127 | + * return $tsdb->CommonCreateBatch($upstreamData, $xf); |
| 128 | + * ``` |
| 129 | + */ |
| 130 | + abstract protected function saveUpstream(array $upstreamData): bool; |
| 131 | + |
| 132 | + /** |
| 133 | + * Syncs upstream data if the last sync occurred more than the specified TTL (time-to-live). |
| 134 | + * |
| 135 | + * This method checks the cache for the last sync timestamp using the provided cache key. |
| 136 | + * If the last sync occurred more than `syncedTtl` seconds ago, it will attempt to sync upstream data. |
| 137 | + * After a successful sync, the cache is updated with the current timestamp. |
| 138 | + * The method returns an HTTP-like status code based on the result of the sync. |
| 139 | + * |
| 140 | + * @param string $cacheKey The key used to retrieve and store the sync timestamp in the cache. |
| 141 | + * @param int $syncedTtl The time-to-live (in seconds) for considering the upstream sync as fresh. Defaults to 60 seconds. |
| 142 | + * @param int $staleTreshold The threshold (in seconds) for considering the upstream sync as stale. Defaults to 3600 seconds (1 hour). |
| 143 | + * |
| 144 | + * @return int Returns an HTTP-like status code: |
| 145 | + * - 200 if the upstream sync was successful. |
| 146 | + * - 203 if the sync was not performed (data from cache is returned). |
| 147 | + * - 502 if the sync failed and the last successful sync is older than the stale threshold. |
| 148 | + */ |
| 149 | + public function syncUpstream(string $cacheKey, int $syncedTtl = 60, int $staleTreshold = 3600): int |
119 | 150 | {
|
120 |
| - $payload['help']['get'] = 'List all IF v1 compliant service providers (A `"provides": "docs"` route is present).'; |
121 |
| - $payload['help']['post'] = 'Post a json according to `service docs` to this interface as a request body to add a service coupler.'; |
122 |
| - $routes = array_filter($this->settings['routes'], function ($key) { |
123 |
| - // return strpos($key, 'be_if_') === 0 && |
124 |
| - return strpos($key, 'be_if_svc') === 0; |
125 |
| - }, ARRAY_FILTER_USE_KEY); |
126 |
| - foreach ($routes as $route) { |
127 |
| - $f['txt'] = trim($route['label']. " / " . $route['dscr']); |
128 |
| - $f['uri'] = $this->settings['glued']['protocol'] . $this->settings['glued']['hostname'] . $route['path']; |
129 |
| - $payload['links'][] = $f; |
| 151 | + $cacheTtl = 86400; // 24 hours in seconds |
| 152 | + $syncedResult = null; |
| 153 | + $now = time(); |
| 154 | + |
| 155 | + // Check if the last sync was more than 60 seconds ago, sync if yes |
| 156 | + $syncedAt = $this->memcache->get($cacheKey, 0); |
| 157 | + if (($now - $syncedAt) > $syncedTtl) { |
| 158 | + $syncedResult = $this->saveUpstream($this->getUpstream()); |
| 159 | + if ($syncedResult === false) { $this->logger->error('Upstream sync failed.', ['cacheKey' => $cacheKey]); } |
| 160 | + else { $this->memcache->set($cacheKey, $now, $cacheTtl); } |
130 | 161 | }
|
131 |
| - $payload['status'] = 'Ok'; |
132 |
| - return $response->withJson($payload); |
133 |
| - } |
134 |
| -
|
135 |
| - public function services_r1(Request $request, Response $response, array $args = []): Response |
136 |
| - { |
137 |
| - $base = $this->settings['glued']['protocol'] . $this->settings['glued']['hostname']; |
138 |
| - $svcs = []; |
139 |
| - foreach ($this->getServices() as $key => $value) { |
140 |
| - $svcs[$key]['name'] = $value; |
141 |
| - $svcs[$key]['links'] = "{$base}/{$this->settings['routes']['be_if_deployments_v1']['path']}/$value/deployments"; |
142 |
| - } |
143 |
| - $payload['status'] = 'Ok'; |
144 |
| - $payload['data'] = $svcs; |
145 |
| - return $response->withJson($payload); |
146 |
| - } |
147 |
| -
|
148 |
| -
|
149 |
| - public function queue_r1(Request $request, Response $response, array $args = []): Response |
150 |
| - { |
151 |
| - $rp = $this->utils->getQueryParams($request) ?? []; |
152 |
| - $override = [ [ 'next_in', '<', '0' ], [ 'row_num', '=', '1' ] ]; |
153 |
| - $qs = (new \Glued\Lib\IfSql())->q['json:runs:latest'];; |
154 |
| - $qs = (new \Glued\Lib\QueryBuilder())->select($qs); |
155 |
| - $qs = $this->utils->mysqlQueryFromRequest($qs, $rp, 'svc_data', override: $override); |
156 |
| - $r = $this->mysqli->execute_query($qs,array_values($rp)); |
157 |
| - $res['status'] = 'ok'; |
158 |
| - foreach ($r as $i) { |
159 |
| - $i['run'] = $this->settings['glued']['protocol'] . $this->settings['glued']['hostname'] . '/api/if/v1/svc/' . $i['svc_type'] . '/act/' . $i['act_uuid']; |
160 |
| - $i['run'] = $this->settings['glued']['protocol'] . $this->settings['glued']['hostname'] . '/api/if/v1/runs/' . $i['act_uuid']; |
161 |
| - $res['data'][] = $i; |
162 |
| - } |
163 |
| - return $response->withJson($res); |
164 |
| - } |
165 |
| -
|
166 |
| - public function deployments_r1(Request $request, Response $response, array $args = []): Response |
167 |
| - { |
168 |
| -
|
169 |
| - $data = []; |
170 |
| - $rp = $this->utils->getQueryParams($request) ?? []; |
171 |
| - $qs = (new \Glued\Lib\IfSql())->q['json:runs:latest']; |
172 |
| - if ($args['svc'] ?? false) { $data[] = $args['svc']; $qs.= " and subquery.service = ?"; } |
173 |
| - $data = array_values($rp) + $data; |
174 |
| - $res = $this->mysqli->execute_query($qs, $data); |
175 |
| - foreach ($res as $row) { |
176 |
| - $data = json_decode($row['json_result'], true); break; } |
177 |
| - $fin['status'] = 'ok'; |
178 |
| - $base = "{$this->settings['glued']['protocol']}{$this->settings['glued']['hostname']}/api/if"; |
179 |
| - foreach ($data as $k => &$i) { |
180 |
| - $data[$k]['links']['start'] = "{$base}/svc/{$i['service']}/v1/act/{$i['action']['uuid']}"; |
181 |
| - //$i['run'] = $this->settings['glued']['protocol'] . $this->settings['glued']['hostname'] . '/api/if/v1/runs/' . $i['act_uuid']; |
182 |
| - } |
183 |
| - $fin['data'] = $data; |
184 |
| -
|
185 |
| - //$res['data'][] = $i; |
186 |
| - return $response->withJson($fin); |
187 |
| - } |
188 |
| -
|
189 |
| - public function stats_r1(Request $request, Response $response, array $args = []): Response |
190 |
| - { |
191 |
| - $res = ['status' => 'ok', 'message' => 'This endpoint is under development.']; |
192 |
| - return $response->withJson($res); |
| 162 | + $status = ($syncedResult === false) |
| 163 | + ? (($now - $syncedAt) > $staleTreshold ? 502 : 203) // 502 if sync failed for >1 hour, else 203 |
| 164 | + : ($syncedResult === null ? 203 : 200); // 203 if cached, 200 if sync successful |
| 165 | + return $status; |
193 | 166 | }
|
194 | 167 |
|
195 | 168 |
|
196 | 169 | }
|
197 | 170 |
|
198 |
| -
|
199 |
| -// {"svc":{"type":"Caretag","name":"NEMCB Prod","host":"https:\/\/caretag-api.nemocnice.local","note": "Production environment ([email protected])","freq":3600,"auth":{"UserName":"[email protected]","Password":"Administrator1!"}},"act":[{"type":"Assets","freq":3600},{"type":"AssetDefinition","freq":36000}]} |
200 |
| -// toalety - wc |
201 |
| -// |
202 |
| -
|
203 |
| -*/ |
0 commit comments