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

537 lines
18 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
{
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
//// );
//// }
////}