390 lines
14 KiB
PHP
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);
|
|
}
|
|
}
|