async function loadData() { try { const response = await fetch("data.json?t=" + Date.now()); const data = await response.json(); if (data.length === 0) { return; } const latest = data[data.length - 1]; const upCount = data.filter(item => item.uptime === "UP").length; const uptimePercentage = ((upCount / data.length) * 100).toFixed(1); document.getElementById("uptime").innerText = uptimePercentage + "%"; document.getElementById("latency").innerText = (latest.latency_ms ?? "-") + " ms"; document.getElementById("dns").innerText = (latest.dns_ms ?? "-") + " ms"; if (latest.ssl && latest.ssl.valid) { document.getElementById("ssl").innerHTML = ` Valid
${latest.ssl.expires} `; } else { document.getElementById("ssl").innerHTML = ` Invalid `; } const table = document.getElementById("historyTable"); table.innerHTML = ""; data .slice() .reverse() .forEach(item => { table.innerHTML += ` ${item.timestamp} ${item.uptime} ${item.latency_ms ?? "-"} ${item.dns_ms ?? "-"} ${item.ssl && item.ssl.valid ? "Valid" : "Invalid"} `; }); const labels = data.map(item => item.timestamp); const latency = data.map(item => item.latency_ms); if (!window.latencyChart) { window.latencyChart = new Chart( document.getElementById("latencyChart"), { type: "line", data: { labels: labels, datasets: [{ label: "Latency (ms)", data: latency, borderColor: "#0b7dda", backgroundColor: "rgba(11,125,218,0.15)", fill: true, tension: 0.3 }] }, options: { responsive: true, plugins: { legend: { display: true } }, scales: { y: { beginAtZero: false } } } } ); } else { window.latencyChart.data.labels = labels; window.latencyChart.data.datasets[0].data = latency; window.latencyChart.update(); } } catch (error) { console.error(error); } } loadData(); setInterval(loadData, 60000);