re-run the partner cache writer for one host // (POST, so Unraid's CSRF guard applies) // // RESPONSE // normal vv_arrs_all() verbatim — local node live, remote nodes cached with cache_age // refresh {"ok":bool,"node":object|null,"output":string} // errors {"ok":false,"error":string} — invalid host, missing script, or timeout // // DEPENDS ON // include/config.php vv_cache_read(), VV_CACHE_DIR // include/arrs.php vv_arrs_all() (loaded only on a cache miss) // Tools/remote_arr_cache_writer.sh (refresh branch only) // ═══════════════════════════════════════════════════════════════════════════════════════════════ header('Content-Type: application/json'); require_once dirname(__DIR__) . '/include/config.php'; // Bound on the partner refresh child process. set_time_limit() does not cover exec() time // on Linux, so this is enforced by `timeout`, not by PHP. define('VV_ARRS_REFRESH_TIMEOUT', 120); // ── Manual remote refresh — runs remote_arr_cache_writer for one host ───────── // POST only. The refresh executes a script, and Unraid's CSRF prepend validates POSTs while // ignoring GETs entirely — so reaching this over GET would mean running it with no token // check. A GET naming the action is refused rather than falling through to the cached read, // so a stale caller fails visibly instead of silently appearing to succeed. if (trim($_GET['action'] ?? '') === 'refresh_remote') { http_response_code(405); echo json_encode(['ok' => false, 'error' => 'POST only']); exit; } $_action = ($_SERVER['REQUEST_METHOD'] === 'POST') ? trim($_POST['action'] ?? '') : ''; if ($_action === 'refresh_remote') { $host = strtolower(trim($_POST['host'] ?? '')); if (!preg_match('/^host\d+$/', $host)) { echo json_encode(['ok' => false, 'error' => 'Invalid host']); exit; } $script = dirname(__DIR__) . '/Tools/remote_arr_cache_writer.sh'; if (!file_exists($script)) { echo json_encode(['ok' => false, 'error' => 'remote_arr_cache_writer.sh not found']); exit; } set_time_limit(VV_ARRS_REFRESH_TIMEOUT + 30); $out = []; $exit = 0; exec('timeout ' . VV_ARRS_REFRESH_TIMEOUT . ' bash ' . escapeshellarg($script) . ' --host=' . escapeshellarg(strtoupper($host)) . ' 2>&1', $out, $exit); if ($exit === 124) { echo json_encode([ 'ok' => false, 'error' => 'Refresh timed out after ' . VV_ARRS_REFRESH_TIMEOUT . 's', 'output' => implode("\n", $out), ]); exit; } $cacheFile = VV_CACHE_DIR . '/arrs_remote_' . $host . '.json'; $node = null; if (file_exists($cacheFile)) { $node = json_decode(file_get_contents($cacheFile), true) ?: null; if ($node) { $node['cached'] = true; $node['cache_age'] = time() - (int)filemtime($cacheFile); } } // Bust the main arrs cache so next poll gets fresh data @unlink(VV_CACHE_DIR . '/arrs.json'); echo json_encode(['ok' => $exit === 0, 'node' => $node, 'output' => implode("\n", $out)]); exit; } unset($_action); // ── Normal data load ────────────────────────────────────────────────────────── $_vv_cached = vv_cache_read('arrs', 300); if ($_vv_cached !== null) { echo json_encode($_vv_cached); exit; } unset($_vv_cached); require_once dirname(__DIR__) . '/include/arrs.php'; echo json_encode(vv_arrs_all());