Log snapshot listing failures

This commit is contained in:
Mikei386
2026-07-10 13:01:16 +02:00
parent bf06b10519
commit 3f1b7cd781
10 changed files with 76 additions and 19 deletions
+2 -2
View File
@@ -14,7 +14,7 @@ $pluginRoot = '/plugins/urbm';
<header class="bu-header">
<div class="bu-brand">
<img class="bu-logo" src="<?= $pluginRoot ?>/images/urbm.png?v=20260710r004" alt="URBM-Logo">
<div><h1>URBM <span class="bu-version">2026.07.10.r004</span></h1><p>Restic Backup Manager für Unraid</p></div>
<div><h1>URBM <span class="bu-version">2026.07.10.r005</span></h1><p>Restic Backup Manager für Unraid</p></div>
</div>
<div id="bu-health" class="bu-health" tabindex="0" data-tooltip="Zeigt, ob die URBM-Hintergrundkomponente erreichbar ist. Beispiel: 'Daemon online' bedeutet, dass Jobs gestartet werden können.">Verbindung wird hergestellt...</div>
</header>
@@ -33,4 +33,4 @@ $pluginRoot = '/plugins/urbm';
<div id="bu-tooltip" role="tooltip" aria-hidden="true"></div>
</div>
<script>window.URBM_CSRF = <?= json_encode($var['csrf_token'] ?? '') ?>;</script>
<script src="<?= $pluginRoot ?>/assets/urbm-2026.07.10.r004.js"></script>
<script src="<?= $pluginRoot ?>/assets/urbm-2026.07.10.r005.js"></script>
+46 -10
View File
@@ -3,21 +3,37 @@ declare(strict_types=1);
header('Content-Type: application/json');
function urbm_bridge_log(string $level, string $message, array $context = []): void
{
$entry = array_merge([
'time' => gmdate('c'),
'level' => $level,
'component' => 'webgui',
'message' => $message,
], $context);
@file_put_contents('/var/log/urbm.log', json_encode($entry, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL, FILE_APPEND | LOCK_EX);
}
function urbm_json_error(int $status, string $message): void
{
http_response_code($status);
echo json_encode(['error' => $message], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
$socket = '/run/urbm/urbm.sock';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$path = $_GET['path'] ?? '/v1/health';
$isSnapshotFileRequest = preg_match('#/snapshots/[^/]+/files(?:\?|$)#', $path) === 1;
if (!preg_match('#^/v1/[A-Za-z0-9_./?=&%:-]*$#', $path) || str_contains($path, '..')) {
http_response_code(400);
echo json_encode(['error' => 'invalid API path']);
exit;
urbm_bridge_log('warn', 'invalid API path', ['path' => $path]);
urbm_json_error(400, 'invalid API path');
}
if (!file_exists($socket)) {
http_response_code(503);
echo json_encode(['error' => 'Der URBM-Daemon läuft nicht']);
exit;
urbm_bridge_log('warn', 'daemon socket missing', ['path' => $path, 'socket' => $socket]);
urbm_json_error(503, 'Der URBM-Daemon läuft nicht');
}
$curl = curl_init();
@@ -42,10 +58,30 @@ $error = curl_error($curl);
curl_close($curl);
if ($response === false) {
http_response_code(502);
echo json_encode(['error' => 'Verbindung zum URBM-Daemon fehlgeschlagen: ' . $error]);
exit;
$message = 'Verbindung zum URBM-Daemon fehlgeschlagen: ' . $error;
urbm_bridge_log('warn', 'daemon request failed', ['path' => $path, 'status' => 502, 'error' => $message]);
urbm_json_error(502, $message);
}
http_response_code($status > 0 ? $status : 502);
if ($status <= 0) {
$message = 'URBM-Daemon lieferte keine HTTP-Antwort';
urbm_bridge_log('warn', 'daemon response missing', ['path' => $path, 'status' => 502, 'error' => $message]);
urbm_json_error(502, $message);
}
if ($status >= 400) {
$decoded = json_decode((string)$response, true);
if (is_array($decoded) && isset($decoded['error']) && is_string($decoded['error'])) {
$message = $decoded['error'];
} else {
$message = trim((string)$response);
}
if ($message === '') {
$message = 'URBM-Daemon lieferte HTTP ' . $status . ' ohne Fehlertext';
}
urbm_bridge_log('warn', 'api request failed', ['path' => $path, 'status' => $status, 'error' => $message]);
urbm_json_error($status, $message);
}
http_response_code($status);
echo $response;
+1 -1
View File
@@ -822,7 +822,7 @@
if (name === 'maint') { await api(`/v1/repositories/${b}/${a}`,{method:'POST'}); notify(`${a==='check'?'Prüfung':'Bereinigung'} wurde eingereiht`); return load(); }
if (name === 'repo-snapshots') { state.view='snapshots'; document.querySelector('[data-view="snapshots"]').click(); render(); setTimeout(()=>{document.getElementById('bu-snapshot-repo').value=a; handle('load-snapshots');},0); return; }
if (name === 'load-snapshots') { const repo=document.getElementById('bu-snapshot-repo').value; state.snapshots=newestSnapshots(await api(`/v1/repositories/${repo}/snapshots`)); state.snapshotRepo=repo; return render(); }
if (name === 'browse') { state.selectedSnapshot=a; state.restoreIncludes=[]; state.files=[]; state.snapshotTree=null; state.snapshotTreeError=''; state.snapshotTreeExpanded={'/':true}; state.snapshotTreeLoading=true; render(); try { state.files=await api(`/v1/repositories/${state.snapshotRepo}/snapshots/${a}/files`); state.snapshotTree=buildSnapshotTree(state.files); } catch(error) { state.snapshotTreeError=`Snapshot-Struktur konnte nicht geladen werden: ${error.message}`; } finally { state.snapshotTreeLoading=false; return render(); } }
if (name === 'browse') { state.selectedSnapshot=a; state.restoreIncludes=[]; state.files=[]; state.snapshotTree=null; state.snapshotTreeError=''; state.snapshotTreeExpanded={'/':true}; state.snapshotTreeLoading=true; render(); try { state.files=await api(`/v1/repositories/${state.snapshotRepo}/snapshots/${a}/files`); state.snapshotTree=buildSnapshotTree(state.files); } catch(error) { state.snapshotTreeError=`Snapshot-Struktur konnte nicht geladen werden: ${error.message}. Details stehen im Tab Protokolle.`; } finally { state.snapshotTreeLoading=false; return render(); } }
if (name === 'toggle-source-tree') { return toggleSourceTree(decodeURIComponent(a)); }
if (name === 'retry-source-tree') { const path=decodeURIComponent(a); delete state.sourceTreeChildren[path]; state.sourceTreeErrors[path]=''; return toggleSourceTree(path,true); }
if (name === 'toggle-dir-tree') { return toggleDirectoryTree(a, decodeURIComponent(b)); }