FileCachedValue utilise Delay

This commit is contained in:
Jephté Clain 2024-05-13 17:59:15 +04:00
parent cf89396467
commit 4494c8ecc3
5 changed files with 83 additions and 33 deletions

View File

@ -44,7 +44,7 @@ Application::run(new class extends Application {
protected $args; protected $args;
function setActionUpdate(int $action, int $updateDuration): void { function setActionUpdate(int $action, $updateDuration): void {
$this->action = self::ACTION_UPDATE; $this->action = self::ACTION_UPDATE;
switch ($action) { switch ($action) {
case self::ACTION_UPDATE_SUB: $this->updateAction = -1; break; case self::ACTION_UPDATE_SUB: $this->updateAction = -1; break;
@ -81,7 +81,7 @@ Application::run(new class extends Application {
case self::ACTION_READ: case self::ACTION_READ:
if ($showSection) msg::section($file); if ($showSection) msg::section($file);
$cache = new CacheFile($file, [ $cache = new CacheFile($file, [
"duration" => PHP_INT_MAX, "duration" => "INF",
"override_duration" => true, "override_duration" => true,
]); ]);
yaml::dump($cache->get()); yaml::dump($cache->get());

View File

@ -7,15 +7,14 @@ use Exception;
use Generator; use Generator;
use nur\A; use nur\A;
use nur\b\coll\TBaseArray; use nur\b\coll\TBaseArray;
use nur\b\date\Date;
use nur\b\date\Datetime;
use nur\b\IllegalAccessException; use nur\b\IllegalAccessException;
use nur\b\params\Parametrable; use nur\b\params\Parametrable;
use nur\b\params\Tparametrable; use nur\b\params\Tparametrable;
use nur\data\types\Tmd; use nur\data\types\Tmd;
use nur\file; use nur\file;
use nur\os; use nur\os;
use nur\ref\ref_cache; use nur\sery\php\time\DateTime;
use nur\sery\php\time\Delay;
/** /**
* Class FileCachedValue: un fichier utilisé pour mettre en cache certaines * Class FileCachedValue: un fichier utilisé pour mettre en cache certaines
@ -28,8 +27,8 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
/** @var string chemin vers le fichier cache par défaut */ /** @var string chemin vers le fichier cache par défaut */
const FILE = null; const FILE = null;
/** @var int durée de vie par défaut du cache en secondes */ /** @var int durée de vie par défaut du cache */
const DURATION = 8 * ref_cache::HOUR; const DURATION = "1D"; // jusqu'au lendemain
/** @var bool faut-il mettre en cache la valeur nulle? */ /** @var bool faut-il mettre en cache la valeur nulle? */
const CACHE_NULL = false; const CACHE_NULL = false;
@ -50,7 +49,7 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
const PARAMETRABLE_PARAMS_SCHEMA = [ const PARAMETRABLE_PARAMS_SCHEMA = [
"file" => ["?string", null, "chemin vers le fichier"], "file" => ["?string", null, "chemin vers le fichier"],
"duration" => ["int", null, "durée de vie du cache en secondes"], "duration" => [Delay::class, null, "durée de vie du cache"],
"override_duration" => ["bool", false, "faut-il ignorer la duration inscrite dans le fichier et prendre la valeur locale?"], "override_duration" => ["bool", false, "faut-il ignorer la duration inscrite dans le fichier et prendre la valeur locale?"],
"cache_null" => ["bool", false, "faut-il mettre en cache la valeur null?"], "cache_null" => ["bool", false, "faut-il mettre en cache la valeur null?"],
"data" => ["array", null, "données supplémentaires"] "data" => ["array", null, "données supplémentaires"]
@ -67,7 +66,7 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
return $cacheFile; return $cacheFile;
} }
/** @var int */ /** @var Delay */
protected $ppDuration; protected $ppDuration;
/** @var bool */ /** @var bool */
@ -94,8 +93,8 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
$outf = file::open($file, "wb"); $outf = file::open($file, "wb");
try { try {
$contents = $this->serialize($data); $contents = $this->serialize($data);
$tstart = time(); $tstart = new DateTime();
$duration = $this->ppDuration; $duration = Delay::with($this->ppDuration, $tstart);
fwrite($outf, serialize([$tstart, $duration])."\n"); fwrite($outf, serialize([$tstart, $duration])."\n");
fwrite($outf, $contents); fwrite($outf, $contents);
} finally { } finally {
@ -150,19 +149,25 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
protected function loadInfos(): array { protected function loadInfos(): array {
[$tstart, $duration] = unserialize(fgets($this->fp)); [$tstart, $duration] = unserialize(fgets($this->fp));
if ($this->ppOverrideDuration) $duration = $this->ppDuration; if (is_int($tstart)) {
$tstart = new DateTime($tstart);
$duration = new Delay($duration, $tstart);
}
if ($this->ppOverrideDuration) {
$duration = Delay::with($this->ppDuration, $tstart);
}
return [$tstart, $duration]; return [$tstart, $duration];
} }
protected function shouldUpdate(bool $noCache=false) { protected function shouldUpdate(bool $noCache=false) {
/** @var Delay $duration */
$this->_open(); $this->_open();
$cleanup = true; $cleanup = true;
try { try {
$this->_lock(LOCK_SH); $this->_lock(LOCK_SH);
if ($this->isValidFile()) { if ($this->isValidFile()) {
$now = time();
[$tstart, $duration] = $this->loadInfos(); [$tstart, $duration] = $this->loadInfos();
$expired = $now - $tstart > $duration; $expired = $duration->isElapsed();
} else { } else {
$expired = false; $expired = false;
$noCache = true; $noCache = true;
@ -234,16 +239,18 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
$this->_lock(LOCK_SH); $this->_lock(LOCK_SH);
if (!$this->isValidFile()) return ["valid" => false]; if (!$this->isValidFile()) return ["valid" => false];
$size = filesize($this->ppFile); $size = filesize($this->ppFile);
/**
* @var DateTime $tstart
* @var Delay $duration
*/
[$tstart, $duration] = $this->loadInfos(); [$tstart, $duration] = $this->loadInfos();
$dateStart = new Datetime($tstart);
$dateEnd = new Datetime($tstart + $duration);
return [ return [
"valid" => true, "valid" => true,
"size" => $size, "size" => $size,
"tstart" => $tstart, "tstart" => $tstart,
"duration" => $duration, "duration" => strval($duration),
"date_start" => $dateStart->format(), "date_start" => $tstart->format(),
"date_end" => $dateEnd->format(), "date_end" => $duration->getDest()->format(),
]; ];
} finally { } finally {
$this->cleanup(); $this->cleanup();
@ -253,17 +260,21 @@ abstract class FileCachedValue extends Parametrable implements ArrayAccess, Coun
const UPDATE_SUB = -1, UPDATE_SET = 0, UPDATE_ADD = 1; const UPDATE_SUB = -1, UPDATE_SET = 0, UPDATE_ADD = 1;
/** mettre à jour la durée de validité du fichier */ /** mettre à jour la durée de validité du fichier */
function updateDuration(int $duration, int $action=1): void { function updateDuration($nduration, int $action=1): void {
$this->_open(); $this->_open();
try { try {
$this->_lock(LOCK_SH); $this->_lock(LOCK_SH);
if (!$this->isValidFile()) return; if (!$this->isValidFile()) return;
$this->_lock(LOCK_EX); $this->_lock(LOCK_EX);
$fp = $this->fp; $fp = $this->fp;
[$tstart, $oduration] = $this->loadInfos(); /**
* @var DateTime $tstart
* @var Delay $duration
*/
[$tstart, $duration] = $this->loadInfos();
$contents = stream_get_contents($fp); $contents = stream_get_contents($fp);
if ($action < 0) $duration = $oduration - $duration; if ($action < 0) $duration->subDuration($nduration);
elseif ($action > 0) $duration = $oduration + $duration; elseif ($action > 0) $duration->addDuration($nduration);
fseek($fp, 0); fseek($fp, 0);
ftruncate($fp, 0); ftruncate($fp, 0);
fwrite($fp, serialize([$tstart, $duration])."\n"); fwrite($fp, serialize([$tstart, $duration])."\n");

View File

@ -4,6 +4,11 @@ namespace nur\sery\php\time;
use InvalidArgumentException; use InvalidArgumentException;
class DateInterval extends \DateInterval { class DateInterval extends \DateInterval {
static function with($interval): self {
if ($interval instanceof static) return $interval;
else return new static($interval);
}
protected static function to_string(DateInterval $interval) { protected static function to_string(DateInterval $interval) {
$string = "P"; $string = "P";
$y = $interval->y; $y = $interval->y;
@ -24,6 +29,7 @@ class DateInterval extends \DateInterval {
} }
function __construct($duration) { function __construct($duration) {
if (is_int($duration)) $duration = "PT${duration}S";
if ($duration instanceof \DateInterval) { if ($duration instanceof \DateInterval) {
$this->y = $duration->y; $this->y = $duration->y;
$this->m = $duration->m; $this->m = $duration->m;

View File

@ -24,6 +24,11 @@ use InvalidArgumentException;
* @property-read string $YmdHMSZ * @property-read string $YmdHMSZ
*/ */
class DateTime extends \DateTime { class DateTime extends \DateTime {
static function with($datetime): self {
if ($datetime instanceof static) return $datetime;
else return new static($datetime);
}
const DMY_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))?$/'; const DMY_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))?$/';
const YMD_PATTERN = '/^((?:\d{2})?\d{2})(\d{2})(\d{2})$/'; const YMD_PATTERN = '/^((?:\d{2})?\d{2})(\d{2})(\d{2})$/';
const DMYHIS_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))? +(\d+)[h:.](\d+)(?:[:.](\d+))?$/'; const DMYHIS_PATTERN = '/^(\d+)\/(\d+)(?:\/(\d+))? +(\d+)[h:.](\d+)(?:[:.](\d+))?$/';

View File

@ -13,6 +13,7 @@ use InvalidArgumentException;
* - une chaine de la forme "x[WDHMS]y" x et y sont des nombres et la lettre * - une chaine de la forme "x[WDHMS]y" x et y sont des nombres et la lettre
* est l'unité de temps: W représente une semaine, D une journée, H une heure, * est l'unité de temps: W représente une semaine, D une journée, H une heure,
* M une minute et S une seconde. * M une minute et S une seconde.
* - la chaine "INF" qui représente une durée infinie
* *
* Dans cette dernière forme, le timestamp destination est calculé en ajoutant x * Dans cette dernière forme, le timestamp destination est calculé en ajoutant x
* unités. puis l'unité inférieure est ramenée à (0 + y) * unités. puis l'unité inférieure est ramenée à (0 + y)
@ -24,6 +25,11 @@ use InvalidArgumentException;
* NB: la valeur y pour l'unité S est ignorée * NB: la valeur y pour l'unité S est ignorée
*/ */
class Delay { class Delay {
static function with($delay, ?DateTimeInterface $from=null): self {
if ($delay instanceof static) return $delay;
else return new static($delay, $from);
}
/** valeurs par défaut de x et y pour les unités supportées */ /** valeurs par défaut de x et y pour les unités supportées */
const DEFAULTS = [ const DEFAULTS = [
"w" => [0, 5], "w" => [0, 5],
@ -35,6 +41,7 @@ class Delay {
static function compute_dest(int $x, string $u, ?int $y, DateTime $from): array { static function compute_dest(int $x, string $u, ?int $y, DateTime $from): array {
$dest = DateTime::clone($from); $dest = DateTime::clone($from);
$yu = null;
switch ($u) { switch ($u) {
case "w": case "w":
if ($x > 0) { if ($x > 0) {
@ -43,29 +50,28 @@ class Delay {
} }
$w = 7 - intval($dest->format("w")); $w = 7 - intval($dest->format("w"));
$dest->add(new \DateInterval("P${w}D")); $dest->add(new \DateInterval("P${w}D"));
$u = "h"; $yu = "h";
break; break;
case "d": case "d":
$dest->add(new \DateInterval("P${x}D")); $dest->add(new \DateInterval("P${x}D"));
$u = "h"; $yu = "h";
break; break;
case "h": case "h":
$dest->add(new \DateInterval("PT${x}H")); $dest->add(new \DateInterval("PT${x}H"));
$u = "m"; $yu = "m";
break; break;
case "m": case "m":
$dest->add(new \DateInterval("PT${x}M")); $dest->add(new \DateInterval("PT${x}M"));
$u = "s"; $yu = "s";
break; break;
case "s": case "s":
$dest->add(new \DateInterval("PT${x}S")); $dest->add(new \DateInterval("PT${x}S"));
$u = null;
break; break;
} }
if ($y !== null && $u !== null) { if ($y !== null && $yu !== null) {
$h = intval($dest->format("H")); $h = intval($dest->format("H"));
$m = intval($dest->format("i")); $m = intval($dest->format("i"));
switch ($u) { switch ($yu) {
case "h": case "h":
$dest->setTime($y, 0, 0, 0); $dest->setTime($y, 0, 0, 0);
break; break;
@ -77,13 +83,18 @@ class Delay {
break; break;
} }
} }
$repr = $y !== null? "$x$y$y": "$x"; $u = strtoupper($u);
$repr = $y !== null? "$x$u$y": "$x";
return [$dest, $repr]; return [$dest, $repr];
} }
function __construct($delay, ?DateTimeInterface $from=null) { function __construct($delay, ?DateTimeInterface $from=null) {
if ($from === null) $from = new DateTime(); if ($from === null) $from = new DateTime();
if (is_int($delay)) { if ($delay === "INF") {
$dest = DateTime::clone($from);
$dest->add(new DateInterval("P9999Y"));
$repr = "INF";
} elseif (is_int($delay)) {
[$dest, $repr] = self::compute_dest($delay, "s", null, $from); [$dest, $repr] = self::compute_dest($delay, "s", null, $from);
} elseif (is_string($delay) && preg_match('/^\d+$/', $delay)) { } elseif (is_string($delay) && preg_match('/^\d+$/', $delay)) {
$x = intval($delay); $x = intval($delay);
@ -111,6 +122,22 @@ class Delay {
return $this->dest; return $this->dest;
} }
function addDuration($duration) {
if (is_int($duration) && $duration < 0) {
$this->dest->sub(DateInterval::with(-$duration));
} else {
$this->dest->add(DateInterval::with($duration));
}
}
function subDuration($duration) {
if (is_int($duration) && $duration < 0) {
$this->dest->add(DateInterval::with(-$duration));
} else {
$this->dest->sub(DateInterval::with($duration));
}
}
/** @var string */ /** @var string */
protected $repr; protected $repr;
@ -125,7 +152,8 @@ class Delay {
/** retourner true si le délai imparti est écoulé */ /** retourner true si le délai imparti est écoulé */
function isElapsed(?DateTimeInterface $now=null): bool { function isElapsed(?DateTimeInterface $now=null): bool {
return $this->_getDiff($now)->invert == 0; if ($this->repr === "INF") return false;
else return $this->_getDiff($now)->invert == 0;
} }
/** /**