2025-09-09 12:07:53 +02:00
|
|
|
<?php
|
2025-09-22 23:17:08 +02:00
|
|
|
/*
|
|
|
|
|
davina — Calendar data CalDAV conditioner
|
|
|
|
|
Copyright (C) 2025 Fenris <fenris@folksprak.org>
|
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
|
|
|
|
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
|
version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
|
|
|
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with this program. If not, see
|
|
|
|
|
<https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2025-09-09 12:07:53 +02:00
|
|
|
|
2025-09-16 12:05:35 +02:00
|
|
|
namespace davina\helpers\cache;
|
2025-09-09 12:07:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
interface interface_cache/*<type_value>*/
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function has(
|
|
|
|
|
string $key
|
|
|
|
|
) : bool
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function get(
|
|
|
|
|
string $key
|
|
|
|
|
)/* : type_value*/
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function set(
|
|
|
|
|
string $key,
|
|
|
|
|
/*type_value */$value
|
|
|
|
|
) : void
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
class class_cache_encoded
|
|
|
|
|
implements interface_cache/*<type_value_inner, type_value_outer>*/
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
private interface_cache $core;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
private \Closure $encode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
private \Closure $decode;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function __construct(
|
|
|
|
|
interface_cache $core,
|
|
|
|
|
\Closure $encode,
|
|
|
|
|
\Closure $decode
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
$this->core = $core;
|
|
|
|
|
$this->encode = $encode;
|
|
|
|
|
$this->decode = $decode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function has(
|
|
|
|
|
string $key
|
|
|
|
|
) : bool
|
|
|
|
|
{
|
|
|
|
|
return $this->core->has($key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function get(
|
|
|
|
|
string $key
|
|
|
|
|
)/* : type_value*/
|
|
|
|
|
{
|
|
|
|
|
return ($this->decode)($this->core->get($key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function set(
|
|
|
|
|
string $key,
|
|
|
|
|
/*type_value */$value
|
|
|
|
|
) : void
|
|
|
|
|
{
|
|
|
|
|
$this->core->set($key, ($this->encode)($value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
class class_cache_memory
|
|
|
|
|
implements interface_cache/*<any>*/
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @property array $data {map<string,any>}
|
|
|
|
|
*/
|
|
|
|
|
private array $data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function __construct(
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
$this->data = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function has(
|
|
|
|
|
string $key
|
|
|
|
|
) : bool
|
|
|
|
|
{
|
|
|
|
|
return \array_key_exists($key, $this->data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function get(
|
|
|
|
|
string $key
|
|
|
|
|
)/* : any*/
|
|
|
|
|
{
|
|
|
|
|
if (! \array_key_exists($key, $this->data))
|
|
|
|
|
{
|
|
|
|
|
throw (new \Exception('missing'));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return $this->data[$key];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function set(
|
|
|
|
|
string $key,
|
|
|
|
|
/*any */$value
|
|
|
|
|
) : void
|
|
|
|
|
{
|
|
|
|
|
$this->data[$key] = $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
class class_cache_file
|
|
|
|
|
implements interface_cache/*<string>*/
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
private $directory;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function __construct(
|
|
|
|
|
string $directory
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
$this->directory = $directory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function compose_path(
|
|
|
|
|
string $key
|
|
|
|
|
) : string
|
|
|
|
|
{
|
|
|
|
|
return \sprintf(
|
|
|
|
|
'%s/%s', $this->directory,
|
|
|
|
|
\hash('sha256', $key)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function has(
|
|
|
|
|
string $key
|
|
|
|
|
) : bool
|
|
|
|
|
{
|
|
|
|
|
$path = $this->compose_path($key);
|
|
|
|
|
return \file_exists($path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function get(
|
|
|
|
|
string $key
|
|
|
|
|
)/* : string*/
|
|
|
|
|
{
|
|
|
|
|
$path = $this->compose_path($key);
|
|
|
|
|
if (! \file_exists($path))
|
|
|
|
|
{
|
|
|
|
|
throw (new \Exception('missing'));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return \file_get_contents($path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function set(
|
|
|
|
|
string $key,
|
|
|
|
|
/*string */$value
|
|
|
|
|
) : void
|
|
|
|
|
{
|
|
|
|
|
$path = $this->compose_path($key);
|
|
|
|
|
\file_put_contents($path, $value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
class class_cache_apcu
|
|
|
|
|
implements interface_cache/*<any>*/
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
private string $prefix;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
public function __construct(
|
|
|
|
|
?array $options = null
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
$options = \array_merge(
|
|
|
|
|
[
|
2025-09-16 12:05:35 +02:00
|
|
|
'prefix' => 'davina_',
|
2025-09-09 12:07:53 +02:00
|
|
|
],
|
|
|
|
|
($options ?? [])
|
|
|
|
|
);
|
|
|
|
|
$this->prefix = $options['prefix'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
private function compose_id(
|
|
|
|
|
string $key
|
|
|
|
|
) : string
|
|
|
|
|
{
|
|
|
|
|
return \sprintf('%s%s', $this->prefix, $key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function has(
|
|
|
|
|
string $key
|
|
|
|
|
) : bool
|
|
|
|
|
{
|
|
|
|
|
$id = $this->compose_id($key);
|
|
|
|
|
return \apcu_exists($id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function get(
|
|
|
|
|
string $key
|
|
|
|
|
)/* : any*/
|
|
|
|
|
{
|
|
|
|
|
$id = $this->compose_id($key);
|
|
|
|
|
return \apcu_fetch($id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [implementation]
|
|
|
|
|
*/
|
|
|
|
|
public function set(
|
|
|
|
|
string $key,
|
|
|
|
|
/*any */$value
|
|
|
|
|
) : void
|
|
|
|
|
{
|
|
|
|
|
$id = $this->compose_id($key);
|
|
|
|
|
\apcu_store($id, $value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*/
|
|
|
|
|
function get/*<type_value>*/(
|
|
|
|
|
interface_cache $cache/*<type_value>*/,
|
|
|
|
|
string $key,
|
|
|
|
|
\Closure $retrieve,
|
|
|
|
|
?array $options = null
|
|
|
|
|
)/* : type_value*/
|
|
|
|
|
{
|
|
|
|
|
$options = \array_merge(
|
|
|
|
|
[
|
|
|
|
|
'ttl' => null,
|
|
|
|
|
'now' => \time(),
|
|
|
|
|
],
|
|
|
|
|
($options ?? [])
|
|
|
|
|
);
|
|
|
|
|
if (! $cache->has($key))
|
|
|
|
|
{
|
|
|
|
|
$entry = null;
|
|
|
|
|
$shall_retrieve = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$entry = $cache->get($key);
|
|
|
|
|
$shall_retrieve = (($entry['expiry'] !== null) && ($options['now'] >= $entry['expiry']));
|
|
|
|
|
}
|
|
|
|
|
if ($shall_retrieve)
|
|
|
|
|
{
|
|
|
|
|
$value = ($retrieve)();
|
|
|
|
|
$entry = [
|
|
|
|
|
'expiry' => (($options['ttl'] === null) ? null : ($options['now'] + $options['ttl'])),
|
|
|
|
|
'value' => $value,
|
|
|
|
|
];
|
|
|
|
|
$cache->set($key, $entry);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$value = $entry['value'];
|
|
|
|
|
}
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
?>
|