fix: drop duplicate count query; cache upstream version failures

- global_stats() executed the 'last N seconds' COUNT twice per page
  load (prepare()->execute() result was discarded, then re-run)
- fetch_upstream_version() cached nothing on failure, so an
  unreachable git server added a cURL wait (up to 5 s) to every
  dashboard load via the 30 s auto-refresh; failures are now cached
  for 15 minutes and get a 2 s connect timeout
This commit is contained in:
daprogs committed 2026-10-18 22:12:18 -04:00
1 parent b0fdd99ad6
commit 4ce1502831
1 file changed
+24 -17
+24 -17
View File
@@ -274,18 +274,24 @@ function purge_old_connections(): int {
define('UPSTREAM_VERSION_URL', 'https://git.ny.daprogs.com/api/v1/repos/DAProgs/portspoof_concentrator/raw/version.php?ref=main'); define('UPSTREAM_VERSION_URL', 'https://git.ny.daprogs.com/api/v1/repos/DAProgs/portspoof_concentrator/raw/version.php?ref=main');
define('UPSTREAM_VERSION_CACHE', __DIR__ . '/../upstream_version.cache'); define('UPSTREAM_VERSION_CACHE', __DIR__ . '/../upstream_version.cache');
define('UPSTREAM_VERSION_TTL', 3600); // seconds define('UPSTREAM_VERSION_TTL', 3600); // seconds
define('UPSTREAM_VERSION_FAIL_TTL', 900); // seconds — how long to cache a failed check
/** /**
* Fetch the upstream version string from the git repo, with a 1-hour file cache. * Fetch the upstream version string from the git repo, with a 1-hour file cache.
* Returns null silently on any failure so the page always loads. * Returns null silently on any failure so the page always loads.
*
* Failures are cached briefly too, so an unreachable git server does not
* add a cURL wait to every dashboard load (the page auto-refreshes every 30 s).
*/ */
function fetch_upstream_version(): ?string { function fetch_upstream_version(): ?string {
// Return cached value if still fresh // Return cached value (success or failure) if still fresh
if (file_exists(UPSTREAM_VERSION_CACHE)) { if (file_exists(UPSTREAM_VERSION_CACHE)) {
$cached = json_decode(file_get_contents(UPSTREAM_VERSION_CACHE), true); $cached = json_decode(file_get_contents(UPSTREAM_VERSION_CACHE), true);
if (isset($cached['version'], $cached['checked_at']) if (isset($cached['checked_at'])) {
&& (time() - $cached['checked_at']) < UPSTREAM_VERSION_TTL) { $ttl = isset($cached['version']) ? UPSTREAM_VERSION_TTL : UPSTREAM_VERSION_FAIL_TTL;
return $cached['version']; if ((time() - $cached['checked_at']) < $ttl) {
return $cached['version'] ?? null;
}
} }
} }
@@ -293,27 +299,30 @@ function fetch_upstream_version(): ?string {
curl_setopt_array($ch, [ curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5, CURLOPT_TIMEOUT => 5,
CURLOPT_CONNECTTIMEOUT => 2,
CURLOPT_FOLLOWLOCATION => true, CURLOPT_FOLLOWLOCATION => true,
]); ]);
$body = curl_exec($ch); $body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch); curl_close($ch);
if ($body === false || $code !== 200) { if ($body !== false && $code === 200
return null; && preg_match("/define\s*\(\s*'APP_VERSION'\s*,\s*'([^']+)'\s*\)/", $body, $m)) {
}
if (!preg_match("/define\s*\(\s*'APP_VERSION'\s*,\s*'([^']+)'\s*\)/", $body, $m)) {
return null;
}
$version = $m[1];
file_put_contents( file_put_contents(
UPSTREAM_VERSION_CACHE, UPSTREAM_VERSION_CACHE,
json_encode(['version' => $version, 'checked_at' => time()]), json_encode(['version' => $m[1], 'checked_at' => time()]),
LOCK_EX LOCK_EX
); );
return $version; return $m[1];
}
// Cache the failure so we don't retry on every page load
file_put_contents(
UPSTREAM_VERSION_CACHE,
json_encode(['version' => null, 'checked_at' => time()]),
LOCK_EX
);
return null;
} }
/** /**
@@ -366,8 +375,6 @@ function global_stats(): array {
$total = (int)$pdo->query('SELECT COUNT(*) FROM connections')->fetchColumn(); $total = (int)$pdo->query('SELECT COUNT(*) FROM connections')->fetchColumn();
$since = date('Y-m-d H:i:s', time() - RATE_WINDOW_SECONDS); $since = date('Y-m-d H:i:s', time() - RATE_WINDOW_SECONDS);
$recent = (int)$pdo->prepare('SELECT COUNT(*) FROM connections WHERE occurred_at >= ?')
->execute([$since]) ? : 0;
$s = $pdo->prepare('SELECT COUNT(*) FROM connections WHERE occurred_at >= ?'); $s = $pdo->prepare('SELECT COUNT(*) FROM connections WHERE occurred_at >= ?');
$s->execute([$since]); $s->execute([$since]);
$recent = (int)$s->fetchColumn(); $recent = (int)$s->fetchColumn();