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, ]);