PHP app layer: consolidate common functions, fix critical bugs, standardize patterns
Consolidations (config.php gains 5 shared utilities): - vv_format_uptime() replaces 4 inline uptime-formatting blocks - vv_parse_conf_scalar() replaces vv_arr_scalar/vv_wd_scalar/vv_fb_scalar/vv_media_conf_scalar - vv_known_hosts() replaces vv_arr_known_hosts/vv_fb_known_hosts + inline parser in watchdog - vv_parse_kv_db() replaces inline key=value parsing in snapshot and monitor - vv_local_ip() replaces duplicate in docker_folders.php and inline in docker.php All module-level function names kept as thin aliases so call sites unchanged. Critical bug fixes: - api/system.php: added require_once config.php and POST-only guard (no auth on shutdown) - api/movescript.php + reorderarray.php: use vv_write_conf_raw (atomic) + vv_push_master_conf - api/snapshot.php: share /tmp/vv_cpu_stat.json with vv_cpu_per_core() instead of own state file Correctness: - vv_cpu_per_core() and vv_network_stats(): atomic tmp+rename for state files (concurrent poll safety) - ext_ip curl cache moved from /tmp/vv_ext_ip.cache to vv_cache_read/write (canonical cache dir) - monitor_remote.php + board.php + snapshot.php: all use vv_cache_read/write instead of ad-hoc /tmp files HTTP method guards added to write-only APIs that were missing them: - api/scheduler.php, conf_toggle.php, flag_toggle.php
This commit is contained in:
@@ -80,13 +80,9 @@ if (is_dir(LOG_DIR)) {
|
||||
$out['errors'] = array_slice($errors, 0, 20);
|
||||
|
||||
// ── Partner reachability ───────────────────────────────────────────────────
|
||||
$cacheFile = '/tmp/vv_partner_cache.json';
|
||||
$cacheTtl = 30;
|
||||
$partnerData = null;
|
||||
$partnerData = vv_cache_read('board_partner', 30);
|
||||
|
||||
if (file_exists($cacheFile) && (time() - (int)filemtime($cacheFile)) < $cacheTtl) {
|
||||
$partnerData = json_decode(file_get_contents($cacheFile), true);
|
||||
} else {
|
||||
if (!$partnerData) {
|
||||
// Discover partner hostname dynamically from master.conf (works for any number of hosts)
|
||||
$vars = vv_conf_vars();
|
||||
$mine = vv_get_hostname();
|
||||
@@ -113,7 +109,7 @@ if (file_exists($cacheFile) && (time() - (int)filemtime($cacheFile)) < $cacheTtl
|
||||
'reachable' => $reached,
|
||||
'latency' => $reached ? $elapsed : null,
|
||||
];
|
||||
@file_put_contents($cacheFile, json_encode($partnerData));
|
||||
vv_cache_write('board_partner', $partnerData);
|
||||
}
|
||||
}
|
||||
$out['partner'] = $partnerData;
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/scheduler.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['ok' => false, 'error' => 'POST only']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = trim($_POST['id'] ?? '');
|
||||
$enabled = ($_POST['enabled'] ?? '0') === '1';
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/scheduler.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['ok' => false, 'error' => 'POST only']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$enabled = ($_POST['enabled'] ?? '0') === '1';
|
||||
|
||||
|
||||
@@ -3,18 +3,11 @@ header('Content-Type: application/json');
|
||||
header('Cache-Control: no-cache, no-store');
|
||||
require_once dirname(__DIR__) . '/include/monitor.php';
|
||||
|
||||
$cacheFile = '/tmp/vv_cache_monitor_remote.json';
|
||||
$cacheTTL = 3600;
|
||||
|
||||
if (!isset($_GET['live']) && file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTTL) {
|
||||
echo file_get_contents($cacheFile);
|
||||
exit;
|
||||
if (!isset($_GET['live'])) {
|
||||
$cached = vv_cache_read('monitor_remote', 3600);
|
||||
if ($cached) { echo json_encode($cached); exit; }
|
||||
}
|
||||
|
||||
$out = json_encode([
|
||||
'remote_hosts' => vv_remote_hosts_stats(),
|
||||
'ts' => time(),
|
||||
]);
|
||||
|
||||
file_put_contents($cacheFile, $out);
|
||||
echo $out;
|
||||
$data = ['remote_hosts' => vv_remote_hosts_stats(), 'ts' => time()];
|
||||
vv_cache_write('monitor_remote', $data);
|
||||
echo json_encode($data);
|
||||
|
||||
@@ -70,9 +70,10 @@ if ($toArray) {
|
||||
$newLines = $resultLines;
|
||||
}
|
||||
|
||||
if (file_put_contents($confPath, implode('', $newLines)) === false) {
|
||||
if (!vv_write_conf_raw('master.conf', implode('', $newLines))) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Write failed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
vv_push_master_conf();
|
||||
echo json_encode(['ok' => true]);
|
||||
|
||||
@@ -101,9 +101,10 @@ $newBlockLines[] = $lines[$blockEnd];
|
||||
// Replace the original block in $lines
|
||||
array_splice($lines, $blockStart, $blockEnd - $blockStart + 1, $newBlockLines);
|
||||
|
||||
if (file_put_contents($confPath, implode('', $lines)) === false) {
|
||||
if (!vv_write_conf_raw('master.conf', implode('', $lines))) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Write failed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
vv_push_master_conf();
|
||||
echo json_encode(['ok' => true]);
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/scheduler.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['ok' => false, 'error' => 'POST only']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Batch save — all entries in one load/write/rebuild cycle
|
||||
if (!empty($_POST['batch'])) {
|
||||
$entries = json_decode($_POST['batch'], true) ?: [];
|
||||
|
||||
@@ -3,61 +3,36 @@ 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;
|
||||
}
|
||||
}
|
||||
// CPU% — shares /tmp/vv_cpu_stat.json with vv_cpu_per_core() so both read the same baseline
|
||||
$cpuPct = vv_cpu_per_core()['overall'] ?? 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);
|
||||
$res = vv_system_resources();
|
||||
$ramTotalMb = $res['ram_total_mb'];
|
||||
$ramUsedMb = $ramTotalMb - $res['ram_free_mb'];
|
||||
$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; }
|
||||
}
|
||||
$fbRaw = @file_get_contents('/tmp/fallback_state.db') ?: '';
|
||||
$fbData = vv_parse_kv_db($fbRaw);
|
||||
$fallbackState = $fbData['state'] ?? 'UNKNOWN';
|
||||
|
||||
// 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 = [
|
||||
$mediaCache = vv_cache_read('snap_media', 30);
|
||||
if (!$mediaCache) {
|
||||
$media = vv_media_sessions();
|
||||
$mediaCache = [
|
||||
'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));
|
||||
vv_cache_write('snap_media', $mediaCache);
|
||||
}
|
||||
$streamCount = (int)($cached['stream_count'] ?? 0);
|
||||
$transcodeCount = (int)($cached['transcode_count'] ?? 0);
|
||||
$streamCount = (int)($mediaCache['stream_count'] ?? 0);
|
||||
$transcodeCount = (int)($mediaCache['transcode_count'] ?? 0);
|
||||
|
||||
echo json_encode([
|
||||
'cpu_pct' => $cpuPct,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['ok' => false, 'error' => 'POST only']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$body = json_decode(file_get_contents('php://input'), true) ?? [];
|
||||
$action = $body['action'] ?? '';
|
||||
|
||||
Reference in New Issue
Block a user