laravel-vuexy-admin-old/Services/CacheManagerService.php
2025-03-05 20:28:54 -06:00

390 lines
14 KiB
PHP

<?php
namespace Koneko\VuexyAdmin\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\File;
class CacheManagerService
{
private string $driver;
public function __construct(string $driver = null)
{
$this->driver = $driver ?? config('cache.default');
}
/**
* Obtiene estadísticas de caché para el driver especificado.
*/
public function getCacheStats(string $driver = null): array
{
$driver = $driver ?? $this->driver;
if (!$this->isSupportedDriver($driver)) {
return $this->response('warning', 'Driver no soportado o no configurado.');
}
try {
return match ($driver) {
'database' => $this->_getDatabaseStats(),
'file' => $this->_getFilecacheStats(),
'redis' => $this->_getRedisStats(),
'memcached' => $this->_getMemcachedStats(),
default => $this->response('info', 'No hay estadísticas disponibles para este driver.'),
};
} catch (\Exception $e) {
return $this->response('danger', 'Error al obtener estadísticas: ' . $e->getMessage());
}
}
public function clearCache(string $driver = null): array
{
$driver = $driver ?? $this->driver;
if (!$this->isSupportedDriver($driver)) {
return $this->response('warning', 'Driver no soportado o no configurado.');
}
try {
switch ($driver) {
case 'redis':
$keysCleared = $this->clearRedisCache();
return $keysCleared
? $this->response('warning', 'Se ha purgado toda la caché de Redis.')
: $this->response('info', 'No se encontraron claves en Redis para eliminar.');
case 'memcached':
$keysCleared = $this->clearMemcachedCache();
return $keysCleared
? $this->response('warning', 'Se ha purgado toda la caché de Memcached.')
: $this->response('info', 'No se encontraron claves en Memcached para eliminar.');
case 'database':
$rowsDeleted = $this->clearDatabaseCache();
return $rowsDeleted
? $this->response('warning', 'Se ha purgado toda la caché almacenada en la base de datos.')
: $this->response('info', 'No se encontraron registros en la caché de la base de datos.');
case 'file':
$filesDeleted = $this->clearFilecache();
return $filesDeleted
? $this->response('warning', 'Se ha purgado toda la caché de archivos.')
: $this->response('info', 'No se encontraron archivos en la caché para eliminar.');
default:
Cache::flush();
return $this->response('warning', 'Caché purgada.');
}
} catch (\Exception $e) {
return $this->response('danger', 'Error al limpiar la caché: ' . $e->getMessage());
}
}
public function getRedisStats()
{
try {
if (!Redis::ping()) {
return $this->response('warning', 'No se puede conectar con el servidor Redis.');
}
$info = Redis::info();
$databases = $this->getRedisDatabases();
$redisInfo = [
'server' => config('database.redis.default.host'),
'redis_version' => $info['redis_version'] ?? 'N/A',
'os' => $info['os'] ?? 'N/A',
'tcp_port' => $info['tcp_port'] ?? 'N/A',
'connected_clients' => $info['connected_clients'] ?? 'N/A',
'blocked_clients' => $info['blocked_clients'] ?? 'N/A',
'maxmemory' => $info['maxmemory'] ?? 0,
'used_memory_human' => $info['used_memory_human'] ?? 'N/A',
'used_memory_peak' => $info['used_memory_peak'] ?? 'N/A',
'used_memory_peak_human' => $info['used_memory_peak_human'] ?? 'N/A',
'total_system_memory' => $info['total_system_memory'] ?? 0,
'total_system_memory_human' => $info['total_system_memory_human'] ?? 'N/A',
'maxmemory_human' => $info['maxmemory_human'] !== '0B' ? $info['maxmemory_human'] : 'Sin Límite',
'total_connections_received' => number_format($info['total_connections_received']) ?? 'N/A',
'total_commands_processed' => number_format($info['total_commands_processed']) ?? 'N/A',
'maxmemory_policy' => $info['maxmemory_policy'] ?? 'N/A',
'role' => $info['role'] ?? 'N/A',
'cache_database' => '',
'sessions_database' => '',
'general_database' => ',',
'keys' => $databases['total_keys'],
'used_memory' => $info['used_memory'] ?? 0,
'uptime' => gmdate('H\h i\m s\s', $info['uptime_in_seconds'] ?? 0),
'databases' => $databases,
];
return $this->response('success', 'Se a recargado las estadísticas de Redis.', ['info' => $redisInfo]);
} catch (\Exception $e) {
return $this->response('danger', 'Error al conectar con el servidor Redis: ' . Redis::getLastError());
}
}
public function getMemcachedStats()
{
try {
$memcachedStats = [];
// Crear instancia del cliente Memcached
$memcached = new \Memcached();
$memcached->addServer(config('memcached.host'), config('memcached.port'));
// Obtener estadísticas del servidor
$stats = $memcached->getStats();
foreach ($stats as $server => $data) {
$server = explode(':', $server);
$memcachedStats[] = [
'server' => $server[0],
'tcp_port' => $server[1],
'uptime' => $data['uptime'] ?? 'N/A',
'version' => $data['version'] ?? 'N/A',
'libevent' => $data['libevent'] ?? 'N/A',
'max_connections' => $data['max_connections'] ?? 0,
'total_connections' => $data['total_connections'] ?? 0,
'rejected_connections' => $data['rejected_connections'] ?? 0,
'curr_items' => $data['curr_items'] ?? 0, // Claves almacenadas
'bytes' => $data['bytes'] ?? 0, // Memoria usada
'limit_maxbytes' => $data['limit_maxbytes'] ?? 0, // Memoria máxima
'cmd_get' => $data['cmd_get'] ?? 0, // Comandos GET ejecutados
'cmd_set' => $data['cmd_set'] ?? 0, // Comandos SET ejecutados
'get_hits' => $data['get_hits'] ?? 0, // GET exitosos
'get_misses' => $data['get_misses'] ?? 0, // GET fallidos
'evictions' => $data['evictions'] ?? 0, // Claves expulsadas
'bytes_read' => $data['bytes_read'] ?? 0, // Bytes leídos
'bytes_written' => $data['bytes_written'] ?? 0, // Bytes escritos
'total_items' => $data['total_items'] ?? 0,
];
}
return $this->response('success', 'Se a recargado las estadísticas de Memcached.', ['info' => $memcachedStats]);
} catch (\Exception $e) {
return $this->response('danger', 'Error al conectar con el servidor Memcached: ' . $e->getMessage());
}
}
/**
* Obtiene estadísticas para caché en base de datos.
*/
private function _getDatabaseStats(): array
{
try {
$recordCount = DB::table('cache')->count();
$tableInfo = DB::select("SHOW TABLE STATUS WHERE Name = 'cache'");
$memory_usage = isset($tableInfo[0]) ? $this->formatBytes($tableInfo[0]->Data_length + $tableInfo[0]->Index_length) : 'N/A';
return $this->response('success', 'Se ha recargado la información de la caché de base de datos.', ['item_count' => $recordCount, 'memory_usage' => $memory_usage]);
} catch (\Exception $e) {
return $this->response('danger', 'Error al obtener estadísticas de la base de datos: ' . $e->getMessage());
}
}
/**
* Obtiene estadísticas para caché en archivos.
*/
private function _getFilecacheStats(): array
{
try {
$cachePath = config('cache.stores.file.path');
$files = glob($cachePath . '/*');
$memory_usage = $this->formatBytes(array_sum(array_map('filesize', $files)));
return $this->response('success', 'Se ha recargado la información de la caché de archivos.', ['item_count' => count($files), 'memory_usage' => $memory_usage]);
} catch (\Exception $e) {
return $this->response('danger', 'Error al obtener estadísticas de archivos: ' . $e->getMessage());
}
}
private function _getRedisStats()
{
try {
$prefix = config('cache.prefix'); // Asegúrate de agregar el sufijo correcto si es necesario
$info = Redis::info();
$keys = Redis::connection('cache')->keys($prefix . '*');
$memory_usage = $this->formatBytes($info['used_memory'] ?? 0);
return $this->response('success', 'Se ha recargado la información de la caché de Redis.', ['item_count' => count($keys), 'memory_usage' => $memory_usage]);
} catch (\Exception $e) {
return $this->response('danger', 'Error al obtener estadísticas de Redis: ' . $e->getMessage());
}
}
public function _getMemcachedStats(): array
{
try {
// Obtener estadísticas generales del servidor
$stats = Cache::getStore()->getMemcached()->getStats();
if (empty($stats)) {
return $this->response('error', 'No se pudieron obtener las estadísticas del servidor Memcached.', ['item_count' => 0, 'memory_usage' => 0]);
}
// Usar el primer servidor configurado (en la mayoría de los casos hay uno)
$serverStats = array_shift($stats);
return $this->response(
'success',
'Estadísticas del servidor Memcached obtenidas correctamente.',
[
'item_count' => $serverStats['curr_items'] ?? 0, // Número total de claves
'memory_usage' => $this->formatBytes($serverStats['bytes'] ?? 0), // Memoria usada
'max_memory' => $this->formatBytes($serverStats['limit_maxbytes'] ?? 0), // Memoria máxima asignada
]
);
} catch (\Exception $e) {
return $this->response('danger', 'Error al obtener estadísticas de Memcached: ' . $e->getMessage());
}
}
private function getRedisDatabases(): array
{
// Verificar si Redis está en uso
$isRedisUsed = collect([
config('cache.default'),
config('session.driver'),
config('queue.default'),
])->contains('redis');
if (!$isRedisUsed) {
return []; // Si Redis no está en uso, devolver un arreglo vacío
}
// Configuraciones de bases de datos de Redis según su uso
$databases = [
'default' => config('database.redis.default.database', 0), // REDIS_DB
'cache' => config('database.redis.cache.database', 0), // REDIS_CACHE_DB
'sessions' => config('database.redis.sessions.database', 0), // REDIS_SESSION_DB
];
$result = [];
$totalKeys = 0;
// Recorrer solo las bases configuradas y activas
foreach ($databases as $type => $db) {
Redis::select($db); // Seleccionar la base de datos
$keys = Redis::dbsize(); // Contar las claves en la base
if ($keys > 0) {
$result[$type] = [
'database' => $db,
'keys' => $keys,
];
$totalKeys += $keys;
}
}
if (!empty($result)) {
$result['total_keys'] = $totalKeys;
}
return $result;
}
private function clearDatabaseCache(): bool
{
$count = DB::table(config('cache.stores.database.table'))->count();
if ($count > 0) {
DB::table(config('cache.stores.database.table'))->truncate();
return true;
}
return false;
}
private function clearFilecache(): bool
{
$cachePath = config('cache.stores.file.path');
$files = glob($cachePath . '/*');
if (!empty($files)) {
File::deleteDirectory($cachePath);
return true;
}
return false;
}
private function clearRedisCache(): bool
{
$prefix = config('cache.prefix', '');
$keys = Redis::connection('cache')->keys($prefix . '*');
if (!empty($keys)) {
Redis::connection('cache')->flushdb();
// Simulate cache clearing delay
sleep(1);
return true;
}
return false;
}
private function clearMemcachedCache(): bool
{
// Obtener el cliente Memcached directamente
$memcached = Cache::store('memcached')->getStore()->getMemcached();
// Ejecutar flush para eliminar todo
if ($memcached->flush()) {
// Simulate cache clearing delay
sleep(1);
return true;
}
return false;
}
/**
* Verifica si un driver es soportado.
*/
private function isSupportedDriver(string $driver): bool
{
return in_array($driver, ['redis', 'memcached', 'database', 'file']);
}
/**
* Convierte bytes en un formato legible.
*/
private function formatBytes($bytes)
{
$sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf('%.2f', $bytes / pow(1024, $factor)) . ' ' . $sizes[$factor];
}
/**
* Genera una respuesta estandarizada.
*/
private function response(string $status, string $message, array $data = []): array
{
return array_merge(compact('status', 'message'), $data);
}
}