352 lines
14 KiB
PHP
352 lines
14 KiB
PHP
<?php
|
||
//
|
||
//namespace App\Livewire\Ui\Dashboard;
|
||
//
|
||
//use Carbon\Carbon;
|
||
//use Illuminate\Support\Facades\Cache;
|
||
//use Livewire\Component;
|
||
//
|
||
//class HealthCard extends Component
|
||
//{
|
||
// // Rohdaten
|
||
// public array $services = [];
|
||
// public array $meta = [];
|
||
//
|
||
// // UI: Balken/Segmente
|
||
// public int $barSegments = 24;
|
||
// public array $cpuSeg = [];
|
||
// public array $ramSeg = [];
|
||
//
|
||
// // UI: Load & Uptime
|
||
// public string $loadBadgeText = '';
|
||
// public array $loadDots = [];
|
||
// public array $uptimeChips = [];
|
||
// public string $uptimeIcon = 'ph ph-clock';
|
||
//
|
||
// // UI: Services kompakt
|
||
// public array $servicesCompact = [];
|
||
//
|
||
// // Storage
|
||
// public ?int $diskUsedGb = null;
|
||
// public ?int $diskTotalGb = null;
|
||
// public ?int $diskPercent = null;
|
||
// public ?int $diskFreeGb = null;
|
||
// public array $diskSegments = [];
|
||
// public int $diskInnerSize = 160; // grauer Kreis
|
||
// public int $diskSegOuterRadius = 92; // Abstand der Ticks
|
||
// public array $diskCenterText = ['percent'=>'–%','label'=>'Speicher belegt'];
|
||
//
|
||
// // Anzeige oben
|
||
// public ?string $ramSummary = null;
|
||
// public ?string $loadText = null;
|
||
// public ?string $uptimeText = null;
|
||
// public ?int $cpuPercent = null;
|
||
// public ?int $ramPercent = null;
|
||
// public ?string $updatedAtHuman = null;
|
||
//
|
||
// public $guardOk = [];
|
||
// public function mount(): void
|
||
// {
|
||
// $this->loadData();
|
||
// }
|
||
//
|
||
// public function loadData(): void
|
||
// {
|
||
// $this->services = Cache::get('health:services', []);
|
||
// $this->meta = Cache::get('health:meta', []);
|
||
//
|
||
// $this->hydrateSystem();
|
||
// $this->hydrateDisk();
|
||
// $this->hydrateUpdatedAt();
|
||
// $this->decorateServicesCompact();
|
||
// $this->decorateDisk();
|
||
// }
|
||
//
|
||
// public function render()
|
||
// {
|
||
// return view('livewire.ui.dashboard.health-card');
|
||
// }
|
||
//
|
||
// /* ---------------- Aufbereitung ---------------- */
|
||
//
|
||
// protected function hydrateSystem(): void
|
||
// {
|
||
// $sys = is_array($this->meta['system'] ?? null) ? $this->meta['system'] : [];
|
||
//
|
||
// // RAM %
|
||
// $this->ramPercent = $this->numInt($this->pick($sys, ['ram','ram_percent','mem_percent','memory']));
|
||
// if ($this->ramPercent === null && is_array($sys['ram'] ?? null)) {
|
||
// $this->ramPercent = $this->numInt($this->pick($sys['ram'], ['percent','used_percent']));
|
||
// }
|
||
//
|
||
// // RAM Summary "used / total"
|
||
// $used = $this->numInt($this->pick($sys['ram'] ?? [], ['used_gb','used','usedGB']));
|
||
// $tot = $this->numInt($this->pick($sys['ram'] ?? [], ['total_gb','total','totalGB']));
|
||
// $this->ramSummary = ($used !== null && $tot !== null) ? "{$used} GB / {$tot} GB" : null;
|
||
//
|
||
// // Load (1/5/15)
|
||
// $load1 = $this->numFloat($this->pick($sys, ['cpu_load_1','load1','load_1']));
|
||
// $load5 = $this->numFloat($this->pick($sys, ['cpu_load_5','load5','load_5']));
|
||
// $load15 = $this->numFloat($this->pick($sys, ['cpu_load_15','load15','load_15']));
|
||
//
|
||
// $loadMixed = $this->pick($sys, ['load','loadavg','load_avg','load_text']);
|
||
// if (is_array($loadMixed)) {
|
||
// $vals = array_values($loadMixed);
|
||
// $load1 ??= $this->numFloat($vals[0] ?? null);
|
||
// $load5 ??= $this->numFloat($vals[1] ?? null);
|
||
// $load15 ??= $this->numFloat($vals[2] ?? null);
|
||
// }
|
||
// $this->loadText = $this->fmtLoad($load1, $load5, $load15, is_string($loadMixed) ? $loadMixed : null);
|
||
//
|
||
// // CPU %
|
||
// $this->cpuPercent = $this->numInt($this->pick($sys, ['cpu','cpu_percent','cpuUsage','cpu_usage']));
|
||
// if ($this->cpuPercent === null && $load1 !== null) {
|
||
// $cores = $this->numInt($this->pick($sys, ['cores','cpu_cores','num_cores'])) ?: 1;
|
||
// $this->cpuPercent = (int) round(min(100, max(0, ($load1 / max(1,$cores)) * 100)));
|
||
// }
|
||
//
|
||
// // Uptime
|
||
// $this->uptimeText = $this->pick($sys, ['uptime_human','uptimeText','uptime']);
|
||
// if (!$this->uptimeText) {
|
||
// $uptimeSec = $this->numInt($this->pick($sys, ['uptime_seconds','uptime_sec','uptime_s']));
|
||
// if ($uptimeSec !== null) $this->uptimeText = $this->secondsToHuman($uptimeSec);
|
||
// }
|
||
//
|
||
// // Segment-Balken
|
||
// $this->cpuSeg = $this->buildSegments($this->cpuPercent);
|
||
// $this->ramSeg = $this->buildSegments($this->ramPercent);
|
||
//
|
||
// // Load: Dots (1/5/15 relativ zu Kernen)
|
||
// $cores = max(1, (int)($this->pick($sys, ['cores','cpu_cores','num_cores']) ?? 1));
|
||
// $ratio1 = $load1 !== null ? $load1 / $cores : null;
|
||
// $ratio5 = $load5 !== null ? $load5 / $cores : null;
|
||
// $ratio15 = $load15 !== null ? $load15 / $cores : null;
|
||
//
|
||
// $this->loadBadgeText = $this->loadText ?? '–';
|
||
// $this->loadDots = [
|
||
// ['label'=>'1m', 'cls'=>$this->loadDotClass($ratio1)],
|
||
// ['label'=>'5m', 'cls'=>$this->loadDotClass($ratio5)],
|
||
// ['label'=>'15m', 'cls'=>$this->loadDotClass($ratio15)],
|
||
// ];
|
||
//
|
||
// // Uptime Chips
|
||
// $chips = [];
|
||
// if ($this->uptimeText) {
|
||
// $d = $h = $m = null;
|
||
// if (preg_match('/(\d+)d/i', $this->uptimeText, $m1)) $d = (int)$m1[1];
|
||
// if (preg_match('/(\d+)h/i', $this->uptimeText, $m2)) $h = (int)$m2[1];
|
||
// if (preg_match('/(\d+)m/i', $this->uptimeText, $m3)) $m = (int)$m3[1];
|
||
// if ($d !== null) $chips[] = ['v'=>$d, 'u'=>'Tage'];
|
||
// if ($h !== null) $chips[] = ['v'=>$h, 'u'=>'Stunden'];
|
||
// if ($m !== null) $chips[] = ['v'=>$m, 'u'=>'Minuten'];
|
||
// }
|
||
// $this->uptimeChips = $chips ?: [['v'=>'–','u'=>'']];
|
||
// }
|
||
//
|
||
// protected function hydrateDisk(): void
|
||
// {
|
||
// $disk = is_array($this->meta['disk'] ?? null) ? $this->meta['disk'] : [];
|
||
//
|
||
// $this->diskPercent = $this->numInt($this->pick($disk, ['percent','usage']));
|
||
// $this->diskFreeGb = $this->numInt($this->pick($disk, ['free_gb','free']));
|
||
//
|
||
// // total/used berechnen, falls nicht geliefert
|
||
// if ($this->diskFreeGb !== null && $this->diskPercent !== null && $this->diskPercent < 100) {
|
||
// $p = max(0, min(100, $this->diskPercent)) / 100;
|
||
// $estTotal = (int) round($this->diskFreeGb / (1 - $p));
|
||
// $this->diskTotalGb = $estTotal > 0 ? $estTotal : null;
|
||
// }
|
||
// if ($this->diskTotalGb !== null && $this->diskFreeGb !== null) {
|
||
// $u = $this->diskTotalGb - $this->diskFreeGb;
|
||
// $this->diskUsedGb = $u >= 0 ? $u : null;
|
||
// }
|
||
// }
|
||
//
|
||
// protected function hydrateUpdatedAt(): void
|
||
// {
|
||
// $updated = $this->meta['updated_at'] ?? null;
|
||
// try { $this->updatedAtHuman = $updated ? Carbon::parse($updated)->diffForHumans() : '–';
|
||
// } catch (\Throwable) { $this->updatedAtHuman = '–'; }
|
||
// }
|
||
//
|
||
// protected function decorateServicesCompact(): void
|
||
// {
|
||
// $nameMap = [
|
||
// 'postfix' => ['label' => 'Postfix', 'hint' => 'MTA'],
|
||
// 'dovecot' => ['label' => 'Dovecot', 'hint' => 'IMAP/POP3'],
|
||
// 'rspamd' => ['label' => 'Rspamd', 'hint' => 'Spamfilter'],
|
||
// 'db' => ['label' => 'Datenbank', 'hint' => 'MySQL/MariaDB'],
|
||
// '127.0.0.1:6379' => ['label' => 'Redis', 'hint' => 'Cache/Queue'],
|
||
// '127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket'],
|
||
// ];
|
||
//
|
||
//// $nameMap = [
|
||
//// // --- Mail ---
|
||
//// 'postfix' => ['label' => 'Postfix', 'hint' => 'MTA / Versand'],
|
||
//// 'dovecot' => ['label' => 'Dovecot', 'hint' => 'IMAP / POP3'],
|
||
//// 'rspamd' => ['label' => 'Rspamd', 'hint' => 'Spamfilter'],
|
||
//// 'clamav' => ['label' => 'ClamAV', 'hint' => 'Virenscanner'],
|
||
////
|
||
//// // --- Daten & Cache ---
|
||
//// 'db' => ['label' => 'Datenbank', 'hint' => 'MySQL / MariaDB'],
|
||
//// '127.0.0.1:6379' => ['label' => 'Redis', 'hint' => 'Cache / Queue'],
|
||
////
|
||
//// // --- Web / PHP ---
|
||
//// 'php8.2-fpm' => ['label' => 'PHP-FPM', 'hint' => 'PHP Runtime'],
|
||
//// 'nginx' => ['label' => 'Nginx', 'hint' => 'Webserver'],
|
||
////
|
||
//// // --- MailWolt spezifisch ---
|
||
//// 'mailwolt-queue' => ['label' => 'MailWolt Queue', 'hint' => 'Job Worker'],
|
||
//// 'mailwolt-schedule'=> ['label' => 'MailWolt Schedule','hint' => 'Task Scheduler'],
|
||
////
|
||
//// // --- Sonstige Infrastruktur ---
|
||
//// 'fail2ban' => ['label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection'],
|
||
//// 'systemd-journald'=> ['label' => 'System Logs', 'hint' => 'Logging / Journal'],
|
||
////
|
||
//// // --- WebSocket & Echtzeit ---
|
||
//// '127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket Server'],
|
||
//// ];
|
||
//
|
||
// $existing = collect($this->services)->keyBy('name');
|
||
//
|
||
// $this->servicesCompact = collect($nameMap)
|
||
// ->map(function ($meta, $key) use ($existing) {
|
||
// $srv = $existing->get($key, []);
|
||
// $ok = (bool)($srv['ok'] ?? false);
|
||
//
|
||
// return [
|
||
// 'label' => $meta['label'],
|
||
// 'hint' => $meta['hint'],
|
||
// 'ok' => $ok,
|
||
//
|
||
// // Punktfarbe
|
||
// 'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
||
//
|
||
// // ✅ Bessere Status-Texte
|
||
// 'pillText' => $ok ? 'Aktiv' : 'Offline',
|
||
//
|
||
// // Farbe für Pill
|
||
// 'pillClass' => $ok
|
||
// ? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
||
// : 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
||
// ];
|
||
// })
|
||
// ->values()
|
||
// ->all();
|
||
//
|
||
// $this->guardOk = collect($this->services)->every(
|
||
// fn($s) => (bool)($s['ok'] ?? false)
|
||
// );
|
||
//// $this->servicesCompact = collect($this->services)
|
||
//// ->map(function ($srv) use ($nameMap) {
|
||
//// $key = (string)($srv['name'] ?? '');
|
||
//// $ok = (bool) ($srv['ok'] ?? false);
|
||
//// $label = $nameMap[$key]['label'] ?? ucfirst($key);
|
||
//// $hint = $nameMap[$key]['hint'] ?? (str_contains($key, ':') ? $key : '');
|
||
////
|
||
//// var_dump($srv);
|
||
//// return [
|
||
//// 'label' => $label,
|
||
//// 'hint' => $hint,
|
||
//// 'ok' => $ok,
|
||
//// 'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
|
||
//// 'pillText' => $ok ? 'Läuft' : 'Down',
|
||
//// 'pillClass' => $ok
|
||
//// ? 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10'
|
||
//// : 'text-rose-300 border-rose-400/30 bg-rose-500/10',
|
||
//// ];
|
||
//// })
|
||
//// ->values()
|
||
//// ->all();
|
||
// }
|
||
//
|
||
// protected function decorateDisk(): void
|
||
// {
|
||
// $percent = (int) max(0, min(100, (int)($this->diskPercent ?? 0)));
|
||
// $this->diskCenterText = [
|
||
// 'percent' => is_numeric($this->diskPercent) ? $this->diskPercent.'%' : '–%',
|
||
// 'label' => 'Speicher belegt',
|
||
// ];
|
||
//
|
||
// $count = 48;
|
||
// $activeN = is_numeric($this->diskPercent) ? (int) round($count * $percent / 100) : 0;
|
||
// $step = 360 / $count;
|
||
//
|
||
// $activeClass = match (true) {
|
||
// $percent >= 90 => 'bg-rose-400',
|
||
// $percent >= 70 => 'bg-amber-300',
|
||
// default => 'bg-emerald-400',
|
||
// };
|
||
//
|
||
// $this->diskSegments = [];
|
||
// for ($i = 0; $i < $count; $i++) {
|
||
// $angle = ($i * $step) - 90; // Start bei 12 Uhr
|
||
// $this->diskSegments[] = [
|
||
// 'angle' => $angle,
|
||
// 'class' => $i < $activeN ? $activeClass : 'bg-white/16',
|
||
// ];
|
||
// }
|
||
// }
|
||
//
|
||
// /* ---------------- Helpers ---------------- */
|
||
//
|
||
// protected function pick(array $arr, array $keys)
|
||
// {
|
||
// foreach ($keys as $k) {
|
||
// if (array_key_exists($k, $arr) && $arr[$k] !== null && $arr[$k] !== '') {
|
||
// return $arr[$k];
|
||
// }
|
||
// }
|
||
// return null;
|
||
// }
|
||
//
|
||
// protected function numInt($v): ?int { return is_numeric($v) ? (int) round($v) : null; }
|
||
// protected function numFloat($v): ?float{ return is_numeric($v) ? (float)$v : null; }
|
||
//
|
||
// protected function fmtLoad(?float $l1, ?float $l5, ?float $l15, ?string $fallback): ?string
|
||
// {
|
||
// if ($l1 !== null || $l5 !== null || $l15 !== null) {
|
||
// $fmt = fn($x) => $x === null ? '–' : number_format($x, 2);
|
||
// return "{$fmt($l1)} / {$fmt($l5)} / {$fmt($l15)}";
|
||
// }
|
||
// return $fallback ?: null;
|
||
// }
|
||
//
|
||
// protected function secondsToHuman(int $s): string
|
||
// {
|
||
// $d = intdiv($s, 86400); $s %= 86400;
|
||
// $h = intdiv($s, 3600); $s %= 3600;
|
||
// $m = intdiv($s, 60);
|
||
// if ($d > 0) return "{$d}d {$h}h";
|
||
// if ($h > 0) return "{$h}h {$m}m";
|
||
// return "{$m}m";
|
||
// }
|
||
//
|
||
// protected function toneByPercent(?int $p): string {
|
||
// if ($p === null) return 'white';
|
||
// if ($p >= 90) return 'rose';
|
||
// if ($p >= 70) return 'amber';
|
||
// return 'emerald';
|
||
// }
|
||
//
|
||
// protected function buildSegments(?int $percent): array {
|
||
// $n = max(6, $this->barSegments);
|
||
// $filled = is_numeric($percent) ? (int) round($n * max(0, min(100, $percent)) / 100) : 0;
|
||
// $tone = $this->toneByPercent($percent);
|
||
// $fillCls = match($tone) {
|
||
// 'rose' => 'bg-rose-500/80',
|
||
// 'amber' => 'bg-amber-400/80',
|
||
// 'emerald'=> 'bg-emerald-500/80',
|
||
// default => 'bg-white/20',
|
||
// };
|
||
// return array_map(fn($i) => $i < $filled ? $fillCls : 'bg-white/10', range(0, $n-1));
|
||
// }
|
||
//
|
||
// protected function loadDotClass(?float $ratio): string {
|
||
// if ($ratio === null) return 'bg-white/25';
|
||
// if ($ratio >= 0.9) return 'bg-rose-500';
|
||
// if ($ratio >= 0.7) return 'bg-amber-400';
|
||
// return 'bg-emerald-400';
|
||
// }
|
||
//}
|