diff options
Diffstat (limited to 'apps/dav/lib/Paginate/PaginateCache.php')
-rw-r--r-- | apps/dav/lib/Paginate/PaginateCache.php | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/apps/dav/lib/Paginate/PaginateCache.php b/apps/dav/lib/Paginate/PaginateCache.php new file mode 100644 index 00000000000..58219b03621 --- /dev/null +++ b/apps/dav/lib/Paginate/PaginateCache.php @@ -0,0 +1,75 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\DAV\Paginate; + +use Generator; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\IDBConnection; +use OCP\Security\ISecureRandom; + +class PaginateCache { + public const TTL = 60 * 60; + private const CACHE_COUNT_SUFFIX = 'count'; + + private ICache $cache; + + public function __construct( + private IDBConnection $database, + private ISecureRandom $random, + ICacheFactory $cacheFactory, + ) { + $this->cache = $cacheFactory->createDistributed('pagination_'); + } + + /** + * @param string $uri + * @param \Iterator $items + * @return array{'token': string, 'count': int} + */ + public function store(string $uri, \Iterator $items): array { + $token = $this->random->generate(32); + $cacheKey = $this->buildCacheKey($uri, $token); + + $count = 0; + foreach ($items as $item) { + // Add small margin to avoid fetching valid count and then expired entries + $this->cache->set($cacheKey . $count, $item, self::TTL + 60); + ++$count; + } + $this->cache->set($cacheKey . self::CACHE_COUNT_SUFFIX, $count, self::TTL); + + return ['token' => $token, 'count' => $count]; + } + + /** + * @return Generator<mixed> + */ + public function get(string $uri, string $token, int $offset, int $count): Generator { + $cacheKey = $this->buildCacheKey($uri, $token); + $nbItems = $this->cache->get($cacheKey . self::CACHE_COUNT_SUFFIX); + if (!$nbItems || $offset > $nbItems) { + return []; + } + + $lastItem = min($nbItems, $offset + $count); + for ($i = $offset; $i < $lastItem; ++$i) { + yield $this->cache->get($cacheKey . $i); + } + } + + public function exists(string $uri, string $token): bool { + return $this->cache->get($this->buildCacheKey($uri, $token) . self::CACHE_COUNT_SUFFIX) > 0; + } + + private function buildCacheKey(string $uri, string $token): string { + return $token . '_' . crc32($uri) . '_'; + } +} |