Initial Commit
This commit is contained in:
99
dependencies/amphp/cache/lib/ArrayCache.php
vendored
Normal file
99
dependencies/amphp/cache/lib/ArrayCache.php
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\Loop;
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
use WP_Ultimo\Dependencies\Amp\Struct;
|
||||
use WP_Ultimo\Dependencies\Amp\Success;
|
||||
final class ArrayCache implements Cache
|
||||
{
|
||||
/** @var object */
|
||||
private $sharedState;
|
||||
/** @var string */
|
||||
private $ttlWatcherId;
|
||||
/** @var int|null */
|
||||
private $maxSize;
|
||||
/**
|
||||
* @param int $gcInterval The frequency in milliseconds at which expired cache entries should be garbage collected.
|
||||
* @param int $maxSize The maximum size of cache array (number of elements).
|
||||
*/
|
||||
public function __construct(int $gcInterval = 5000, int $maxSize = null)
|
||||
{
|
||||
// By using a shared state object we're able to use `__destruct()` for "normal" garbage collection of both this
|
||||
// instance and the loop's watcher. Otherwise this object could only be GC'd when the TTL watcher was cancelled
|
||||
// at the loop layer.
|
||||
$this->sharedState = $sharedState = new class
|
||||
{
|
||||
use Struct;
|
||||
/** @var string[] */
|
||||
public $cache = [];
|
||||
/** @var int[] */
|
||||
public $cacheTimeouts = [];
|
||||
/** @var bool */
|
||||
public $isSortNeeded = \false;
|
||||
public function collectGarbage() : void
|
||||
{
|
||||
$now = \time();
|
||||
if ($this->isSortNeeded) {
|
||||
\asort($this->cacheTimeouts);
|
||||
$this->isSortNeeded = \false;
|
||||
}
|
||||
foreach ($this->cacheTimeouts as $key => $expiry) {
|
||||
if ($now <= $expiry) {
|
||||
break;
|
||||
}
|
||||
unset($this->cache[$key], $this->cacheTimeouts[$key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
$this->ttlWatcherId = Loop::repeat($gcInterval, [$sharedState, "collectGarbage"]);
|
||||
$this->maxSize = $maxSize;
|
||||
Loop::unreference($this->ttlWatcherId);
|
||||
}
|
||||
public function __destruct()
|
||||
{
|
||||
$this->sharedState->cache = [];
|
||||
$this->sharedState->cacheTimeouts = [];
|
||||
Loop::cancel($this->ttlWatcherId);
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function get(string $key) : Promise
|
||||
{
|
||||
if (!isset($this->sharedState->cache[$key])) {
|
||||
return new Success(null);
|
||||
}
|
||||
if (isset($this->sharedState->cacheTimeouts[$key]) && \time() > $this->sharedState->cacheTimeouts[$key]) {
|
||||
unset($this->sharedState->cache[$key], $this->sharedState->cacheTimeouts[$key]);
|
||||
return new Success(null);
|
||||
}
|
||||
return new Success($this->sharedState->cache[$key]);
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function set(string $key, string $value, int $ttl = null) : Promise
|
||||
{
|
||||
if ($ttl === null) {
|
||||
unset($this->sharedState->cacheTimeouts[$key]);
|
||||
} elseif ($ttl >= 0) {
|
||||
$expiry = \time() + $ttl;
|
||||
$this->sharedState->cacheTimeouts[$key] = $expiry;
|
||||
$this->sharedState->isSortNeeded = \true;
|
||||
} else {
|
||||
throw new \Error("Invalid cache TTL ({$ttl}; integer >= 0 or null required");
|
||||
}
|
||||
unset($this->sharedState->cache[$key]);
|
||||
if (\count($this->sharedState->cache) === $this->maxSize) {
|
||||
\array_shift($this->sharedState->cache);
|
||||
}
|
||||
$this->sharedState->cache[$key] = $value;
|
||||
/** @var Promise<void> */
|
||||
return new Success();
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function delete(string $key) : Promise
|
||||
{
|
||||
$exists = isset($this->sharedState->cache[$key]);
|
||||
unset($this->sharedState->cache[$key], $this->sharedState->cacheTimeouts[$key]);
|
||||
return new Success($exists);
|
||||
}
|
||||
}
|
237
dependencies/amphp/cache/lib/AtomicCache.php
vendored
Normal file
237
dependencies/amphp/cache/lib/AtomicCache.php
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
use WP_Ultimo\Dependencies\Amp\Serialization\SerializationException;
|
||||
use WP_Ultimo\Dependencies\Amp\Sync\KeyedMutex;
|
||||
use WP_Ultimo\Dependencies\Amp\Sync\Lock;
|
||||
use function WP_Ultimo\Dependencies\Amp\call;
|
||||
/**
|
||||
* @template TValue
|
||||
*/
|
||||
final class AtomicCache
|
||||
{
|
||||
/** @var SerializedCache<TValue> */
|
||||
private $cache;
|
||||
/** @var KeyedMutex */
|
||||
private $mutex;
|
||||
/**
|
||||
* @param SerializedCache<TValue> $cache
|
||||
* @param KeyedMutex $mutex
|
||||
*/
|
||||
public function __construct(SerializedCache $cache, KeyedMutex $mutex)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->mutex = $mutex;
|
||||
}
|
||||
/**
|
||||
* Obtains the lock for the given key, then invokes the $create callback with the current cached value (which may
|
||||
* be null if the key did not exist in the cache). The value returned from the callback is stored in the cache and
|
||||
* the promise returned from this method is resolved with the value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param callable(string, mixed|null): mixed $create Receives $key and $value as parameters.
|
||||
* @param int|null $ttl Timeout in seconds. The default `null` $ttl value indicates no timeout.
|
||||
*
|
||||
* @return Promise<mixed>
|
||||
*
|
||||
* @psalm-param callable(string, TValue|null):(TValue|Promise<TValue>|\Generator<mixed, mixed, mixed, TValue>)
|
||||
* $create
|
||||
* @psalm-return Promise<TValue>
|
||||
*
|
||||
* @throws CacheException If the $create callback throws an exception while generating the value.
|
||||
* @throws SerializationException If serializing the value returned from the callback fails.
|
||||
*/
|
||||
public function compute(string $key, callable $create, ?int $ttl = null) : Promise
|
||||
{
|
||||
return call(function () use($key, $create, $ttl) : \Generator {
|
||||
$lock = (yield from $this->lock($key));
|
||||
\assert($lock instanceof Lock);
|
||||
try {
|
||||
$value = (yield $this->cache->get($key));
|
||||
return yield from $this->create($create, $key, $value, $ttl);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Attempts to get the value for the given key. If the key is not found, the key is locked, the $create callback
|
||||
* is invoked with the key as the first parameter. The value returned from the callback is stored in the cache and
|
||||
* the promise returned from this method is resolved with the value.
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param callable(string): mixed $create Receives $key as parameter.
|
||||
* @param int|null $ttl Timeout in seconds. The default `null` $ttl value indicates no timeout.
|
||||
*
|
||||
* @return Promise<mixed>
|
||||
*
|
||||
* @psalm-param callable(string, TValue|null):(TValue|Promise<TValue>|\Generator<mixed, mixed, mixed, TValue>)
|
||||
* $create
|
||||
* @psalm-return Promise<TValue>
|
||||
*
|
||||
* @throws CacheException If the $create callback throws an exception while generating the value.
|
||||
* @throws SerializationException If serializing the value returned from the callback fails.
|
||||
*/
|
||||
public function computeIfAbsent(string $key, callable $create, ?int $ttl = null) : Promise
|
||||
{
|
||||
return call(function () use($key, $create, $ttl) : \Generator {
|
||||
$value = (yield $this->cache->get($key));
|
||||
if ($value !== null) {
|
||||
return $value;
|
||||
}
|
||||
$lock = (yield from $this->lock($key));
|
||||
\assert($lock instanceof Lock);
|
||||
try {
|
||||
// Attempt to get the value again, since it may have been set while obtaining the lock.
|
||||
$value = (yield $this->cache->get($key));
|
||||
if ($value !== null) {
|
||||
return $value;
|
||||
}
|
||||
return yield from $this->create($create, $key, null, $ttl);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Attempts to get the value for the given key. If the key exists, the key is locked, the $create callback
|
||||
* is invoked with the key as the first parameter and the current key value as the second parameter. The value
|
||||
* returned from the callback is stored in the cache and the promise returned from this method is resolved with
|
||||
* the value.
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param callable(string, mixed): mixed $create Receives $key and $value as parameters.
|
||||
* @param int|null $ttl Timeout in seconds. The default `null` $ttl value indicates no timeout.
|
||||
*
|
||||
* @return Promise<mixed>
|
||||
*
|
||||
* @psalm-param callable(string, TValue|null): (TValue|Promise<TValue>|\Generator<mixed, mixed, mixed, TValue>) $create
|
||||
* @psalm-return Promise<TValue>
|
||||
*
|
||||
* @throws CacheException If the $create callback throws an exception while generating the value.
|
||||
* @throws SerializationException If serializing the value returned from the callback fails.
|
||||
*/
|
||||
public function computeIfPresent(string $key, callable $create, ?int $ttl = null) : Promise
|
||||
{
|
||||
return call(function () use($key, $create, $ttl) : \Generator {
|
||||
$value = (yield $this->cache->get($key));
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
$lock = (yield from $this->lock($key));
|
||||
\assert($lock instanceof Lock);
|
||||
try {
|
||||
// Attempt to get the value again, since it may have been set while obtaining the lock.
|
||||
$value = (yield $this->cache->get($key));
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
return yield from $this->create($create, $key, $value, $ttl);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* The lock is obtained for the key before setting the value.
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param mixed $value Value to cache.
|
||||
* @param int|null $ttl Timeout in seconds. The default `null` $ttl value indicates no timeout.
|
||||
*
|
||||
* @return Promise<void> Resolves either successfully or fails with a CacheException on failure.
|
||||
*
|
||||
* @psalm-param TValue $value
|
||||
* @psalm-return Promise<void>
|
||||
*
|
||||
* @throws CacheException
|
||||
* @throws SerializationException
|
||||
*
|
||||
* @see SerializedCache::set()
|
||||
*/
|
||||
public function set(string $key, $value, ?int $ttl = null) : Promise
|
||||
{
|
||||
return call(function () use($key, $value, $ttl) : \Generator {
|
||||
$lock = (yield from $this->lock($key));
|
||||
\assert($lock instanceof Lock);
|
||||
try {
|
||||
(yield $this->cache->set($key, $value, $ttl));
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Returns the cached value for the key or the given default value if the key does not exist.
|
||||
*
|
||||
* @template TDefault
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param mixed $default Default value returned if the key does not exist. Null by default.
|
||||
*
|
||||
* @return Promise<mixed|null> Resolved with null iff $default is null.
|
||||
*
|
||||
* @psalm-param TDefault $default
|
||||
* @psalm-return Promise<TValue|TDefault>
|
||||
*
|
||||
* @throws CacheException
|
||||
* @throws SerializationException
|
||||
*
|
||||
* @see SerializedCache::get()
|
||||
*/
|
||||
public function get(string $key, $default = null) : Promise
|
||||
{
|
||||
return call(function () use($key, $default) : \Generator {
|
||||
$value = (yield $this->cache->get($key));
|
||||
if ($value === null) {
|
||||
return $default;
|
||||
}
|
||||
return $value;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* The lock is obtained for the key before deleting the key.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return Promise<bool|null>
|
||||
*
|
||||
* @see SerializedCache::delete()
|
||||
*/
|
||||
public function delete(string $key) : Promise
|
||||
{
|
||||
return call(function () use($key) : \Generator {
|
||||
$lock = (yield from $this->lock($key));
|
||||
\assert($lock instanceof Lock);
|
||||
try {
|
||||
return (yield $this->cache->delete($key));
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
private function lock(string $key) : \Generator
|
||||
{
|
||||
try {
|
||||
return (yield $this->mutex->acquire($key));
|
||||
} catch (\Throwable $exception) {
|
||||
throw new CacheException(\sprintf('Exception thrown when obtaining the lock for key "%s"', $key), 0, $exception);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @psalm-param TValue|null $value
|
||||
* @psalm-return \Generator<mixed, mixed, mixed, TValue>
|
||||
*/
|
||||
private function create(callable $create, string $key, $value, ?int $ttl) : \Generator
|
||||
{
|
||||
try {
|
||||
$value = (yield call($create, $key, $value));
|
||||
} catch (\Throwable $exception) {
|
||||
throw new CacheException(\sprintf('Exception thrown while creating the value for key "%s"', $key), 0, $exception);
|
||||
}
|
||||
(yield $this->cache->set($key, $value, $ttl));
|
||||
return $value;
|
||||
}
|
||||
}
|
48
dependencies/amphp/cache/lib/Cache.php
vendored
Normal file
48
dependencies/amphp/cache/lib/Cache.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
interface Cache
|
||||
{
|
||||
/**
|
||||
* Gets a value associated with the given key.
|
||||
*
|
||||
* If the specified key doesn't exist implementations MUST succeed the resulting promise with `null`.
|
||||
*
|
||||
* @param $key string Cache key.
|
||||
*
|
||||
* @return Promise<string|null> Resolves to the cached value nor `null` if it doesn't exist or fails with a
|
||||
* CacheException on failure.
|
||||
*/
|
||||
public function get(string $key) : Promise;
|
||||
/**
|
||||
* Sets a value associated with the given key. Overrides existing values (if they exist).
|
||||
*
|
||||
* The eventual resolution value of the resulting promise is unimportant. The success or failure of the promise
|
||||
* indicates the operation's success.
|
||||
*
|
||||
* @param $key string Cache key.
|
||||
* @param $value string Value to cache.
|
||||
* @param $ttl int Timeout in seconds. The default `null` $ttl value indicates no timeout. Values less than 0 MUST
|
||||
* throw an \Error.
|
||||
*
|
||||
* @return Promise<void> Resolves either successfully or fails with a CacheException on failure.
|
||||
*/
|
||||
public function set(string $key, string $value, int $ttl = null) : Promise;
|
||||
/**
|
||||
* Deletes a value associated with the given key if it exists.
|
||||
*
|
||||
* Implementations SHOULD return boolean `true` or `false` to indicate whether the specified key existed at the time
|
||||
* the delete operation was requested. If such information is not available, the implementation MUST resolve the
|
||||
* promise with `null`.
|
||||
*
|
||||
* Implementations MUST transparently succeed operations for non-existent keys.
|
||||
*
|
||||
* @param $key string Cache key.
|
||||
*
|
||||
* @return Promise<bool|null> Resolves to `true` / `false` to indicate whether the key existed or fails with a
|
||||
* CacheException on failure. May also resolve with `null` if that information is not available.
|
||||
*/
|
||||
public function delete(string $key) : Promise;
|
||||
}
|
10
dependencies/amphp/cache/lib/CacheException.php
vendored
Normal file
10
dependencies/amphp/cache/lib/CacheException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
/**
|
||||
* MUST be thrown in case a cache operation fails.
|
||||
*/
|
||||
class CacheException extends \Exception
|
||||
{
|
||||
}
|
147
dependencies/amphp/cache/lib/FileCache.php
vendored
Normal file
147
dependencies/amphp/cache/lib/FileCache.php
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
/** @noinspection PhpUndefinedFunctionInspection */
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\File;
|
||||
use WP_Ultimo\Dependencies\Amp\File\Driver;
|
||||
use WP_Ultimo\Dependencies\Amp\Loop;
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
use WP_Ultimo\Dependencies\Amp\Sync\KeyedMutex;
|
||||
use WP_Ultimo\Dependencies\Amp\Sync\Lock;
|
||||
use function WP_Ultimo\Dependencies\Amp\call;
|
||||
final class FileCache implements Cache
|
||||
{
|
||||
private static function getFilename(string $key) : string
|
||||
{
|
||||
return \hash('sha256', $key) . '.cache';
|
||||
}
|
||||
/** @var string */
|
||||
private $directory;
|
||||
/** @var KeyedMutex */
|
||||
private $mutex;
|
||||
/** @var string */
|
||||
private $gcWatcher;
|
||||
/** @var bool */
|
||||
private $ampFileVersion2;
|
||||
public function __construct(string $directory, KeyedMutex $mutex)
|
||||
{
|
||||
$this->directory = $directory = \rtrim($directory, "/\\");
|
||||
$this->mutex = $mutex;
|
||||
if (!\interface_exists(Driver::class)) {
|
||||
throw new \Error(__CLASS__ . ' requires amphp/file to be installed');
|
||||
}
|
||||
$this->ampFileVersion2 = $ampFileVersion2 = \function_exists('WP_Ultimo\\Dependencies\\Amp\\File\\listFiles');
|
||||
$gcWatcher = static function () use($directory, $mutex, $ampFileVersion2) : \Generator {
|
||||
try {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
$files = (yield $ampFileVersion2 ? File\listFiles($directory) : File\scandir($directory));
|
||||
foreach ($files as $file) {
|
||||
if (\strlen($file) !== 70 || \substr($file, -\strlen('.cache')) !== '.cache') {
|
||||
continue;
|
||||
}
|
||||
/** @var Lock $lock */
|
||||
$lock = (yield $mutex->acquire($file));
|
||||
try {
|
||||
/** @var File\File $handle */
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
$handle = (yield $ampFileVersion2 ? File\openFile($directory . '/' . $file, 'r') : File\open($directory . '/' . $file, 'r'));
|
||||
$ttl = (yield $handle->read(4));
|
||||
if ($ttl === null || \strlen($ttl) !== 4) {
|
||||
(yield $handle->close());
|
||||
continue;
|
||||
}
|
||||
$ttl = \unpack('Nttl', $ttl)['ttl'];
|
||||
if ($ttl < \time()) {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
(yield $ampFileVersion2 ? File\deleteFile($directory . '/' . $file) : File\unlink($directory . '/' . $file));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// ignore
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// ignore
|
||||
}
|
||||
};
|
||||
// trigger once, so short running scripts also GC and don't grow forever
|
||||
Loop::defer($gcWatcher);
|
||||
$this->gcWatcher = Loop::repeat(300000, $gcWatcher);
|
||||
}
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->gcWatcher !== null) {
|
||||
Loop::cancel($this->gcWatcher);
|
||||
}
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function get(string $key) : Promise
|
||||
{
|
||||
return call(function () use($key) {
|
||||
$filename = $this->getFilename($key);
|
||||
/** @var Lock $lock */
|
||||
$lock = (yield $this->mutex->acquire($filename));
|
||||
try {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
$cacheContent = (yield $this->ampFileVersion2 ? File\read($this->directory . '/' . $filename) : File\get($this->directory . '/' . $filename));
|
||||
if (\strlen($cacheContent) < 4) {
|
||||
return null;
|
||||
}
|
||||
$ttl = \unpack('Nttl', \substr($cacheContent, 0, 4))['ttl'];
|
||||
if ($ttl < \time()) {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
(yield $this->ampFileVersion2 ? File\deleteFile($this->directory . '/' . $filename) : File\unlink($this->directory . '/' . $filename));
|
||||
return null;
|
||||
}
|
||||
$value = \substr($cacheContent, 4);
|
||||
\assert(\is_string($value));
|
||||
return $value;
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function set(string $key, string $value, int $ttl = null) : Promise
|
||||
{
|
||||
if ($ttl < 0) {
|
||||
throw new \Error("Invalid cache TTL ({$ttl}); integer >= 0 or null required");
|
||||
}
|
||||
return call(function () use($key, $value, $ttl) {
|
||||
$filename = $this->getFilename($key);
|
||||
/** @var Lock $lock */
|
||||
$lock = (yield $this->mutex->acquire($filename));
|
||||
if ($ttl === null) {
|
||||
$ttl = \PHP_INT_MAX;
|
||||
} else {
|
||||
$ttl = \time() + $ttl;
|
||||
}
|
||||
$encodedTtl = \pack('N', $ttl);
|
||||
try {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
(yield $this->ampFileVersion2 ? File\write($this->directory . '/' . $filename, $encodedTtl . $value) : File\put($this->directory . '/' . $filename, $encodedTtl . $value));
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function delete(string $key) : Promise
|
||||
{
|
||||
return call(function () use($key) {
|
||||
$filename = $this->getFilename($key);
|
||||
/** @var Lock $lock */
|
||||
$lock = (yield $this->mutex->acquire($filename));
|
||||
try {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
return (yield $this->ampFileVersion2 ? File\deleteFile($this->directory . '/' . $filename) : File\unlink($this->directory . '/' . $filename));
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
28
dependencies/amphp/cache/lib/NullCache.php
vendored
Normal file
28
dependencies/amphp/cache/lib/NullCache.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
use WP_Ultimo\Dependencies\Amp\Success;
|
||||
/**
|
||||
* Cache implementation that just ignores all operations and always resolves to `null`.
|
||||
*/
|
||||
class NullCache implements Cache
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function get(string $key) : Promise
|
||||
{
|
||||
return new Success();
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function set(string $key, string $value, int $ttl = null) : Promise
|
||||
{
|
||||
/** @var Promise<void> */
|
||||
return new Success();
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function delete(string $key) : Promise
|
||||
{
|
||||
return new Success(\false);
|
||||
}
|
||||
}
|
39
dependencies/amphp/cache/lib/PrefixCache.php
vendored
Normal file
39
dependencies/amphp/cache/lib/PrefixCache.php
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
final class PrefixCache implements Cache
|
||||
{
|
||||
private $cache;
|
||||
private $keyPrefix;
|
||||
public function __construct(Cache $cache, string $keyPrefix)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->keyPrefix = $keyPrefix;
|
||||
}
|
||||
/**
|
||||
* Gets the specified key prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyPrefix() : string
|
||||
{
|
||||
return $this->keyPrefix;
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function get(string $key) : Promise
|
||||
{
|
||||
return $this->cache->get($this->keyPrefix . $key);
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function set(string $key, string $value, int $ttl = null) : Promise
|
||||
{
|
||||
return $this->cache->set($this->keyPrefix . $key, $value, $ttl);
|
||||
}
|
||||
/** @inheritdoc */
|
||||
public function delete(string $key) : Promise
|
||||
{
|
||||
return $this->cache->delete($this->keyPrefix . $key);
|
||||
}
|
||||
}
|
86
dependencies/amphp/cache/lib/SerializedCache.php
vendored
Normal file
86
dependencies/amphp/cache/lib/SerializedCache.php
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Cache;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp\Failure;
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
use WP_Ultimo\Dependencies\Amp\Serialization\SerializationException;
|
||||
use WP_Ultimo\Dependencies\Amp\Serialization\Serializer;
|
||||
use function WP_Ultimo\Dependencies\Amp\call;
|
||||
/**
|
||||
* @template TValue
|
||||
*/
|
||||
final class SerializedCache
|
||||
{
|
||||
/** @var Cache */
|
||||
private $cache;
|
||||
/** @var Serializer */
|
||||
private $serializer;
|
||||
public function __construct(Cache $cache, Serializer $serializer)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
/**
|
||||
* Fetch a value from the cache and unserialize it.
|
||||
*
|
||||
* @param $key string Cache key.
|
||||
*
|
||||
* @return Promise<mixed|null> Resolves to the cached value or `null` if it doesn't exist. Fails with a
|
||||
* CacheException or SerializationException on failure.
|
||||
*
|
||||
* @psalm-return Promise<TValue|null>
|
||||
*
|
||||
* @see Cache::get()
|
||||
*/
|
||||
public function get(string $key) : Promise
|
||||
{
|
||||
return call(function () use($key) {
|
||||
$data = (yield $this->cache->get($key));
|
||||
if ($data === null) {
|
||||
return null;
|
||||
}
|
||||
return $this->serializer->unserialize($data);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Serializes a value and stores its serialization to the cache.
|
||||
*
|
||||
* @param $key string Cache key.
|
||||
* @param $value mixed Value to cache.
|
||||
* @param $ttl int Timeout in seconds. The default `null` $ttl value indicates no timeout. Values less than 0 MUST
|
||||
* throw an \Error.
|
||||
*
|
||||
* @psalm-param TValue $value
|
||||
*
|
||||
* @return Promise<void> Resolves either successfully or fails with a CacheException or SerializationException.
|
||||
*
|
||||
* @see Cache::set()
|
||||
*/
|
||||
public function set(string $key, $value, int $ttl = null) : Promise
|
||||
{
|
||||
if ($value === null) {
|
||||
return new Failure(new CacheException('Cannot store NULL in serialized cache'));
|
||||
}
|
||||
try {
|
||||
$value = $this->serializer->serialize($value);
|
||||
} catch (SerializationException $exception) {
|
||||
return new Failure($exception);
|
||||
}
|
||||
return $this->cache->set($key, $value, $ttl);
|
||||
}
|
||||
/**
|
||||
* Deletes a value associated with the given key if it exists.
|
||||
*
|
||||
* @param $key string Cache key.
|
||||
*
|
||||
* @return Promise<bool|null> Resolves to `true` / `false` to indicate whether the key existed or fails with a
|
||||
* CacheException on failure. May also resolve with `null` if that information is not available.
|
||||
*
|
||||
* @see Cache::delete()
|
||||
*/
|
||||
public function delete(string $key) : Promise
|
||||
{
|
||||
return $this->cache->delete($key);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user