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

907 lines
30 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\Artisan;
use Illuminate\Support\Facades\Cache;
use Livewire\Component;
class UpdateCard extends Component
{
/** Rohwerte (so wie gelesen/aus Cache) */
public ?string $current = null; // z.B. "v1.0.20" oder "1.0.20"
public ?string $latest = null; // z.B. "1.0.20" oder "v1.0.20"
/** Anzeige (immer mit v-Präfix) */
public ?string $displayCurrent = null; // z.B. "v1.0.20"
public ?string $displayLatest = null; // nur gesetzt, wenn wirklich neuer
/** Status/UX */
public bool $hasUpdate = false;
public string $state = 'idle'; // idle|running
public ?string $message = null;
public ?bool $messagePositive = null;
/** low-level / Wrapper */
public bool $running = false;
public ?int $rc = null;
/** intern */
protected string $cacheStartedAtKey = 'mw.update.started_at';
protected int $failsafeSeconds = 20 * 60; // 20 Min
public function mount(): void
{
$this->current = $this->readCurrentVersion();
$this->latest = Cache::get('mailwolt.update_available');
$this->refreshLowLevelState();
$this->recompute(); // setzt hasUpdate + display* + ggf. message
if ($this->running) $this->state = 'running';
}
public function render()
{
return view('livewire.ui.system.update-card');
}
/* =================== Aktionen =================== */
public function refreshState(): void
{
$this->state = 'running';
$this->message = 'Prüfe auf Updates …';
$this->messagePositive = null;
try {
Artisan::call('mailwolt:check-updates');
} catch (\Throwable $e) {
// weich fallen
}
$this->reloadVersionsAndStatus();
$this->recompute();
$this->finishUiIfNoUpdate(); // beendet progress, wenn nichts mehr offen ist
}
public function runUpdate(): void
{
// Hinweis sofort entfernen (Badge weg)
Cache::forget('mailwolt.update_available');
Cache::put($this->cacheStartedAtKey, time(), now()->addHour());
// Wrapper asynchron starten
@shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
// UI-Status
$this->latest = null;
$this->displayLatest = null;
$this->hasUpdate = false;
$this->state = 'running';
$this->running = true;
$this->message = 'Update läuft …';
$this->messagePositive = null;
}
/** Wird nur gepollt, solange $state==='running' (wire:poll) */
public function tick(): void
{
$this->refreshLowLevelState();
// Failsafe
$started = (int)Cache::get($this->cacheStartedAtKey, 0);
if ($this->running && $started > 0 && (time() - $started) > $this->failsafeSeconds) {
$this->running = false;
}
if (!$this->running) {
Cache::forget($this->cacheStartedAtKey);
$this->reloadVersionsAndStatus();
$this->recompute();
$this->finishUiIfNoUpdate();
}
}
/* =================== Helpers =================== */
protected function reloadVersionsAndStatus(): void
{
$this->current = $this->readCurrentVersion();
$this->latest = Cache::get('mailwolt.update_available');
$this->refreshLowLevelState();
}
protected function finishUiIfNoUpdate(): void
{
if (!$this->hasUpdate) {
$this->state = 'idle';
$cur = $this->displayCurrent ?? '';
// <<< Klammern-Fix: erst coalescen, dann in den String einsetzen
$this->message = "Du bist auf dem neuesten Stand ({$cur})";
$this->messagePositive = true;
// zur Sicherheit: Cache leeren
Cache::forget('mailwolt.update_available');
}
}
protected function recompute(): void
{
$curNorm = $this->normalizeVersion($this->current);
$latNorm = $this->normalizeVersion($this->latest);
$this->hasUpdate = ($curNorm && $latNorm)
? version_compare($latNorm, $curNorm, '>')
: false;
// Anzeige immer mit v-Präfix
$this->displayCurrent = $curNorm ? 'v' . $curNorm : null;
$this->displayLatest = ($this->hasUpdate && $latNorm) ? 'v' . $latNorm : null;
// Initiale Message (nur wenn noch nicht gesetzt)
if ($this->message === null) {
if ($this->hasUpdate) {
$this->message = "Neue Version verfügbar: {$this->displayLatest}";
$this->messagePositive = false;
} else {
$cur = $this->displayCurrent ?? '';
$this->message = "Du bist auf dem neuesten Stand ({$cur})";
$this->messagePositive = true;
}
}
}
protected function refreshLowLevelState(): void
{
$state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
$this->running = ($state === 'running');
$rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
$this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
}
protected function readCurrentVersion(): ?string
{
// bevorzugt build.info
$build = @file_get_contents('/etc/mailwolt/build.info');
if ($build) {
foreach (preg_split('/\R+/', $build) as $line) {
if (str_starts_with($line, 'version=')) {
$v = trim(substr($line, 8));
return $v !== '' ? $v : null;
}
}
}
$v = config('app.version');
return $v !== '' ? $v : null;
}
protected function normalizeVersion(?string $v): ?string
{
if ($v === null) return null;
$v = trim($v);
// führendes v/V + whitespace entfernen
$v = ltrim($v, "vV \t\n\r\0\x0B");
return $v === '' ? null : $v;
}
}
//namespace App\Livewire\Ui\System;
//
//use Illuminate\Support\Facades\Artisan;
//use Illuminate\Support\Facades\Cache;
//use Livewire\Component;
//
//class UpdateCard extends Component
//{
// public ?string $current = null; // installierte Version
// public ?string $latest = null; // verfügbare Version (oder null)
// public string $state = 'idle'; // idle | running
//
// public ?string $message = null;
// public ?bool $messagePositive = null;
//
// // low-level
// public bool $running = false;
// public ?int $rc = null;
//
// // intern
// protected string $cacheStartedAtKey = 'mw.update.started_at';
// protected int $failsafeSeconds = 20 * 60; // 20 Min
//
// public function mount(): void
// {
// $this->current = $this->readCurrentVersion();
// $this->latest = Cache::get('mailwolt.update_available');
// $this->refreshLowLevelState();
//
// // initiale Message
// if ($this->message === null) {
// if ($this->getHasUpdateProperty()) {
// $this->message = "Neue Version verfügbar: {$this->latest}";
// $this->messagePositive = false;
// } else {
// $cur = $this->current ?: '';
// $this->message = "Du bist auf dem neuesten Stand ({$cur})";
// $this->messagePositive = true;
// }
// }
//
// // falls der Wrapper gerade läuft → visuell „running“
// if ($this->running) {
// $this->state = 'running';
// }
// }
//
// public function render()
// {
// return view('livewire.ui.system.update-card');
// }
//
// /* =================== Aktionen =================== */
//
// public function refreshState(): void
// {
// $this->state = 'running';
// $this->message = 'Prüfe auf Updates …';
// $this->messagePositive = null;
//
// try {
// Artisan::call('mailwolt:check-updates');
// } catch (\Throwable $e) {
// // weich fallen
// }
//
// $this->reloadVersionsAndStatus();
// $this->finishUiIfNoUpdate();
// }
//
// public function runUpdate(): void
// {
// // Badge „Update verfügbar“ sofort ausblenden
// Cache::forget('mailwolt.update_available');
//
// // Startzeit merken (Failsafe)
// Cache::put($this->cacheStartedAtKey, time(), now()->addHours(1));
//
// // Wrapper asynchron starten
// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
//
// $this->latest = null;
// $this->state = 'running';
// $this->running = true;
// $this->message = 'Update läuft …';
// $this->messagePositive = null;
// }
//
// /**
// * Wird vom Blade nur während running gepollt (wire:poll="tick").
// * Bricht den Fortschritt ab, sobald der Wrapper „done“ meldet ODER
// * der Failsafe greift. Lädt danach Versionen & Badge neu.
// */
// public function tick(): void
// {
// $this->refreshLowLevelState();
//
// // Failsafe: nach N Minuten Fortschritt aus
// $started = (int)Cache::get($this->cacheStartedAtKey, 0);
// if ($this->running && $started > 0 && (time() - $started) > $this->failsafeSeconds) {
// $this->running = false;
// }
//
// if (!$this->running) {
// // abgeschlossen → Startmarke löschen
// Cache::forget($this->cacheStartedAtKey);
//
// // Versionen/Caches neu laden
// $this->reloadVersionsAndStatus();
//
// // wenn erfolgreich (rc=0) und keine neue Version mehr → Done
// $this->finishUiIfNoUpdate();
// }
// // wenn weiterhin running: nichts tun, UI zeigt Progress weiter
// }
//
// /* =================== Computed =================== */
//
// // Blade nutzt $this->hasUpdate
// public function getHasUpdateProperty(): bool
// {
// $cur = $this->normalizeVersion($this->current ?? null);
// $lat = $this->normalizeVersion($this->latest ?? null);
// if ($lat === null || $cur === null) return false;
// return version_compare($lat, $cur, '>');
// }
//
// /* =================== Helpers =================== */
//
// protected function reloadVersionsAndStatus(): void
// {
// $this->current = $this->readCurrentVersion();
// $this->latest = Cache::get('mailwolt.update_available');
// $this->refreshLowLevelState();
// }
//
// protected function finishUiIfNoUpdate(): void
// {
// if (!$this->getHasUpdateProperty()) {
// // alles aktuell → Fortschritt aus, Badge „Aktuell“, Hinweistext grün
// $this->state = 'idle';
// $this->message = "Du bist auf dem neuesten Stand (" . $this->current ?? '' . ")";
// $this->messagePositive = true;
//
// // zur Sicherheit Badge-Cache entfernen
// Cache::forget('mailwolt.update_available');
// }
// }
//
// protected function refreshLowLevelState(): void
// {
// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
// $this->running = ($state === 'running');
//
// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
// }
//
// protected function readCurrentVersion(): ?string
// {
// $build = @file_get_contents('/etc/mailwolt/build.info');
// if ($build) {
// foreach (preg_split('/\R+/', $build) as $line) {
// if (str_starts_with($line, 'version=')) {
// $v = trim(substr($line, 8));
// if ($v !== '') return $v;
// }
// }
// }
// $v = config('app.version');
// return $v !== '' ? $v : null;
// }
//
// protected function normalizeVersion(?string $v): ?string
// {
// if ($v === null) return null;
// $v = trim($v);
// $v = ltrim($v, 'v'); // führt "v1.0.19" und "1.0.19" zusammen
// return $v === '' ? null : $v;
// }
//}
//namespace App\Livewire\Ui\System;
//
//use Illuminate\Support\Facades\Artisan;
//use Illuminate\Support\Facades\Cache;
//use Livewire\Component;
//
//class UpdateCard extends Component
//{
// public ?string $current = null; // installed (pretty)
// public ?string $latest = null; // available (pretty or null)
// public string $state = 'idle'; // idle|running
//
// public ?string $message = null; // inline message
// public ?bool $messagePositive = null;
//
// // low-level
// public bool $running = false;
// public ?int $rc = null;
//
// // ---- lifecycle ---------------------------------------------------------
//
// public function mount(): void
// {
// $this->readLowLevel();
// $this->current = $this->readCurrentVersion();
// $this->latest = $this->readCachedLatest();
//
// if ($this->message === null) {
// if ($this->hasUpdate()) {
// $this->message = "Neue Version verfügbar: {$this->latest}";
// $this->messagePositive = false;
// } else {
// $cur = $this->current ?? '';
// $this->message = "Du bist auf dem neuesten Stand ({$cur})";
// $this->messagePositive = true;
// }
// }
//
// // if wrapper is already running when page loads, reflect that
// if ($this->running) {
// $this->state = 'running';
// }
// }
//
// public function render()
// {
// return view('livewire.ui.system.update-card');
// }
//
// // ---- UI actions --------------------------------------------------------
//
// /** Button: „Erneut prüfen“ (no toast; shows inline progress) */
// public function refreshState(): void
// {
// $this->state = 'running';
// $this->message = 'Prüfe auf Updates …';
// $this->messagePositive = null;
//
// try {
// // your checker should update the cache key below
// Artisan::call('mailwolt:check-updates');
// } catch (\Throwable $e) {
// // swallow but still continue to show something meaningful
// }
//
// $this->current = $this->readCurrentVersion();
// $this->latest = $this->readCachedLatest();
// $this->readLowLevel();
//
// if ($this->hasUpdate()) {
// $this->message = "Neue Version verfügbar: {$this->latest}";
// $this->messagePositive = false;
// } else {
// $this->message = "Du bist auf dem neuesten Stand ($this->current ?? '')";
// $this->messagePositive = true;
// }
//
// $this->state = 'idle';
// }
//
// /** Button: „Jetzt aktualisieren“ (no toast; start wrapper + progress) */
// public function runUpdate(): void
// {
// // Hide the yellow badges immediately
// Cache::forget('mailwolt.update_available');
//
// // spawn wrapper in the background
// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
//
// // reflect “running” in UI
// $this->latest = null;
// $this->state = 'running';
// $this->running = true;
// $this->message = 'Update läuft …';
// $this->messagePositive = null;
// }
//
// /**
// * Called from the blade with `wire:poll.1200ms="tick"` but **only**
// * when $state === 'running'. This finishes the UX once the wrapper ends.
// */
// public function tick(): void
// {
// if ($this->state !== 'running') return;
//
// $this->readLowLevel();
//
// if (!$this->running) { // wrapper finished
// // give build.info a split second to land on slow disks
// usleep(150000);
//
// $this->current = $this->readCurrentVersion();
// $this->latest = $this->readCachedLatest();
//
// if ($this->rc === 0) {
// // success path
// if ($this->hasUpdate()) {
// // very unlikely right after success, but handle anyway
// $this->message = "Neue Version verfügbar: {$this->latest}";
// $this->messagePositive = false;
// } else {
// $this->message = "Update erfolgreich jetzt: {$this->current}";
// $this->messagePositive = true;
// }
// } else {
// // failure path
// $rc = $this->rc ?? 1;
// $this->message = "Update fehlgeschlagen (rc={$rc})";
// $this->messagePositive = false;
// }
//
// $this->state = 'idle';
// }
// }
//
// // ---- helpers -----------------------------------------------------------
//
// public function getHasUpdateProperty(): bool
// {
// // gleiche Logik wie in deiner Klasse:
// $cur = $this->normalizeVersion($this->current ?? null);
// $lat = $this->normalizeVersion($this->latest ?? null);
// if ($lat === null || $cur === null) return false;
// return version_compare($lat, $cur, '>');
// }
//
// protected function hasUpdate(): bool
// {
// $cur = $this->normalizeVersion($this->current);
// $lat = $this->normalizeVersion($this->latest);
//
// if ($lat === null || $cur === null) return false;
// return version_compare($lat, $cur, '>');
// }
//
// protected function readLowLevel(): void
// {
// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
// $this->running = ($state === 'running');
//
// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
// }
//
// protected function readCurrentVersion(): ?string
// {
// // Prefer the installer/updater stamp
// $build = @file_get_contents('/etc/mailwolt/build.info');
// if ($build) {
// foreach (preg_split('/\R+/', $build) as $line) {
// if (str_starts_with($line, 'version=')) {
// $v = trim(substr($line, 8));
// if ($v !== '') return $this->prettyVersion($v);
// }
// }
// }
// $v = trim((string)config('app.version', ''));
// return $v !== '' ? $this->prettyVersion($v) : null;
// }
//
// protected function readCachedLatest(): ?string
// {
// $v = Cache::get('mailwolt.update_available');
// if (!is_string($v) || $v === '') return null;
// return $this->prettyVersion($v);
// }
//
// /**
// * Return a “compare-safe” semver string: e.g. `v1.0.18` → `1.0.18`.
// * Accepts tags like `release-1.0.18` too.
// */
// protected function normalizeVersion(?string $v): ?string
// {
// if (!$v) return null;
// // keep only the first x.y.z like portion
// if (preg_match('/(\d+\.\d+\.\d+)/', $v, $m)) {
// return $m[1];
// }
// // fallback: bare digits (x.y)
// if (preg_match('/(\d+\.\d+)/', $v, $m)) {
// return $m[1];
// }
// return null;
// }
//
// /** Always render with a single leading `v` (no “vv…”) */
// protected function prettyVersion(string $v): string
// {
// $n = $this->normalizeVersion($v);
// return $n ? 'v' . $n : $v;
// }
//}
//namespace App\Livewire\Ui\System;
//
//use Livewire\Component;
//use Illuminate\Support\Facades\Artisan;
//use Illuminate\Support\Facades\Cache;
//
//class UpdateCard extends Component
//{
// public ?string $current = null; // installierte Version
// public ?string $latest = null; // verfügbare Version (oder null)
// public string $state = 'idle'; // idle | running
//
// // UI-Textausgabe nach einer Prüfung / Aktion
// public ?string $message = null; // z.B. "Du bist auf dem neuesten Stand (v1.0.16)"
// public ?bool $messagePositive = null; // true = grün, false = neutral/weiß
//
// // low-level (falls du sie später brauchst)
// public bool $running = false; // aus /var/lib/mailwolt/update/state
// public ?int $rc = null;
//
// public function mount(): void
// {
// $this->current = $this->readCurrentVersion();
// $this->latest = Cache::get('mailwolt.update_available');
// $this->refreshLowLevelState();
//
// // Starttext, falls nichts geprüft wurde
// if ($this->message === null) {
// $this->message = $this->latest && $this->hasUpdate()
// ? "Neue Version verfügbar: {$this->latest}"
// : ($this->current ? "Du bist auf dem neuesten Stand ({$this->current})" : "Status unbekannt");
// $this->messagePositive = !$this->hasUpdate();
// }
// }
//
// public function render()
// {
// return view('livewire.ui.system.update-card');
// }
//
// /**
// * „Erneut prüfen“ ohne Toast:
// * - Progress anzeigen
// * - Check-Command laufen lassen
// * - Message in der Box aktualisieren
// */
// public function refreshState(): void
// {
// $this->state = 'running';
// $this->message = 'Prüfe auf Updates …';
// $this->messagePositive = null;
//
// try {
// // Passe den Namen hier an dein tatsächliches Command an:
// Artisan::call('mailwolt:check-updates');
// } catch (\Throwable $e) {
// // weich fallen
// }
//
// // Daten neu einlesen
// $this->current = $this->readCurrentVersion();
// $this->latest = Cache::get('mailwolt.update_available');
//
// if ($this->hasUpdate()) {
// $this->message = "Neue Version verfügbar: {$this->latest}";
// $this->messagePositive = false; // neutral
// } else {
// $cur = $this->current ?: '';
// $this->message = "Du bist auf dem neuesten Stand ({$cur})";
// $this->messagePositive = true; // grün
// }
//
// $this->refreshLowLevelState();
// $this->state = 'idle';
// }
//
// /**
// * „Jetzt aktualisieren“ ohne Toast:
// * - Hinweis sofort aus Cache entfernen (Badge weg)
// * - Update-Wrapper starten
// * - Running + Text in der Box anzeigen
// */
// public function runUpdate(): void
// {
// Cache::forget('mailwolt.update_available');
//
// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
//
// $this->latest = null;
// $this->state = 'running';
// $this->running = true;
// $this->message = 'Update läuft …';
// $this->messagePositive = null;
// }
//
// /** --------------------- helpers --------------------- */
//
// protected function hasUpdate(): bool
// {
// if (!$this->latest) return false;
// $cur = $this->current ?: '0.0.0';
// return version_compare($this->latest, $cur, '>');
// }
//
// protected function refreshLowLevelState(): void
// {
// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
// $this->running = ($state === 'running');
//
// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
// }
//
// protected function readCurrentVersion(): ?string
// {
// // bevorzugt /etc/mailwolt/build.info (wird im Installer/Updater gepflegt)
// $build = @file_get_contents('/etc/mailwolt/build.info');
// if ($build) {
// foreach (preg_split('/\R+/', $build) as $line) {
// if (str_starts_with($line, 'version=')) {
// $v = trim(substr($line, 8));
// if ($v !== '') return $v;
// }
// }
// }
// $v = config('app.version');
// return $v !== '' ? $v : null;
// }
//}
//
//
//namespace App\Livewire\Ui\System;
//
//use Livewire\Component;
//use Illuminate\Support\Facades\Artisan;
//use Illuminate\Support\Facades\Cache;
//
//class UpdateCard extends Component
//{
// public ?string $current = null; // z.B. v1.0.16 (aktuell installiert)
// public ?string $latest = null; // z.B. v1.0.17 (verfügbar) oder null
// public string $state = 'idle'; // idle | running
//
// // optional: Low-level-Infos, falls du sie irgendwo anders brauchst
// public bool $running = false; // Wrapper-/Updater läuft gerade (aus State-Datei)
// public string $log = '';
// public ?int $rc = null;
//
// public function mount(): void
// {
// $this->current = $this->readCurrentVersion();
// $this->latest = Cache::get('mailwolt.update_available');
// $this->refreshLowLevelState(); // liest /var/lib/mailwolt/update/*
// }
//
// public function render()
// {
// return view('livewire.ui.system.update-card');
// }
//
// /**
// * „Erneut prüfen“:
// * - zeigt Running-Progress
// * - ruft den Checker (dein bestehendes Artisan-Command)
// * - aktualisiert $latest / $current
// * - dispatcht passenden Toast
// */
// public function refreshState(): void
// {
// $this->state = 'running';
//
// // Falls vorhanden: dein Command, der cache('mailwolt.update_available') setzt
// // -> Namen ggf. anpassen (du hattest z.B. mailwolt:check-updates erwähnt)
// try {
// Artisan::call('mailwolt:check-updates');
// } catch (\Throwable $e) {
// // Wenn das Command (noch) nicht existiert, nicht crashen state einfach zurücksetzen
// }
//
// // App-Status neu einlesen
// $this->current = $this->readCurrentVersion();
// $this->latest = Cache::get('mailwolt.update_available');
//
// $hasUpdate = $this->hasUpdate();
//
// // Toast ausspielen
// $this->dispatch('toast',
// type: $hasUpdate ? 'info' : 'done',
// badge: 'Update',
// title: $hasUpdate ? 'Neue Version verfügbar' : 'Alles aktuell',
// text: $hasUpdate
// ? "Verfügbar: {$this->latest} installiert: {$this->current}"
// : "Du bist auf dem neuesten Stand ({$this->current}).",
// duration: 6000
// );
//
// // Low-level-State (optional) und UI-State zurücksetzen
// $this->refreshLowLevelState();
// $this->state = 'idle';
// }
//
// /**
// * „Jetzt aktualisieren“:
// * - blendet die verfügbare-Version sofort aus
// * - startet den Root-Wrapper im Hintergrund
// * - zeigt einen Toast „Update gestartet“
// */
// public function runUpdate(): void
// {
// Cache::forget('mailwolt.update_available'); // Badge sofort weg
// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
//
// $this->state = 'running';
// $this->running = true;
//
// $this->dispatch('toast',
// type: 'info',
// badge: 'Update',
// title: 'Update gestartet',
// text: 'Das System wird aktualisiert …',
// duration: 6000
// );
// }
//
// /** ---- Helpers ------------------------------------------------------- */
//
// protected function hasUpdate(): bool
// {
// if (!$this->latest) return false;
// $cur = $this->current ?: '0.0.0';
// return version_compare($this->latest, $cur, '>');
// }
//
// protected function refreshLowLevelState(): void
// {
// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
// $this->running = ($state === 'running');
//
// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
//
// // Log bewusst NICHT angezeigt, aber verfügbar, falls du es später brauchst
// $this->log = @shell_exec('tail -n 200 /var/log/mailwolt-update.log 2>/dev/null') ?? '';
// }
//
// protected function readCurrentVersion(): ?string
// {
// // bevorzugt build.info, sonst config('app.version')
// $build = @file_get_contents('/etc/mailwolt/build.info');
// if ($build) {
// foreach (preg_split('/\R+/', $build) as $line) {
// if (str_starts_with($line, 'version=')) {
// $v = trim(substr($line, 8));
// if ($v !== '') return $v;
// }
// }
// }
// $v = config('app.version');
// return $v !== '' ? $v : null;
// }
//}
////
////namespace App\Livewire\Ui\System;
////
////use Livewire\Component;
////use Illuminate\Support\Facades\Artisan;
////use Illuminate\Support\Facades\Cache;
////
////class UpdateCard extends Component
////{
//// public ?string $current = null;
//// public ?string $latest = null;
//// public string $state = 'idle'; // idle|running
////
//// public bool $running = false;
//// public string $log = '';
//// public ?int $rc = null;
////
//// public function mount(): void
//// {
////// $this->refreshState();
//// $this->latest = cache('mailwolt.update_available');
////
//// }
////
//// public function render()
//// {
//// return view('livewire.ui.system.update-card');
//// }
////
//// public function refreshState(): void
//// {
//// $state = @trim(@file_get_contents('/var/lib/mailwolt/update/state') ?: '');
//// $this->running = ($state === 'running');
////
//// $rcRaw = @trim(@file_get_contents('/var/lib/mailwolt/update/rc') ?: '');
//// $this->rc = is_numeric($rcRaw) ? (int)$rcRaw : null;
////
//// // letzte 200 Zeilen Log
//// $this->log = @shell_exec('tail -n 200 /var/log/mailwolt-update.log 2>/dev/null') ?? '';
//// }
////
//// public function runUpdate(): void
//// {
//// // Hinweis „Update verfügbar“ ausblenden
//// cache()->forget('mailwolt.update_available');
////
//// // Update im Hintergrund starten
//// @shell_exec('nohup sudo -n /usr/local/sbin/mw-update >/dev/null 2>&1 &');
////
//// $this->running = true;
//// $this->dispatch('toast',
//// type: 'info',
//// badge: 'Update',
//// title: 'Update gestartet',
//// text: 'Das System wird aktualisiert …',
//// duration: 6000
//// );
//// }
////}