Files
annu-kute-ced/includes/simple-cache.php
T

233 lines
6.1 KiB
PHP

<?php
/**
* Cache simple pour les API PeerTube - optimisation minimale
*/
class SimpleAPICache {
private $cacheDir;
private $enabled;
public function __construct($cacheDir = null) {
$this->cacheDir = $cacheDir ?? (__DIR__ . '/../cache/api');
$this->enabled = true;
// Créer le répertoire de cache s'il n'existe pas
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0755, true);
}
}
/**
* Génère une clé de cache
*/
private function getCacheKey($endpoint, $params = []) {
$key = $endpoint;
if (!empty($params)) {
ksort($params);
$key .= '_' . md5(serialize($params));
}
return 'cache_' . md5($key) . '.json';
}
/**
* Récupère depuis le cache
*/
public function get($endpoint, $params = []) {
if (!$this->enabled) return null;
$file = $this->cacheDir . '/' . $this->getCacheKey($endpoint, $params);
if (!file_exists($file)) {
return null;
}
$data = json_decode(file_get_contents($file), true);
// Vérifier l'expiration
if (isset($data['expires']) && time() > $data['expires']) {
unlink($file);
return null;
}
return $data['content'] ?? null;
}
/**
* Stocke dans le cache
*/
public function set($endpoint, $params, $content, $ttl = 300) {
if (!$this->enabled) return;
$file = $this->cacheDir . '/' . $this->getCacheKey($endpoint, $params);
$data = [
'content' => $content,
'expires' => time() + $ttl,
'created' => time()
];
// Verrou exclusif : évite les écritures concurrentes tronquées
file_put_contents($file, json_encode($data), LOCK_EX);
}
/**
* Vide entièrement le cache (entrées valides comme expirées)
*
* @return int Nombre de fichiers supprimés
*/
public function clear() {
$files = glob($this->cacheDir . '/cache_*.json');
$deleted = 0;
foreach ($files as $file) {
if (unlink($file)) {
$deleted++;
}
}
return $deleted;
}
/**
* Nettoie le cache expiré
*/
public function cleanup() {
$files = glob($this->cacheDir . '/cache_*.json');
$cleaned = 0;
foreach ($files as $file) {
$data = json_decode(file_get_contents($file), true);
if (isset($data['expires']) && time() > $data['expires']) {
unlink($file);
$cleaned++;
}
}
return $cleaned;
}
}
// Instance globale
$GLOBALS['simple_api_cache'] = new SimpleAPICache();
/**
* TTL de cache selon l'endpoint PeerTube.
*
* Correspondance exacte d'abord, puis par préfixe. L'ancien matching par
* sous-chaîne (strpos) créait des collisions : « accounts/{nom}/videos »
* capturait le TTL de « videos » (10 min) au lieu de celui de « accounts »
* (5 min, pensé pour les lives).
*
* @param string $endpoint Endpoint de l'API (sans slash initial)
* @return int TTL en secondes
*/
function getPeerTubeCacheTtl($endpoint) {
static $exactMap = [
'videos/categories' => 3600, // 1 heure
'videos' => 600, // 10 minutes
'search/videos' => 600, // 10 minutes
'wp-posts' => 900, // 15 minutes pour WordPress
'accounts' => 300 // 5 minutes pour live streams
];
static $prefixMap = [
'accounts/' => 300, // lives : accounts/{nom}/videos
'video-channels/' => 600, // vidéos d'une chaîne
'videos/' => 600 // videos/{id}, commentaires
];
if (isset($exactMap[$endpoint])) {
return $exactMap[$endpoint];
}
foreach ($prefixMap as $prefix => $ttl) {
if (strpos($endpoint, $prefix) === 0) {
return $ttl;
}
}
return 300; // Défaut 5 minutes
}
/**
* Version cachée de callPeerTubeApi - remplace l'originale
*/
function callPeerTubeApiCached($endpoint, $params = []) {
// Cache désactivé : appel direct, sans lecture ni écriture
if (!defined('CACHE_ENABLED') || !CACHE_ENABLED) {
return callPeerTubeApiOriginal($endpoint, $params);
}
$cache = $GLOBALS['simple_api_cache'];
$ttl = getPeerTubeCacheTtl($endpoint);
// Essayer le cache d'abord
$cached = $cache->get($endpoint, $params);
if ($cached !== null) {
return $cached;
}
// Appeler l'API originale
$data = callPeerTubeApiOriginal($endpoint, $params);
// Mettre en cache si on a des données
if (!empty($data)) {
$cache->set($endpoint, $params, $data, $ttl);
}
return $data;
}
/**
* Cache générique pour tout type d'API
*/
function callApiCached($cacheKey, $callable, $ttl = 900) {
$cache = $GLOBALS['simple_api_cache'];
// Essayer le cache d'abord
$cached = $cache->get($cacheKey, []);
if ($cached !== null) {
return $cached;
}
// Appeler la fonction fournie
try {
$data = call_user_func($callable);
} catch (Exception $e) {
error_log('API call failed for ' . $cacheKey . ': ' . $e->getMessage());
return [];
}
// Mettre en cache si on a des données
if (!empty($data)) {
$cache->set($cacheKey, [], $data, $ttl);
}
return $data;
}
/**
* Helpers simples pour le cache générique
*/
function getFromCache($key) {
if (!defined('CACHE_ENABLED') || !CACHE_ENABLED) {
return null;
}
$cache = $GLOBALS['simple_api_cache'];
return $cache->get($key, []);
}
function saveToCache($key, $data, $ttl = null) {
if (!defined('CACHE_ENABLED') || !CACHE_ENABLED) {
return;
}
$ttl = $ttl ?? (defined('CACHE_DURATION') ? CACHE_DURATION : 3600);
$cache = $GLOBALS['simple_api_cache'];
$cache->set($key, [], $data, $ttl);
}
// Nettoyage automatique occasionnel
if (rand(1, 100) === 1) {
$GLOBALS['simple_api_cache']->cleanup();
}
?>