From ba21c74e72417fd458eab8c1f40e04e1a3d329c1 Mon Sep 17 00:00:00 2001 From: abdulmohsen Date: Mon, 22 Apr 2024 18:10:01 +0300 Subject: [PATCH] Implemented basic cache for GetLibrariesList. --- .../Jellyfin/Action/GetLibrariesList.php | 77 ++++++++----- src/Backends/Plex/Action/GetLibrariesList.php | 108 +++++++++++------- tests/Backends/Plex/GetLibrariesListTest.php | 3 +- 3 files changed, 121 insertions(+), 67 deletions(-) diff --git a/src/Backends/Jellyfin/Action/GetLibrariesList.php b/src/Backends/Jellyfin/Action/GetLibrariesList.php index ec1cfd5e..32f3d956 100644 --- a/src/Backends/Jellyfin/Action/GetLibrariesList.php +++ b/src/Backends/Jellyfin/Action/GetLibrariesList.php @@ -10,7 +10,9 @@ use App\Backends\Common\Error; use App\Backends\Common\Levels; use App\Backends\Common\Response; use App\Backends\Jellyfin\JellyfinClient; +use App\Libs\Exceptions\RuntimeException; use App\Libs\Options; +use DateInterval; use JsonException; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; @@ -57,40 +59,26 @@ class GetLibrariesList * @param array $opts (optional) Options. * * @return Response The response object containing the fetched libraries. - * @throws JsonException If the response body is not a valid JSON. - * @throws ExceptionInterface If the request failed. + * + * @throws ExceptionInterface When an error happens during the request. + * @throws JsonException When the JSON response cannot be parsed. */ private function action(Context $context, array $opts = []): Response { - $url = $context->backendUrl->withPath(r('/Users/{user_id}/items/', ['user_id' => $context->backendUser])); + $cls = fn() => $this->real_request($context); - $this->logger->debug('Requesting [{backend}] libraries list.', [ - 'backend' => $context->backendName, - 'url' => (string)$url - ]); - - $response = $this->http->request('GET', (string)$url, $context->backendHeaders); - - if (200 !== $response->getStatusCode()) { - return new Response( - status: false, - error: new Error( - message: 'Request for [{backend}] libraries returned with unexpected [{status_code}] status code.', - context: [ - 'backend' => $context->backendName, - 'status_code' => $response->getStatusCode(), - ], - level: Levels::ERROR - ), + try { + $json = true === (bool)ag($opts, Options::NO_CACHE) ? $cls() : $this->tryCache( + $context, + 'library_list', + $cls, + new DateInterval('PT1M'), + $this->logger ); + } catch (RuntimeException $e) { + return new Response(status: false, error: new Error(message: $e->getMessage(), level: Levels::ERROR)); } - $json = json_decode( - json: $response->getContent(), - associative: true, - flags: JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE - ); - if ($context->trace) { $this->logger->debug('Parsing [{backend}] libraries payload.', [ 'backend' => $context->backendName, @@ -144,4 +132,39 @@ class GetLibrariesList return new Response(status: true, response: $list); } + + /** + * Fetches the libraries from the backend. + * + * @return array The fetched libraries. + * + * @throws ExceptionInterface When an error happens during the request. + * @throws JsonException When the JSON response cannot be parsed. + */ + private function real_request(Context $context): array + { + $url = $context->backendUrl->withPath(r('/Users/{user_id}/items/', ['user_id' => $context->backendUser])); + + $this->logger->debug('Requesting [{backend}] libraries list.', [ + 'backend' => $context->backendName, + 'url' => (string)$url + ]); + + $response = $this->http->request('GET', (string)$url, $context->backendHeaders); + + if (200 !== $response->getStatusCode()) { + throw new RuntimeException( + r('Request for [{backend}] libraries returned with unexpected [{status_code}] status code.', [ + 'backend' => $context->backendName, + 'status_code' => $response->getStatusCode(), + ]) + ); + } + + return json_decode( + json: $response->getContent(), + associative: true, + flags: JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE + ); + } } diff --git a/src/Backends/Plex/Action/GetLibrariesList.php b/src/Backends/Plex/Action/GetLibrariesList.php index 0f97a651..d0661450 100644 --- a/src/Backends/Plex/Action/GetLibrariesList.php +++ b/src/Backends/Plex/Action/GetLibrariesList.php @@ -10,7 +10,9 @@ use App\Backends\Common\Error; use App\Backends\Common\Levels; use App\Backends\Common\Response; use App\Backends\Plex\PlexClient; +use App\Libs\Exceptions\RuntimeException; use App\Libs\Options; +use DateInterval; use JsonException; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; @@ -40,52 +42,32 @@ final class GetLibrariesList } /** - * @throws ExceptionInterface - * @throws JsonException + * Fetches libraries from the backend. + * + * @param Context $context Backend context. + * @param array $opts (optional) Options. + * + * @return Response The response object containing the fetched libraries. + * + * @throws ExceptionInterface when an error happens during the request. + * @throws JsonException when the response is not a valid JSON. */ private function action(Context $context, array $opts = []): Response { - $url = $context->backendUrl->withPath('/library/sections'); + try { + $cls = fn() => $this->real_request($context); - $this->logger->debug('Requesting [{backend}] libraries list.', [ - 'backend' => $context->backendName, - 'url' => (string)$url - ]); - - $response = $this->http->request('GET', (string)$url, $context->backendHeaders); - - $payload = $response->getContent(false); - - if ($context->trace) { - $this->logger->debug('Processing [{backend}] response.', [ - 'backend' => $context->backendName, - 'url' => (string)$url, - 'response' => $payload, - ]); - } - - if (200 !== $response->getStatusCode()) { - return new Response( - status: false, - error: new Error( - message: 'Request for [{backend}] libraries returned with unexpected [{status_code}] status code.', - context: [ - 'backend' => $context->backendName, - 'status_code' => $response->getStatusCode(), - ], - level: Levels::ERROR - ), + $json = true === (bool)ag($opts, Options::NO_CACHE) ? $cls() : $this->tryCache( + $context, + 'libraries_list', + $cls, + new DateInterval('PT1M'), + $this->logger ); + } catch (RuntimeException $e) { + return new Response(status: false, error: new Error(message: $e->getMessage(), level: Levels::ERROR)); } - $json = json_decode( - json: $payload, - associative: true, - flags: JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE - ); - - unset($payload); - if ($context->trace) { $this->logger->debug('Parsing [{backend}] libraries payload.', [ 'backend' => $context->backendName, @@ -142,4 +124,52 @@ final class GetLibrariesList return new Response(status: true, response: $list); } + + /** + * Fetches the libraries from the backend. + * + * @return array The fetched libraries. + * + * @throws ExceptionInterface when an error happens during the request. + * @throws JsonException when the response is not a valid JSON. + */ + private function real_request(Context $context): array + { + $url = $context->backendUrl->withPath('/library/sections'); + + $this->logger->debug('Requesting [{backend}] libraries list.', [ + 'backend' => $context->backendName, + 'url' => (string)$url + ]); + + $response = $this->http->request('GET', (string)$url, $context->backendHeaders); + + $payload = $response->getContent(false); + + if ($context->trace) { + $this->logger->debug('Processing [{backend}] response.', [ + 'backend' => $context->backendName, + 'url' => (string)$url, + 'response' => $payload, + ]); + } + + if (200 !== $response->getStatusCode()) { + throw new RuntimeException( + r( + 'Request for [{backend}] libraries returned with unexpected [{status_code}] status code.', + [ + 'backend' => $context->backendName, + 'status_code' => $response->getStatusCode(), + ] + ) + ); + } + + return json_decode( + json: $payload, + associative: true, + flags: JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE + ); + } } diff --git a/tests/Backends/Plex/GetLibrariesListTest.php b/tests/Backends/Plex/GetLibrariesListTest.php index 968cc195..a6dd4702 100644 --- a/tests/Backends/Plex/GetLibrariesListTest.php +++ b/tests/Backends/Plex/GetLibrariesListTest.php @@ -9,6 +9,7 @@ use App\Backends\Common\Context; use App\Backends\Plex\Action\GetLibrariesList; use App\Backends\Plex\PlexClient; use App\Libs\Extends\LogMessageProcessor; +use App\Libs\Options; use App\Libs\Stream; use App\Libs\TestCase; use App\Libs\Uri; @@ -105,7 +106,7 @@ class GetLibrariesListTest extends TestCase $client = new MockHttpClient($resp); $list = new GetLibrariesList($client, $this->logger); - $response = $list($this->context); + $response = $list($this->context, [Options::NO_CACHE => true]); $this->assertFalse($response->status); $this->assertNotNull($response->error);