Files
circlewithadot.net/services/aprelay.js

101 lines
3.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* @licstart Copyleft (🄯) 2025 James Osborne — AGPLv3+ @licend */
'use strict';
/* ===== Copy-to-clipboard handler ===== */
document.addEventListener('click', (e) => {
const el = e.target.closest('.copyable');
if (!el) return;
const text = el.dataset.copy ?? '';
const copyPromise =
(navigator.clipboard && window.isSecureContext)
? navigator.clipboard.writeText(text)
: (async () => {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); } catch {}
ta.remove();
})();
Promise.resolve(copyPromise).then(() => {
el.dataset._orig ??= el.textContent || '';
el.textContent = `${el.dataset._orig} (copied!)`;
setTimeout(() => { el.textContent = el.dataset._orig; }, 1500);
});
});
/* ===== Stats loader ===== */
async function loadStats() {
const endpoints = [
'/relay-stats.json', // same-origin first (no CORS)
'https://relay-us-east.circlewithadot.net/relay-stats.json',
];
for (const url of endpoints) {
try {
const r = await fetch(url, { cache: 'no-store' });
if (!r.ok) continue;
const d = await r.json();
const set = (id, val) => {
const el = document.getElementById(id);
if (el) el.textContent = val;
};
set('instances', d.instances ?? '');
// accept either jobs_5min (new) or jobs_per_min (old)
set('jobs', (d.jobs_5min ?? d.jobs_per_min ?? ''));
set('updated', d.updated ? new Date(d.updated).toLocaleString() : '');
return;
} catch (e) {
console.warn('[relay stats] fetch failed:', e);
}
}
const box = document.getElementById('relay-stats');
if (box) box.textContent = 'Stats unavailable';
}
loadStats();
setInterval(loadStats, 300000);
async function loadInstanceStatuses() {
const bodyEl = document.getElementById("instances-body");
const updatedEl = document.getElementById("instances-updated");
if (!bodyEl || !updatedEl) return;
try {
const res = await fetch("aprelay_instances.json", { cache: "no-store" });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
const instances = Array.isArray(data.instances) ? data.instances : [];
updatedEl.textContent = data.generated_at || "";
if (!instances.length) {
bodyEl.innerHTML = `<div class="instances-row"><span class="mono">No data</span><span></span></div>`;
return;
}
bodyEl.innerHTML = instances.map(x => `
<div class="instances-row" role="row">
<span class="mono" role="cell">${x.domain}</span>
<span role="cell">${x.status}</span>
</div>
`).join("");
} catch (e) {
bodyEl.innerHTML = `<div class="instances-row"><span class="mono">Error loading list</span><span></span></div>`;
updatedEl.textContent = "";
}
}
document.addEventListener("DOMContentLoaded", () => {
loadInstanceStatuses();
});