This commit is contained in:
𓍼 2025-06-08 00:43:31 -05:00
parent 396b81929a
commit 20d49560e9
6 changed files with 103 additions and 131 deletions

127
index.mjs
View File

@ -17,7 +17,6 @@ import wisp from "wisp-server-node";
const surgeConfigPath = path.resolve("surge.config.json"); const surgeConfigPath = path.resolve("surge.config.json");
const isSurgedRun = process.argv.includes("--surged"); const isSurgedRun = process.argv.includes("--surged");
let startTime = Date.now();
function applySurgeAndRestartIfNeeded() { function applySurgeAndRestartIfNeeded() {
if (isSurgedRun) { if (isSurgedRun) {
@ -48,20 +47,13 @@ applySurgeAndRestartIfNeeded();
if (global.gc) { if (global.gc) {
setInterval(() => { setInterval(() => {
const { heapUsed, heapTotal } = process.memoryUsage(); const { heapUsed, heapTotal } = process.memoryUsage();
if (heapTotal > 0 && heapUsed / heapTotal > 0.7) global.gc(); if (heapTotal > 0 && heapUsed / heapTotal > 0.8) global.gc();
}, 60000); }, 120000);
} }
import "./others/scaler.mjs"; import "./others/scaler.mjs";
import "./others/warmup.mjs"; import "./others/warmup.mjs";
const cache = new LRUCache({
maxSize: 1000,
ttl: 60_000,
allowStale: false,
sizeCalculation: (value, key) => Buffer.byteLength(value) + Buffer.byteLength(key)
});
const port = parseInt(process.env.PORT || "3000", 10); const port = parseInt(process.env.PORT || "3000", 10);
function logInfo(msg) { function logInfo(msg) {
@ -80,9 +72,7 @@ process.on("uncaughtException", err => logError(`Unhandled Exception: ${err}`));
process.on("unhandledRejection", reason => logError(`Unhandled Rejection: ${reason}`)); process.on("unhandledRejection", reason => logError(`Unhandled Rejection: ${reason}`));
if (cluster.isPrimary) { if (cluster.isPrimary) {
const cpus = os.cpus().length; const workers = Math.max(1, os.cpus().length - 1);
const workers = Math.max(1, cpus - 1);
logInfo(`Master: forking ${workers} workers`); logInfo(`Master: forking ${workers} workers`);
for (let i = 0; i < workers; i++) { for (let i = 0; i < workers; i++) {
@ -108,18 +98,26 @@ if (cluster.isPrimary) {
const __dirname = process.cwd(); const __dirname = process.cwd();
const publicPath = path.join(__dirname, "public"); const publicPath = path.join(__dirname, "public");
const app = express(); const app = express();
let latencySamples = [];
const cache = new LRUCache({
max: 500,
ttl: 60_000,
allowStale: false
});
const latencySamples = new Array(200);
app.use(compression({ level: 4, memLevel: 4, threshold: 1024 })); app.use(compression({ level: 4, memLevel: 4, threshold: 1024 }));
app.use((req, res, next) => { app.use((req, res, next) => {
if (req.path.startsWith("/api/")) return next();
const key = req.originalUrl; const key = req.originalUrl;
const val = cache.get(key); const val = cache.get(key);
if (val) { if (val) {
res.setHeader("X-Cache", "HIT"); res.setHeader("X-Cache", "HIT");
return res.send(val); return res.send(val);
} }
res.sendResponse = res.send.bind(res); res.sendResponse = res.send;
res.send = body => { res.send = body => {
cache.set(key, body); cache.set(key, body);
res.setHeader("X-Cache", "MISS"); res.setHeader("X-Cache", "MISS");
@ -128,13 +126,12 @@ if (cluster.isPrimary) {
next(); next();
}); });
const staticOpts = { maxAge: "7d", immutable: true }; const staticOpts = { maxAge: "7d", immutable: true, etag: false };
app.use("/baremux/", express.static(baremuxPath, staticOpts)); app.use("/baremux/", express.static(baremuxPath, staticOpts));
app.use("/epoxy/", express.static(epoxyPath, staticOpts)); app.use("/epoxy/", express.static(epoxyPath, staticOpts));
app.use("/libcurl/", express.static(libcurlPath, staticOpts)); app.use("/libcurl/", express.static(libcurlPath, staticOpts));
app.use(express.static(publicPath, staticOpts)); app.use(express.static(publicPath, staticOpts));
app.use("/wah/", express.static(uvPath, staticOpts)); app.use("/wah/", express.static(uvPath, staticOpts));
app.use(express.json());
const sendHtml = file => (_req, res) => res.sendFile(path.join(publicPath, file)); const sendHtml = file => (_req, res) => res.sendFile(path.join(publicPath, file));
@ -144,75 +141,40 @@ if (cluster.isPrimary) {
app.get("/resent", (_req, res) => res.sendFile(path.join(publicPath, "resent", "index.html"))); app.get("/resent", (_req, res) => res.sendFile(path.join(publicPath, "resent", "index.html")));
app.get("/api/info", (_req, res) => { app.get("/api/info", (_req, res) => {
try { const validSamples = latencySamples.filter(s => s !== undefined);
const average = latencySamples.length const average = validSamples.length ? validSamples.reduce((a, b) => a + b, 0) / validSamples.length : 0;
? latencySamples.reduce((a, b) => a + b, 0) / latencySamples.length res.json({
: 0; speed: average < 200 ? "Fast" : average > 500 ? "Slow" : "Medium",
let speed = "Medium"; averageLatency: average.toFixed(2),
if (average < 200) speed = "Fast"; timestamp: Date.now()
else if (average > 500) speed = "Slow"; });
const cpus = os.cpus();
const totalMem = os.totalmem() / 1024 / 1024 / 1024;
res.json({
speed,
averageLatency: average.toFixed(2),
specs: `${cpus[0].model} + ${cpus.length} CPU Cores + ${totalMem.toFixed(1)}GB of RAM`,
startTime,
samples: latencySamples.length,
timestamp: Date.now()
});
} catch {
res.status(500).json({ error: "Internal error" });
}
});
app.get("/api/latest-commit", async (_req, res) => {
try {
const ghRes = await fetch(
"https://api.github.com/repos/xojw/waves/commits?per_page=1",
{
headers: {
"User-Agent": "waves-app",
Accept: "application/vnd.github.v3+json"
}
}
);
if (!ghRes.ok) return res.status(ghRes.status).json({ error: "GitHub API error" });
const commits = await ghRes.json();
const updates = commits.map(c => ({
sha: c.sha.slice(0, 7),
message: c.commit.message.split("\n")[0],
author: c.commit.author.name,
date: c.commit.author.date
}));
res.json({ repo: "xojw/waves", updates });
} catch {
res.status(500).json({ error: "Internal server error" });
}
}); });
app.use((_req, res) => res.status(404).sendFile(path.join(publicPath, "404.html"))); app.use((_req, res) => res.status(404).sendFile(path.join(publicPath, "404.html")));
const server = createServer(app); const server = createServer(app);
server.keepAliveTimeout = 0; server.keepAliveTimeout = 5000;
server.headersTimeout = 0; server.headersTimeout = 10000;
const pingWSS = new WebSocket.Server({ const pingWSS = new WebSocket.Server({
noServer: true, noServer: true,
maxPayload: 4 * 1024 * 1024, maxPayload: 16384,
perMessageDeflate: false perMessageDeflate: false
}); });
pingWSS.on("connection", (ws, req) => { pingWSS.on("connection", (ws, req) => {
const remote = req.socket.remoteAddress || "unknown"; const remote = req.socket.remoteAddress || "unknown";
let lat = []; const lat = [];
const interval = setInterval(() => { let sampleIndex = 0;
const sendPing = () => {
if (ws.readyState === WebSocket.OPEN) { if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: "ping", timestamp: Date.now() })); ws.send(JSON.stringify({ type: "ping", timestamp: Date.now() }));
} }
}, 1000); };
const pingInterval = setInterval(sendPing, 500);
sendPing();
ws.on("message", msg => { ws.on("message", msg => {
try { try {
@ -220,39 +182,36 @@ if (cluster.isPrimary) {
if (data.type === "pong" && data.timestamp) { if (data.type === "pong" && data.timestamp) {
const d = Date.now() - data.timestamp; const d = Date.now() - data.timestamp;
lat.push(d); lat.push(d);
if (lat.length > 5) lat.shift(); if (lat.length > 10) lat.shift();
latencySamples.push(d);
if (latencySamples.length > 100) latencySamples.shift(); latencySamples[sampleIndex % latencySamples.length] = d;
ws.send(JSON.stringify({ type: "latency", latency: d })); sampleIndex = (sampleIndex + 1) % latencySamples.length;
ws.send(JSON.stringify({ type: "latency", latency: d }), { compress: false });
} }
} catch (e) { } catch {}
logError(`Ping error: ${e}`);
}
}); });
ws.on("close", () => { ws.on("close", () => {
clearInterval(interval); clearInterval(pingInterval);
const avg = lat.length const avg = lat.length ? (lat.reduce((a, b) => a + b) / lat.length).toFixed(2) : 0;
? (lat.reduce((a, b) => a + b) / lat.length).toFixed(2)
: 0;
logInfo(`WS ${remote} closed. Avg: ${avg}ms`); logInfo(`WS ${remote} closed. Avg: ${avg}ms`);
}); });
}); });
server.on("upgrade", (req, sock, head) => { server.on("upgrade", (req, sock, head) => {
if (req.url === "/w/ping") { if (req.url === "/w/ping") {
pingWSS.handleUpgrade(req, sock, head, ws => pingWSS.handleUpgrade(req, sock, head, ws =>
pingWSS.emit("connection", ws, req) pingWSS.emit("connection", ws, req)
); );
} else if (req.url.startsWith("/w/")) { } else if (req.url.startsWith("/w/")) {
wisp.routeRequest(req, sock, head); wisp.routeRequest(req, sock, head);
} else { } else {
sock.end(); sock.destroy();
} }
}); });
server.on("error", err => logError(`Worker error: ${err}`)); server.on("error", err => logError(`Worker error: ${err}`));
server.listen(0, () => logSuccess(`Worker ${process.pid} ready`)); server.listen(0, () => logSuccess(`Worker ${process.pid} ready`));
process.on("message", (msg, conn) => { process.on("message", (msg, conn) => {

View File

@ -114,10 +114,10 @@
</div> </div>
</div> </div>
<div id="pingDisplay"><i class="fa-regular fa-wifi"></i> Ping: Connecting...</div> <div id="pingDisplay"><i class="fas fa-satellite-dish"></i> Ping: Connecting...</div>
<div id="greeting"></div> <div id="greeting"></div>
<iframe id="cool-iframe" class="iframe"></iframe> <iframe id="cool-iframe" class="iframe"></iframe>
<div id="lastest-commit">Loading latest commit</div> <div id="hi">Hii,</div>
<div id="copyright"> <div id="copyright">
<i class="fa-regular fa-copyright"></i> 2025 <i class="fa-regular fa-copyright"></i> 2025

View File

@ -55,7 +55,7 @@ body {
color: #ffffff; color: #ffffff;
display: inline-block; display: inline-block;
text-align: left; text-align: left;
margin: 1px 80px 0 10px; margin: 1px 75px 0 10px;
white-space: nowrap; white-space: nowrap;
cursor: default; cursor: default;
transition: all 0.3s ease; transition: all 0.3s ease;
@ -88,7 +88,7 @@ body {
.home-navbar .favicon { .home-navbar .favicon {
width: 28px; width: 28px;
height: 24px; height: 24px;
margin-right: -10px; margin-right: -9px;
vertical-align: middle; vertical-align: middle;
} }
@ -114,8 +114,8 @@ body {
.home-navbar i { .home-navbar i {
color: #ffffff; color: #ffffff;
margin-right: -15px; margin-right: -19px;
margin-left: 115px; margin-left: 119px;
} }
.navbar { .navbar {
@ -590,14 +590,14 @@ body {
animation: fadeOut 0.3s ease-in-out forwards; animation: fadeOut 0.3s ease-in-out forwards;
} }
#lastest-commit { #hi {
position: fixed; position: fixed;
bottom: 10px; bottom: 10px;
left: 10px; left: 10px;
z-index: 9999; z-index: 9999;
background-color: #08080894; background-color: #08080894;
border: 1px solid #ffffff21; border: 1px solid #ffffff21;
color: #cfcfcf; color: #aaaaaa;
font-weight: 540; font-weight: 540;
transition: all 0.3s ease; transition: all 0.3s ease;
cursor: default; cursor: default;
@ -606,6 +606,10 @@ body {
font-size: 14px; font-size: 14px;
} }
#hi:hover {
color: #ffffff;
}
#copyright { #copyright {
position: fixed; position: fixed;
bottom: 10px; bottom: 10px;

View File

@ -141,6 +141,14 @@ document.addEventListener('DOMContentLoaded', () => {
updateDecodedSearchInput(); updateDecodedSearchInput();
} }
function generateSubject() {
const subjects = ['math', 'science', 'history', 'art', 'programming', 'philosophy'];
const randomSubject = subjects[Math.floor(Math.random() * subjects.length)];
try {
history.replaceState({}, '', `/learning?subject=${randomSubject}`);
} catch (e) {}
}
function setupIframeNavigationListeners() { function setupIframeNavigationListeners() {
try { try {
const iframeWindow = iframe.contentWindow; const iframeWindow = iframe.contentWindow;
@ -209,6 +217,7 @@ document.addEventListener('DOMContentLoaded', () => {
} }
} }
setupIframeNavigationListeners(); setupIframeNavigationListeners();
generateSubject();
if (navbarToggle && navbarToggle.checked && navBar) { if (navbarToggle && navbarToggle.checked && navBar) {
navBar.style.display = 'block'; navBar.style.display = 'block';
} }
@ -466,20 +475,4 @@ document.addEventListener('DOMContentLoaded', () => {
window.APP.decodeUrl = decodeUrl; window.APP.decodeUrl = decodeUrl;
window.APP.normalizeUrl = normalizeUrl; window.APP.normalizeUrl = normalizeUrl;
}); });
(async () => {
try {
const res = await fetch('/api/latest-commit');
const {
updates
} = await res.json();
const u = updates[0];
const commitUrl = `https://github.com/xojw/waves/commit/${u.sha}`;
document.getElementById('lastest-commit').innerHTML =
`<a href="${commitUrl}" class="hover-link" target="_blank" rel="noopener noreferrer"><i class="fa-solid fa-code-commit"></i> ${u.sha}</a>`;
} catch {
document.getElementById('lastest-commit').textContent =
'Failed to load lastest commit';
}
})();

View File

@ -1,6 +1,7 @@
window.onload = function() { window.onload = function() {
const storedName = localStorage.getItem('userName'); const storedName = localStorage.getItem('userName');
const path = window.location.pathname; const path = window.location.pathname;
if (!storedName) { if (!storedName) {
document.getElementById('overlay').style.display = 'block'; document.getElementById('overlay').style.display = 'block';
document.getElementById('namePrompt').style.display = 'block'; document.getElementById('namePrompt').style.display = 'block';
@ -12,20 +13,27 @@ window.onload = function() {
}); });
return; return;
} }
const welcomeMsg = getWelcomeMessage(storedName); const welcomeMsg = getWelcomeMessage(storedName);
const iconType = getIconType(path); const iconType = getIconType(path);
showToast(welcomeMsg, 'success', iconType); showToast(welcomeMsg, 'success', iconType);
const greetingElement = document.getElementById('greeting'); const greetingElement = document.getElementById('greeting');
if (greetingElement) { if (greetingElement) {
updateGreeting(storedName); updateGreeting(storedName);
} }
updateHi(storedName);
}; };
function submitName() { function submitName() {
const name = document.getElementById('userName').value.trim(); const name = document.getElementById('userName').value.trim();
if (!name) return; if (!name) return;
localStorage.setItem('userName', name); localStorage.setItem('userName', name);
updateGreeting(name); updateGreeting(name);
updateHi(name);
document.getElementById('namePrompt').classList.add('fade-out'); document.getElementById('namePrompt').classList.add('fade-out');
showToast(`Hey, ${name}! Welcome to Waves!`, 'success', 'wave'); showToast(`Hey, ${name}! Welcome to Waves!`, 'success', 'wave');
setTimeout(() => { setTimeout(() => {
@ -52,8 +60,7 @@ function getIconType(path) {
} }
const generalGreetings = [ const generalGreetings = [
{ text: 'Welcome aboard', icon: '<i class="fa-regular fa-rocket"></i>', suffix: '!' }, { text: 'Have fun', icon: '<i class="fa-regular fa-party-horn"></i>', suffix: '!' },
{ text: 'Hii', icon: '<i class="fa-regular fa-hand-wave"></i>', suffix: '!!' },
{ text: 'Hope you enjoy Waves', icon: '<i class="fa-solid fa-heart"></i>', suffix: ' <3' }, { text: 'Hope you enjoy Waves', icon: '<i class="fa-solid fa-heart"></i>', suffix: ' <3' },
{ text: 'Consider joining our Discord (discord.gg/ire)', icon: '<i class="fa-solid fa-smile"></i>', suffix: '!' }, { text: 'Consider joining our Discord (discord.gg/ire)', icon: '<i class="fa-solid fa-smile"></i>', suffix: '!' },
{ text: 'How you doing today', icon: '<i class="fa-regular fa-question"></i>', suffix: '?' } { text: 'How you doing today', icon: '<i class="fa-regular fa-question"></i>', suffix: '?' }
@ -67,21 +74,18 @@ timeGreetings.push(
{ text: 'Enjoy your morning', icon: '<i class="fa-regular fa-mug-hot"></i>', suffix: '!' }, { text: 'Enjoy your morning', icon: '<i class="fa-regular fa-mug-hot"></i>', suffix: '!' },
{ text: 'Your day starts here', icon: '<i class="fa-regular fa-star"></i>', suffix: '!' } { text: 'Your day starts here', icon: '<i class="fa-regular fa-star"></i>', suffix: '!' }
); );
timeGreetings.push( timeGreetings.push(
{ text: 'Good afternoon', icon: '<i class="fa-regular fa-leaf"></i>', suffix: '!' }, { text: 'Good afternoon', icon: '<i class="fa-regular fa-leaf"></i>', suffix: '!' },
{ text: 'Hope your day is going well', icon: '<i class="fa-regular fa-coffee"></i>', suffix: '.' }, { text: 'Hope your day is going well', icon: '<i class="fa-regular fa-coffee"></i>', suffix: '.' },
{ text: 'Keep up the pace', icon: '<i class="fa-regular fa-book"></i>', suffix: '!' }, { text: 'Keep up the pace', icon: '<i class="fa-regular fa-book"></i>', suffix: '!' },
{ text: 'Stay on track today', icon: '<i class="fa-regular fa-sun"></i>', suffix: '.' } { text: 'Stay on track today', icon: '<i class="fa-regular fa-sun"></i>', suffix: '.' }
); );
timeGreetings.push( timeGreetings.push(
{ text: 'Good evening', icon: '<i class="fa-regular fa-cloud-moon"></i>', suffix: '!' }, { text: 'Good evening', icon: '<i class="fa-regular fa-cloud-moon"></i>', suffix: '!' },
{ text: 'Time to unwind', icon: '<i class="fa-regular fa-fire"></i>', suffix: '.' }, { text: 'Time to unwind', icon: '<i class="fa-regular fa-fire"></i>', suffix: '.' },
{ text: 'Evenings here—relax', icon: '<i class="fa-regular fa-star"></i>', suffix: '.' }, { text: 'Evenings here—relax', icon: '<i class="fa-regular fa-star"></i>', suffix: '.' },
{ text: 'Breathe and recharge', icon: '<i class="fa-regular fa-moon"></i>', suffix: '…' } { text: 'Breathe and recharge', icon: '<i class="fa-regular fa-moon"></i>', suffix: '…' }
); );
timeGreetings.push( timeGreetings.push(
{ text: 'Good night', icon: '<i class="fa-regular fa-bed"></i>', suffix: '!' }, { text: 'Good night', icon: '<i class="fa-regular fa-bed"></i>', suffix: '!' },
{ text: 'Rest well', icon: '<i class="fa-regular fa-blanket"></i>', suffix: '.' }, { text: 'Rest well', icon: '<i class="fa-regular fa-blanket"></i>', suffix: '.' },
@ -93,6 +97,7 @@ function getGreeting() {
const now = new Date(); const now = new Date();
const hour = now.getHours(); const hour = now.getHours();
let pool = []; let pool = [];
if (hour >= 5 && hour < 12) { if (hour >= 5 && hour < 12) {
pool = timeGreetings.slice(0, 4); pool = timeGreetings.slice(0, 4);
} else if (hour < 17) { } else if (hour < 17) {
@ -102,41 +107,50 @@ function getGreeting() {
} else { } else {
pool = timeGreetings.slice(12, 16); pool = timeGreetings.slice(12, 16);
} }
if (Math.random() < 0.5) { if (Math.random() < 0.5) {
pool = generalGreetings; pool = generalGreetings;
} }
const choice = pool[Math.floor(Math.random() * pool.length)];
return { text: choice.text, icon: choice.icon, suffix: choice.suffix }; return pool[Math.floor(Math.random() * pool.length)];
} }
function updateGreeting(name) { function updateGreeting(name) {
const { text, icon, suffix } = getGreeting(); const { text, icon, suffix } = getGreeting();
const el = document.getElementById('greeting'); const el = document.getElementById('greeting');
if (!el) return; if (!el) return;
if (text === 'Hope you enjoy Waves') {
el.innerHTML = `${icon} ${text}, ${name}${suffix}`; el.innerHTML = `${icon} ${text}, ${name}${suffix}`;
} else {
el.innerHTML = `${icon} ${text}, ${name}${suffix}`;
}
el.style.opacity = 1; el.style.opacity = 1;
} }
function updateHi(name) {
const hiEl = document.getElementById('hi');
if (hiEl) {
hiEl.textContent = `Hii, ${name}!!`;
}
}
function showToast(message, type = 'success', iconType = 'wave') { function showToast(message, type = 'success', iconType = 'wave') {
const toast = document.createElement('div'); const toast = document.createElement('div');
toast.className = `toast show ${type}`; toast.className = `toast show ${type}`;
const icons = { const icons = {
success: '<i class="fas fa-check-circle" style="margin-right: 8px;"></i>', success: '<i class="fas fa-check-circle" style="margin-right: 8px;"></i>',
error: '<i class="fas fa-times-circle" style="margin-right: 8px;"></i>', error: '<i class="fas fa-times-circle" style="margin-right: 8px;"></i>',
info: '<i class="fas fa-info-circle" style="margin-right: 8px;"></i>', info: '<i class="fas fa-info-circle" style="margin-right: 8px;"></i>',
warning: '<i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>', warning: '<i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>',
wave: '<i class="fa-regular fa-hand-wave" style="margin-right: 8px;"></i>', wave: '<i class="fa-regular fa-hand-wave" style="margin-right: 8px;"></i>',
game: '<i class="fa-regular fa-gamepad" style="margin-right: 8px;"></i>', game: '<i class="fa-regular fa-gamepad" style="margin-right: 8px;"></i>',
apps: '<i class="fa-regular fa-th" style="margin-right: 8px;"></i>' apps: '<i class="fa-regular fa-th" style="margin-right: 8px;"></i>'
}; };
toast.innerHTML = `${icons[iconType] || icons.wave}${message}`; toast.innerHTML = `${icons[iconType] || icons.wave}${message}`;
const progressBar = document.createElement('div'); const progressBar = document.createElement('div');
progressBar.className = 'progress-bar'; progressBar.className = 'progress-bar';
toast.appendChild(progressBar); toast.appendChild(progressBar);
const closeBtn = document.createElement('button'); const closeBtn = document.createElement('button');
closeBtn.className = 'toast-close'; closeBtn.className = 'toast-close';
closeBtn.innerHTML = '<i class="fas fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>'; closeBtn.innerHTML = '<i class="fas fa-xmark" style="margin-left: 8px; font-size: 0.8em;"></i>';
@ -145,7 +159,9 @@ function showToast(message, type = 'success', iconType = 'wave') {
setTimeout(() => toast.remove(), 500); setTimeout(() => toast.remove(), 500);
}); });
toast.appendChild(closeBtn); toast.appendChild(closeBtn);
document.body.appendChild(toast); document.body.appendChild(toast);
setTimeout(() => { setTimeout(() => {
toast.classList.add('hide'); toast.classList.add('hide');
setTimeout(() => toast.remove(), 500); setTimeout(() => toast.remove(), 500);

View File

@ -10,7 +10,7 @@
ws = new WebSocket(wsUrl); ws = new WebSocket(wsUrl);
ws.onopen = function() { ws.onopen = function() {
pingDisplay.innerHTML = '<i class="fas fa-wifi"></i> Ping: Waiting...'; pingDisplay.innerHTML = '<i class="fas fa-satellite-dish"></i> Ping: Waiting...';
}; };
ws.onmessage = function(event) { ws.onmessage = function(event) {
@ -23,7 +23,7 @@
})); }));
} }
if (data.type === "latency" && typeof data.latency === "number") { if (data.type === "latency" && typeof data.latency === "number") {
pingDisplay.innerHTML = '<i class="fa-solid fa-wifi"></i> Ping: ' + '~' + data.latency + 'ms'; pingDisplay.innerHTML = '<i class="fas fa-satellite-dish"></i> ' + 'Ping: ' + '~' + data.latency + 'ms';
} }
} catch (err) { } catch (err) {
console.error("Error parsing message:", err); console.error("Error parsing message:", err);
@ -31,11 +31,11 @@
}; };
ws.onerror = function() { ws.onerror = function() {
pingDisplay.innerHTML = '<i class="fa-regular fa-wifi"></i> Ping: Error'; pingDisplay.innerHTML = '<i class="fas fa-satellite-dish"></i> Ping: Error';
}; };
ws.onclose = function() { ws.onclose = function() {
pingDisplay.innerHTML = '<i class="fa-regular fa-wifi"></i> Ping: Disconnected'; pingDisplay.innerHTML = '<i class="fas fa-satellite-dish"></i> Ping: Disconnected';
setTimeout(createWebSocket, 1000); setTimeout(createWebSocket, 1000);
}; };
} }