/dev/null'); $containers = []; foreach (explode("\n", trim($out ?? '')) as $line) { if (!$line) continue; $c = json_decode($line, true); if ($c) $containers[] = $c; } return $containers; } function vv_docker_stopped(): array { $out = shell_exec('docker ps -a --filter "status=exited" --filter "status=created" --format \'{"name":"{{.Names}}","status":"{{.Status}}"}\' 2>/dev/null'); $containers = []; foreach (explode("\n", trim($out ?? '')) as $line) { if (!$line) continue; $c = json_decode($line, true); if ($c) $containers[] = $c; } return $containers; } function vv_gpu_stats(): array { $out = shell_exec('nvidia-smi --query-gpu=name,memory.used,memory.total,utilization.gpu,temperature.gpu --format=csv,noheader,nounits 2>/dev/null'); if (!$out) return ['available' => false]; $parts = array_map('trim', explode(',', $out)); return [ 'available' => true, 'name' => $parts[0] ?? '', 'memory_used' => (int)($parts[1] ?? 0), 'memory_total' => (int)($parts[2] ?? 0), 'utilization' => (int)($parts[3] ?? 0), 'temperature' => (int)($parts[4] ?? 0), ]; } function vv_gpu_processes(): array { $out = shell_exec('nvidia-smi --query-compute-apps=pid,used_gpu_memory,name --format=csv,noheader,nounits 2>/dev/null'); $procs = []; foreach (explode("\n", trim($out ?? '')) as $line) { if (!$line) continue; $parts = array_map('trim', explode(',', $line)); $procs[] = [ 'pid' => $parts[0] ?? '', 'memory_mb' => $parts[1] ?? '', 'name' => $parts[2] ?? '', ]; } return $procs; } function vv_system_resources(): array { // RAM $mem = []; foreach (file('/proc/meminfo') ?: [] as $line) { if (preg_match('/^(MemTotal|MemAvailable):\s+(\d+)/', $line, $m)) $mem[$m[1]] = (int)$m[2]; } // CPU (1-second sample) $cpu = (int)trim(shell_exec("top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d. -f1") ?: '0'); // Disk — ramdisk + cache $ramdisk = vv_df('/mnt/ramdisk_transcodes'); $cache = vv_df('/mnt/cache'); return [ 'ram_total_mb' => (int)(($mem['MemTotal'] ?? 0) / 1024), 'ram_free_mb' => (int)(($mem['MemAvailable'] ?? 0) / 1024), 'cpu_percent' => $cpu, 'ramdisk' => $ramdisk, 'cache' => $cache, ]; } function vv_df(string $path): array { $out = shell_exec("df -BM --output=size,used,avail '$path' 2>/dev/null | tail -1"); if (!$out) return ['available' => false, 'path' => $path]; $parts = preg_split('/\s+/', trim($out)); return [ 'available' => true, 'path' => $path, 'size_mb' => (int)$parts[0], 'used_mb' => (int)$parts[1], 'free_mb' => (int)$parts[2], ]; } function vv_fallback_state(): array { // State file written by fallback.sh $stateFile = '/tmp/fallback_state.db'; if (!file_exists($stateFile)) return ['state' => 'UNKNOWN']; $raw = []; foreach (file($stateFile) ?: [] as $line) { [$k, $v] = array_pad(explode('=', trim($line), 2), 2, ''); $raw[trim($k)] = trim($v); } return [ 'state' => $raw['state'] ?? 'UNKNOWN', 'failover_start' => $raw['failover_start'] ?? '0', 'tier2_started' => $raw['tier2_started'] ?? 'false', 'tier3_started' => $raw['tier3_started'] ?? 'false', 'tier4_started' => $raw['tier4_started'] ?? 'false', ]; } function vv_transcode_sessions(): array { // Read from transcode state file written by transcode_manager.sh $stateFile = '/tmp/transcode_state.db'; if (!file_exists($stateFile)) return []; $raw = []; foreach (file($stateFile) ?: [] as $line) { [$k, $v] = array_pad(explode('=', trim($line), 2), 2, ''); $raw[trim($k)] = trim($v); } return $raw; }