function formatBytes(bytes) { if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB", "TB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`; } function formatUptime(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const mins = Math.floor((seconds % 3600) / 60); if (days > 0) return `${days}d ${hours}h`; if (hours > 0) return `${hours}h ${mins}m`; return `${mins}m`; } const regionNames = typeof Intl !== "undefined" && Intl.DisplayNames ? new Intl.DisplayNames([navigator.language || "en"], { type: "region" }) : null; function normalizeCode(countryCode) { if (!countryCode || countryCode === "Unknown") return null; const normalized = String(countryCode).trim().toUpperCase(); return normalized.length === 2 ? normalized : null; } function getCountryName(countryCode) { const normalized = normalizeCode(countryCode); if (!normalized) return "Unknown"; try { return regionNames?.of(normalized) || normalized; } catch { return normalized; } } function getFlag(countryCode) { const normalized = normalizeCode(countryCode); if (!normalized) return "🌐"; const codePoints = normalized .split("") .map((char) => 127397 + char.charCodeAt(0)); return String.fromCodePoint(...codePoints); } function formatKB(kbString) { const kb = parseFloat(kbString); if (kb >= 1024 * 1024) return `${(kb / 1024 / 1024).toFixed(2)} GB`; if (kb >= 1024) return `${(kb / 1024).toFixed(2)} MB`; return `${kb.toFixed(2)} KB`; } async function fetchLogs() { try { const response = await fetch("/api/logs"); const text = await response.text(); const logDiv = document.getElementById("activity-log"); const lines = text .split("\n") .filter((line) => line.includes("In the last")) .reverse(); if (lines.length === 0) { logDiv.innerHTML = '
No activity yet. Check back soon!
'; return; } const rows = lines .flatMap((line) => { const match = line.match( /(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}).*?(\d+) completed.*?↓ ([\d.]+) KB \(([\d.]+) KB\/s\).*?↑ ([\d.]+) KB \(([\d.]+) KB\/s\)/, ); if (!match) return []; const [, timestamp, connections, dlTotal, dlRate, ulTotal, ulRate] = match; const utcDate = new Date(`${timestamp.replace(/\//g, "-")}Z`); const time = utcDate.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", }); const fullDate = utcDate.toLocaleDateString([], { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", }); const isoDate = utcDate.toISOString(); return [ ` ${connections} ${formatKB(dlTotal)} (${formatKB(dlRate)}/s) ${formatKB(ulTotal)} (${formatKB(ulRate)}/s) `, ]; }) .join(""); logDiv.innerHTML = ` ${rows}
Time Conns Download Upload
`; pulse(logDiv); } catch (_e) { document.getElementById("activity-log").innerHTML = '
Error loading logs
'; } } async function fetchNatType() { try { const response = await fetch("/api/nat"); const text = await response.text(); const natType = text.trim() || "Unknown"; const el = document.getElementById("nat-type"); const row = document.getElementById("nat-row"); const isUnknown = !natType || natType.toLowerCase() === "unknown"; if (row) row.hidden = isUnknown; if (el && !isUnknown) { const capitalized = natType.charAt(0).toUpperCase() + natType.slice(1).toLowerCase(); el.textContent = capitalized; const natLower = natType.toLowerCase(); let natDesc = ""; if (natLower === "unrestricted") { natDesc = "Address-independent NAT mapping. Compatible with most other NATs and can connect to restricted proxies."; } else if (natLower === "restricted") { natDesc = "Address-dependent NAT mapping. May have limited compatibility with other restricted NATs."; } if (natDesc) { el.title = natDesc; const descId = "nat-type-desc"; let descEl = document.getElementById(descId); if (!descEl) { descEl = document.createElement("span"); descEl.id = descId; descEl.className = "sr-only"; el.insertAdjacentElement("afterend", descEl); } descEl.textContent = natDesc; el.setAttribute("aria-describedby", descId); } } } catch (_e) { const el = document.getElementById("nat-type"); const row = document.getElementById("nat-row"); if (row) row.hidden = false; if (el) el.innerHTML = 'Error'; } } async function fetchStats() { try { const response = await fetch("/api/metrics"); const text = await response.text(); let total = 0; let timeouts = 0; let torInbound = 0; let torOutbound = 0; let memory = 0; let startTime = 0; const countries = {}; text.split("\n").forEach((line) => { if (line.startsWith("tor_snowflake_proxy_connections_total")) { const match = line.match(/country="([^"]*)".*?(\d+)$/); if (match) { const country = match[1] || "Unknown"; const count = parseInt(match[2], 10); countries[country] = count; total += count; } } else if ( line.startsWith("tor_snowflake_proxy_connection_timeouts_total") ) { const match = line.match(/(\d+)$/); if (match) timeouts = parseInt(match[1], 10); } else if ( line.startsWith("tor_snowflake_proxy_traffic_inbound_bytes_total") ) { const match = line.match(/(\d+\.?\d*e?\+?\d*)$/); if (match) torInbound = parseFloat(match[1]) * 1024; } else if ( line.startsWith("tor_snowflake_proxy_traffic_outbound_bytes_total") ) { const match = line.match(/(\d+\.?\d*e?\+?\d*)$/); if (match) torOutbound = parseFloat(match[1]) * 1024; } else if (line.startsWith("process_resident_memory_bytes")) { const match = line.match(/(\d+\.?\d*e?\+?\d*)$/); if (match) memory = parseFloat(match[1]); } else if (line.startsWith("process_start_time_seconds")) { const match = line.match(/(\d+\.?\d*e?\+?\d*)$/); if (match) startTime = parseFloat(match[1]); } }); const attempts = total + timeouts; const successRate = attempts > 0 ? (total / attempts) * 100 : 0; const uptime = startTime > 0 ? Date.now() / 1000 - startTime : 0; document.getElementById("total").textContent = total; document.getElementById("timeouts").textContent = timeouts; const rateEl = document.getElementById("success-rate-small"); const statusLabel = successRate >= 70 ? "Good" : successRate >= 40 ? "Warning" : "Critical"; rateEl.innerHTML = `${successRate.toFixed(1)}% (${statusLabel})`; rateEl.className = successRate >= 70 ? "success-rate" : successRate >= 40 ? "warn-rate" : "error"; document.getElementById("tor-traffic").textContent = `${formatBytes(torInbound)} / ${formatBytes(torOutbound)}`; document.getElementById("memory").textContent = formatBytes(memory); document.getElementById("uptime").textContent = formatUptime(uptime); pulse(document.getElementById("metrics-stat")); const table = document.getElementById("countries"); const tbody = table.querySelector("tbody"); tbody.innerHTML = ""; Object.entries(countries) .sort((a, b) => b[1] - a[1]) .forEach(([country, count]) => { const row = tbody.insertRow(); const displayName = getCountryName(country); const percentage = total > 0 ? ((count / total) * 100).toFixed(1) : 0; const countryCell = row.insertCell(0); const flagSpan = document.createElement("span"); flagSpan.className = "flag"; flagSpan.textContent = getFlag(country); countryCell.appendChild(flagSpan); countryCell.appendChild(document.createTextNode(displayName)); row.insertCell(1).textContent = count; row.insertCell(2).textContent = `${percentage}%`; }); } catch (_e) { for (const id of ["total", "timeouts", "tor-traffic", "memory", "uptime"]) { const el = document.getElementById(id); if (el) el.innerHTML = 'Error'; } } } function pulse(el) { if (!el) return; el.classList.remove("refreshed"); // force reflow so the animation restarts void el.offsetWidth; el.classList.add("refreshed"); } fetchStats(); fetchLogs(); fetchNatType(); setInterval(fetchStats, 300000); setInterval(fetchLogs, 300000);