parent
adea3c5275
commit
d76ea0b703
|
|
@ -2,37 +2,169 @@
|
|||
|
||||
namespace App\Livewire\Ui\System;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
|
||||
class BackupStatusCard extends Component
|
||||
{
|
||||
public ?string $lastAt = null;
|
||||
public ?string $lastSize = null;
|
||||
public ?string $lastDuration = null;
|
||||
public ?string $lastAt = null; // formatierte Zeit
|
||||
public ?string $lastSize = null; // human readable
|
||||
public ?string $lastDuration = null; // human readable
|
||||
public ?bool $ok = null;
|
||||
|
||||
public function mount(): void { $this->load(); }
|
||||
public function render() { return view('livewire.ui.system.backup-status-card'); }
|
||||
public function refresh(): void { $this->load(true); }
|
||||
// Laufzeit/Progress
|
||||
public string $state = 'idle'; // idle|running|done|error
|
||||
public string $step = ''; // aktueller Schritt
|
||||
public array $steps = [
|
||||
'mysqldump' => 'Datenbank sichern',
|
||||
'maildir' => 'Maildir kopieren',
|
||||
'app' => 'App sichern',
|
||||
'configs' => 'Configs sichern',
|
||||
'archive' => 'Archiv erstellen',
|
||||
'compress' => 'Komprimieren',
|
||||
'retention' => 'Aufräumen',
|
||||
'finish' => 'Abschluss',
|
||||
];
|
||||
|
||||
protected string $statusFile = '/var/lib/mailwolt/backup.status';
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->load(true);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.ui.system.backup-status-card');
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->load(true);
|
||||
}
|
||||
|
||||
public function runNow(): void
|
||||
{
|
||||
@shell_exec('nohup /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &');
|
||||
$this->dispatch('toast', type:'info', title:'Backup gestartet');
|
||||
@shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &');
|
||||
// Sofort in "running" gehen – Poll übernimmt dann
|
||||
$this->state = 'running';
|
||||
$this->step = 'mysqldump';
|
||||
}
|
||||
|
||||
protected function load(bool $force=false): void
|
||||
public function load(bool $force = false): void
|
||||
{
|
||||
// Example: parse a tiny status file your backup script writes.
|
||||
$f = '/var/lib/mailwolt/backup.status';
|
||||
if (is_file($f)) {
|
||||
$lines = @file($f, FILE_IGNORE_NEW_LINES) ?: [];
|
||||
foreach ($lines as $ln) {
|
||||
if (str_starts_with($ln,'time=')) $this->lastAt = substr($ln,5);
|
||||
if (str_starts_with($ln,'size=')) $this->lastSize = substr($ln,5);
|
||||
if (str_starts_with($ln,'dur=')) $this->lastDuration = substr($ln,4);
|
||||
if (str_starts_with($ln,'ok=')) $this->ok = (substr($ln,3) === '1');
|
||||
}
|
||||
$raw = $this->readStatus();
|
||||
$this->state = $raw['state'] ?? 'idle';
|
||||
$this->step = $raw['step'] ?? '';
|
||||
|
||||
// Datum/Zeit hübsch
|
||||
if (!empty($raw['time'])) {
|
||||
$this->lastAt = $this->fmtTime($raw['time']);
|
||||
} else {
|
||||
$this->lastAt = null;
|
||||
}
|
||||
|
||||
// Größe/Dauer hübsch
|
||||
$bytes = isset($raw['size_bytes']) ? (int)$raw['size_bytes'] : null;
|
||||
$secs = isset($raw['dur_seconds']) ? (int)$raw['dur_seconds'] : null;
|
||||
|
||||
$this->lastSize = $bytes !== null ? $this->humanBytes($bytes) : null;
|
||||
$this->lastDuration = $secs !== null ? $this->humanDuration($secs) : null;
|
||||
$this->ok = isset($raw['ok']) ? ((string)$raw['ok'] === '1') : null;
|
||||
}
|
||||
|
||||
protected function readStatus(): array
|
||||
{
|
||||
if (!is_file($this->statusFile)) return [];
|
||||
$out = [];
|
||||
foreach (@file($this->statusFile, FILE_IGNORE_NEW_LINES) ?: [] as $ln) {
|
||||
if (!str_contains($ln, '=')) continue;
|
||||
[$k, $v] = array_map('trim', explode('=', $ln, 2));
|
||||
$out[$k] = $v;
|
||||
}
|
||||
|
||||
// Backward compatibility (alte Keys)
|
||||
if (isset($out['size']) && !isset($out['size_bytes'])) {
|
||||
$out['size_bytes'] = (int)$out['size'];
|
||||
}
|
||||
if (isset($out['dur']) && !isset($out['dur_seconds'])) {
|
||||
$out['dur_seconds'] = (int)$out['dur'];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
protected function fmtTime(string $iso): string
|
||||
{
|
||||
try {
|
||||
$tz = config('app.timezone', 'UTC');
|
||||
// ISO aus Script ist idealerweise UTC (Z)
|
||||
$dt = CarbonImmutable::parse($iso)->timezone($tz);
|
||||
// z.B. 27.10.2025, 16:48:02 (CET)
|
||||
return $dt->isoFormat('L, LTS') . ' ' . $dt->format('T');
|
||||
} catch (\Throwable) {
|
||||
return $iso;
|
||||
}
|
||||
}
|
||||
|
||||
protected function humanBytes(int $bytes): string
|
||||
{
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$i = 0;
|
||||
while ($bytes >= 1024 && $i < count($units) - 1) {
|
||||
$bytes /= 1024;
|
||||
$i++;
|
||||
}
|
||||
return number_format($bytes, $i === 0 ? 0 : 1, ',', '.') . ' ' . $units[$i];
|
||||
}
|
||||
|
||||
protected function humanDuration(int $secs): string
|
||||
{
|
||||
if ($secs < 60) return $secs . ' s';
|
||||
$m = intdiv($secs, 60);
|
||||
$s = $secs % 60;
|
||||
if ($m < 60) return sprintf('%d min %02d s', $m, $s);
|
||||
$h = intdiv($m, 60);
|
||||
$m = $m % 60;
|
||||
return sprintf('%d h %02d min', $h, $m);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//namespace App\Livewire\Ui\System;
|
||||
//
|
||||
//use Livewire\Component;
|
||||
//
|
||||
//class BackupStatusCard extends Component
|
||||
//{
|
||||
// public ?string $lastAt = null;
|
||||
// public ?string $lastSize = null;
|
||||
// public ?string $lastDuration = null;
|
||||
// public ?bool $ok = null;
|
||||
//
|
||||
// public function mount(): void { $this->load(); }
|
||||
// public function render() { return view('livewire.ui.system.backup-status-card'); }
|
||||
// public function refresh(): void { $this->load(true); }
|
||||
//
|
||||
// public function runNow(): void
|
||||
// {
|
||||
// @shell_exec('nohup sudo -n /usr/local/sbin/mailwolt-backup >/dev/null 2>&1 &');
|
||||
//// $this->dispatch('toast', type:'info', title:'Backup gestartet');
|
||||
// }
|
||||
//
|
||||
// protected function load(bool $force=false): void
|
||||
// {
|
||||
// // Example: parse a tiny status file your backup script writes.
|
||||
// $f = '/var/lib/mailwolt/backup.status';
|
||||
// if (is_file($f)) {
|
||||
// $lines = @file($f, FILE_IGNORE_NEW_LINES) ?: [];
|
||||
// foreach ($lines as $ln) {
|
||||
// if (str_starts_with($ln,'time=')) $this->lastAt = substr($ln,5);
|
||||
// if (str_starts_with($ln,'size=')) $this->lastSize = substr($ln,5);
|
||||
// if (str_starts_with($ln,'dur=')) $this->lastDuration = substr($ln,4);
|
||||
// if (str_starts_with($ln,'ok=')) $this->ok = (substr($ln,3) === '1');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ final class BuildMeta
|
|||
}
|
||||
|
||||
// 2) Fallback: .env APP_VERSION
|
||||
if ($m->version === 'dev' && ($envVer = env('APP_VERSION'))) {
|
||||
$m->version = trim($envVer);
|
||||
}
|
||||
// if ($m->version === 'dev' && ($envVer = env('APP_VERSION'))) {
|
||||
// $m->version = trim($envVer);
|
||||
// }
|
||||
|
||||
// 3) Fallback: Git (ohne "-dirty")
|
||||
if ($m->rev === '' || $m->version === 'dev') {
|
||||
|
|
|
|||
Loading…
Reference in New Issue