clavitor/clavitor.com/templates/glass.tmpl

98 lines
3.6 KiB
Cheetah

{{define "glass"}}
<div class="hero container">
<p class="label accent mb-4">Network</p>
<h1 class="mb-4">Looking Glass</h1>
<p class="lead">{{len .Pops}} points of presence. Find the fastest node for you.</p>
</div>
<div class="section container" style="padding-top:24px">
<div class="glass-grid">
{{range .Pops}}
<div class="glass-pop {{if eq .Status "live"}}glass-live{{else}}glass-planned{{end}}">
<div class="glass-header">
<div><div class="pop-city">{{.City}}</div><div class="pop-country">{{.CountryFull}}</div></div>
<span class="glass-status {{if eq .Status "live"}}glass-status-live{{else}}glass-status-planned{{end}}">{{.Status}}</span>
</div>
{{if eq .Status "live"}}<div class="glass-latency-block">
<div class="glass-latency-left"><span class="glass-latency-title">Response time</span><span class="glass-latency-hint">lower is better</span></div>
<div class="glass-latency-hero glass-latency" data-dns="{{.DNS}}" data-status="{{.Status}}">—</div>
</div>
<div class="glass-details">
{{if .IP}}<div class="glass-row">
<span class="glass-key">IPv4</span>
<span class="glass-val mono">{{.IP}}</span>
</div>{{end}}
{{if .DNS}}<div class="glass-row">
<span class="glass-key">DNS</span>
<span class="glass-val mono">{{.DNS}}</span>
</div>{{end}}
</div>{{end}}
</div>
{{end}}
</div>
</div>
{{end}}
{{define "glass-script"}}
<script>
(function() {
const grid = document.querySelector('.glass-grid');
function classify(ms) {
if (ms < 60) return 'glass-fast';
if (ms < 120) return 'glass-ok';
return 'glass-slow';
}
function applyResult(el, ms) {
el.classList.remove('glass-fast', 'glass-ok', 'glass-slow');
if (ms < 4900) {
el.textContent = ms + ' ms';
el.dataset.ms = ms;
el.classList.add(classify(ms));
} else {
el.textContent = 'down';
el.dataset.ms = 99999;
el.classList.add('glass-slow');
}
}
function sortGrid() {
const arr = Array.from(grid.querySelectorAll('.glass-pop'));
arr.sort((a, b) => {
const aMs = parseInt(a.querySelector('.glass-latency')?.dataset.ms || 99998);
const bMs = parseInt(b.querySelector('.glass-latency')?.dataset.ms || 99998);
return aMs - bMs;
});
arr.forEach(el => grid.appendChild(el));
}
function ping(el) {
const dns = el.dataset.dns;
if (!dns) { el.textContent = '—'; return Promise.resolve(); }
el.textContent = '...';
// Warm-up: first fetch establishes TLS, second measures actual latency
return fetch('https://' + dns + ':1984/ping').then(() => {}).catch(() => {}).then(() => {
const t0 = performance.now();
return fetch('https://' + dns + ':1984/ping').then(() => {}).catch(() => {}).then(() => {
applyResult(el, Math.round(performance.now() - t0));
sortGrid();
});
});
}
async function pingAll() {
const els = Array.from(document.querySelectorAll('.glass-latency[data-status="live"][data-dns]'));
if (window.innerWidth < 768) {
for (const el of els) { await ping(el); sortGrid(); }
} else {
els.forEach(el => ping(el));
}
}
pingAll();
setInterval(pingAll, 60000);
})();
</script>
{{end}}