Monitor layout (8-col grid): - Row 1: System | Power | CPU | Memory | Network - Row 2: Scripts | Partner & Fallback (span 3) | Containers & VMs (span 4) - Row 3: GPU (span 2) | Transcode (span 2) | Streams (span 4) - Row 4: Parity (cols 1-2) | Pools (cols 3-4) | Array (cols 5-8) New Containers & VMs card: - Reads FolderView3 folders from docker.json; expand/collapse per folder - VMs listed first (virsh); containers show start/stop/webui/edit actions - 2-column balanced layout; collapses to 1 column below 900px - Docker WebUI URLs resolved from dockerMan template XMLs New files: include/vms.php, include/docker_folders.php, api/docker_action.php, api/snapshot.php Responsive: explicit grid-column placements reset at 1024px breakpoint
73 lines
2.8 KiB
PHP
73 lines
2.8 KiB
PHP
<?php
|
|
header('Content-Type: application/json');
|
|
require_once dirname(__DIR__) . '/include/monitor.php';
|
|
require_once dirname(__DIR__) . '/include/media.php';
|
|
|
|
// CPU% — delta from own state file so it doesn't conflict with monitor.php
|
|
$cpuPct = 0;
|
|
$cpuLine = '';
|
|
foreach (file('/proc/stat') ?: [] as $line) {
|
|
if (strncmp($line, 'cpu ', 4) === 0) { $cpuLine = $line; break; }
|
|
}
|
|
if (preg_match('/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/', $cpuLine, $m)) {
|
|
$c = [(int)$m[1],(int)$m[2],(int)$m[3],(int)$m[4],(int)$m[5],(int)$m[6],(int)$m[7]];
|
|
$sf = '/tmp/vv_snap_cpu.json';
|
|
$p = file_exists($sf) ? (json_decode(file_get_contents($sf), true) ?: null) : null;
|
|
file_put_contents($sf, json_encode($c));
|
|
if ($p && is_array($p)) {
|
|
$dt = array_sum($c) - array_sum($p);
|
|
$di = ($c[3] + $c[4]) - ($p[3] + $p[4]);
|
|
$cpuPct = $dt > 0 ? max(0, min(100, (int)round((1 - $di / $dt) * 100))) : 0;
|
|
}
|
|
}
|
|
|
|
// RAM%
|
|
$mem = [];
|
|
foreach (file('/proc/meminfo') ?: [] as $line) {
|
|
if (preg_match('/^(MemTotal|MemAvailable):\s+(\d+)/', $line, $m)) $mem[$m[1]] = (int)$m[2];
|
|
}
|
|
$ramTotalMb = (int)(($mem['MemTotal'] ?? 0) / 1024);
|
|
$ramUsedMb = (int)((($mem['MemTotal'] ?? 0) - ($mem['MemAvailable'] ?? 0)) / 1024);
|
|
$ramPct = $ramTotalMb > 0 ? (int)round($ramUsedMb / $ramTotalMb * 100) : 0;
|
|
|
|
// Fallback state (fast file read, no exec)
|
|
$fallbackState = 'UNKNOWN';
|
|
foreach (@file('/tmp/fallback_state.db') ?: [] as $line) {
|
|
if (preg_match('/^state=(.+)/', trim($line), $m)) { $fallbackState = trim($m[1]); break; }
|
|
}
|
|
|
|
// Partner
|
|
$partner = vv_partner_state();
|
|
$peers = array_values(array_filter($partner['hosts'], fn($h) => !$h['is_me']));
|
|
|
|
// Media sessions — cached 30s so the HTTP calls don't hold up every snapshot poll
|
|
$streamCount = 0;
|
|
$transcodeCount = 0;
|
|
$mediaCacheFile = '/tmp/vv_snap_media.json';
|
|
$cacheMaxAge = 30;
|
|
$cacheValid = file_exists($mediaCacheFile) && (time() - filemtime($mediaCacheFile)) < $cacheMaxAge;
|
|
if ($cacheValid) {
|
|
$cached = json_decode(file_get_contents($mediaCacheFile), true) ?: [];
|
|
} else {
|
|
$media = vv_media_sessions();
|
|
$cached = [
|
|
'stream_count' => count($media['sessions']),
|
|
'transcode_count' => count(array_filter($media['sessions'], fn($s) => !empty($s['is_tc']))),
|
|
];
|
|
file_put_contents($mediaCacheFile, json_encode($cached));
|
|
}
|
|
$streamCount = (int)($cached['stream_count'] ?? 0);
|
|
$transcodeCount = (int)($cached['transcode_count'] ?? 0);
|
|
|
|
echo json_encode([
|
|
'cpu_pct' => $cpuPct,
|
|
'ram_pct' => $ramPct,
|
|
'ram_used_mb' => $ramUsedMb,
|
|
'ram_total_mb' => $ramTotalMb,
|
|
'fallback' => $fallbackState,
|
|
'partner_enabled' => $partner['enabled'],
|
|
'peers' => $peers,
|
|
'stream_count' => $streamCount,
|
|
'transcode_count' => $transcodeCount,
|
|
]);
|