mailwolt/app/Livewire/Ui/System/ServicesCard.php

305 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Livewire\Ui\System;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
class ServicesCard extends Component
{
public array $servicesCompact = [];
/** Pro Karte mehrere Quellen grün sobald eine Quelle OK ist */
protected array $cards = [
// Mail
'postfix' => [
'label' => 'Postfix', 'hint' => 'MTA / Versand',
'sources' => ['systemd:postfix'],
],
'dovecot' => [
'label' => 'Dovecot', 'hint' => 'IMAP / POP3',
'sources' => ['systemd:dovecot', 'tcp:127.0.0.1:993'],
],
'rspamd' => [
'label' => 'Rspamd', 'hint' => 'Spamfilter',
'sources' => ['systemd:rspamd', 'tcp:127.0.0.1:11333', 'tcp:127.0.0.1:11334'],
],
'clamav' => [
'label' => 'ClamAV', 'hint' => 'Virenscanner',
// mehrere mögliche Units + Socket/PID + TCP
'sources' => [
'systemd:clamav-daemon',
'systemd:clamav-daemon@scan',
'systemd:clamd',
'socket:/run/clamav/clamd.ctl',
'pid:/run/clamav/clamd.pid',
'tcp:127.0.0.1:3310',
],
],
// Daten & Cache
'db' => [
'label' => 'Datenbank', 'hint' => 'MySQL / MariaDB',
'sources' => ['db'],
],
'redis' => [
'label' => 'Redis', 'hint' => 'Cache / Queue',
'sources' => ['tcp:127.0.0.1:6379', 'systemd:redis-server', 'systemd:redis'],
],
// Web / PHP
'php-fpm' => [
'label' => 'PHP-FPM', 'hint' => 'PHP Runtime',
'sources' => [
'systemd:php8.3-fpm', 'systemd:php8.2-fpm', 'systemd:php8.1-fpm', 'systemd:php-fpm',
'socket:/run/php/php8.3-fpm.sock', 'socket:/run/php/php8.2-fpm.sock',
'socket:/run/php/php8.1-fpm.sock', 'socket:/run/php/php-fpm.sock',
'tcp:127.0.0.1:9000',
],
],
'nginx' => [
'label' => 'Nginx', 'hint' => 'Webserver',
'sources' => ['systemd:nginx', 'tcp:127.0.0.1:80'],
],
// MailWolt (Units ODER laufende artisan-Prozesse)
'mw-queue' => [
'label' => 'MailWolt Queue', 'hint' => 'Job Worker',
'sources' => [
'systemd:mailwolt-queue',
'proc:/php.*artisan(\.php)?\s+queue:work',
],
],
'mw-schedule' => [
'label' => 'MailWolt Schedule', 'hint' => 'Task Scheduler',
'sources' => [
'systemd:mailwolt-schedule',
'proc:/php.*artisan(\.php)?\s+schedule:work',
],
],
'mw-ws' => [
'label' => 'MailWolt WebSocket', 'hint' => 'Echtzeit Updates',
'sources' => ['systemd:mailwolt-ws', 'tcp:127.0.0.1:8080'],
],
// Sonstiges
'fail2ban' => [
'label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection',
'sources' => ['systemd:fail2ban'],
],
'journal' => [
'label' => 'System Logs', 'hint' => 'Journal',
'sources' => ['systemd:systemd-journald', 'systemd:rsyslog'],
],
];
public function mount(): void
{
$this->load();
}
public function refresh(): void
{
Cache::forget('health:services.v2');
$this->load();
}
public function load(): void
{
$data = Cache::remember('health:services.v2', 15, function () {
$out = [];
foreach ($this->cards as $key => $card) {
$ok = false;
foreach ($card['sources'] as $src) {
if ($this->check($src)) {
$ok = true;
break;
}
}
$out[$key] = ['label' => $card['label'], 'hint' => $card['hint'], 'ok' => $ok];
}
return $out;
});
$this->servicesCompact = collect($data)->map(function ($row) {
$ok = (bool)$row['ok'];
return [
'label' => $row['label'],
'hint' => $row['hint'],
'ok' => $ok,
'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
'pillText' => $ok ? 'Online' : 'Offline',
'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();
}
public function render()
{
return view('livewire.ui.system.services-card');
}
// ───────────── Probes ─────────────
protected function check(string $source): bool
{
if (str_starts_with($source, 'systemd:')) {
return $this->probeSystemd(substr($source, 8));
}
if (str_starts_with($source, 'tcp:')) {
[$host, $port] = explode(':', substr($source, 4), 2);
return $this->probeTcp($host, (int)$port);
}
if (str_starts_with($source, 'socket:')) {
$path = substr($source, 7);
return is_string($path) && @file_exists($path);
}
if (str_starts_with($source, 'pid:')) {
$path = substr($source, 4);
if (!@is_file($path)) return false;
$pid = (int)trim(@file_get_contents($path) ?: '');
return $pid > 1 && @posix_kill($pid, 0);
}
if (str_starts_with($source, 'proc:')) {
$regex = substr($source, 5);
return $this->probeProcessRegex($regex);
}
if ($source === 'db') {
return $this->probeDatabase();
}
return false;
}
protected function probeSystemd(string $unit): bool
{
// versuche /bin und /usr/bin
$bin = file_exists('/bin/systemctl') ? '/bin/systemctl'
: (file_exists('/usr/bin/systemctl') ? '/usr/bin/systemctl' : 'systemctl');
$cmd = sprintf('%s is-active --quiet %s 2>/dev/null', escapeshellcmd($bin), escapeshellarg($unit));
$exit = null;
@exec($cmd, $_, $exit);
return $exit === 0;
}
protected function probeTcp(string $host, int $port, int $timeout = 1): bool
{
$fp = @fsockopen($host, $port, $e1, $e2, $timeout);
if (is_resource($fp)) {
fclose($fp);
return true;
}
return false;
// Alternative: stream_socket_client("tcp://$host:$port", …)
}
protected function probeProcessRegex(string $regex): bool
{
// /proc durchsuchen leichtgewichtig und ohne ps-Depend
$regex = '#' . $regex . '#i';
foreach (@scandir('/proc') ?: [] as $d) {
if (!ctype_digit($d)) continue;
$cmd = @file_get_contents("/proc/$d/cmdline");
if ($cmd === false || $cmd === '') continue;
$cmd = str_replace("\0", ' ', $cmd);
if (preg_match($regex, $cmd)) return true;
}
return false;
}
protected function probeDatabase(): bool
{
try {
DB::connection()->getPdo();
return true;
} catch (\Throwable) {
return false;
}
}
}
//
//namespace App\Livewire\Ui\System;
//
//use Carbon\Carbon;
//use Illuminate\Support\Facades\Cache;
//use Livewire\Component;
//
//class ServicesCard extends Component
//{
// public array $services = [];
// public array $servicesCompact = [];
//
// // Mapping für schöne Labels/Hints
// protected array $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
// 'mailwolt-queue' => ['label' => 'MailWolt Queue', 'hint' => 'Job Worker'],
// 'mailwolt-schedule'=> ['label' => 'MailWolt Schedule', 'hint' => 'Task Scheduler'],
// 'mailwolt-ws' => ['label' => 'MailWolt WebSocket','hint' => 'Echtzeit Updates'],
//
// // Sonstiges
// 'fail2ban' => ['label' => 'Fail2Ban', 'hint' => 'SSH / Mail Protection'],
// 'systemd-journald'=> ['label' => 'System Logs', 'hint' => 'Journal'],
// 'rsyslog' => ['label' => 'Rsyslog', 'hint' => 'Logging'],
//
// // WebSocket/TCP
// '127.0.0.1:8080' => ['label' => 'Reverb', 'hint' => 'WebSocket Server'],
// ];
//
// public function mount(): void
// {
// $this->load();
// }
//
// public function load(): void
// {
// $this->services = Cache::get('health:services', []);
// $meta = Cache::get('health:meta', []);
// $updated = $meta['updated_at'] ?? null;
//
// $existing = collect($this->services)->keyBy('name');
//
// $this->servicesCompact = collect($this->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,
// 'dotClass' => $ok ? 'bg-emerald-400' : 'bg-rose-400',
// 'pillText' => $ok ? 'Aktiv' : 'Offline',
// '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();
// }
//
// public function render()
// {
// return view('livewire.ui.system.services-card');
// }
//}