"use strict" /* global document, window */ const location = document.location const performance = window.performance import { clear, ms_ns, node, q, s_ns, servertime_now_ns, session_id, session_url, } from "./shared.js" let socket, servertime, toffset_ms, clients = {}, me function setup_url() { const sid = session_id() || "" location.hash = sid } function send(type, value) { // console.debug('sending', value) socket.send(JSON.stringify({ type, value })) } function prettynum(n) { let i = Math.abs(n) | 0 let s = [] while (true) { const m = i % 1000 i = (i / 1000) | 0 if (i === 0) { s.unshift(String(m)) break } else { s.unshift(String(m).padStart(3, "0")) } } return (n < 0 ? "-" : "") + s.join("'") } function assert(expected, got) { if (expected !== got) { throw Error("Assertion failed.") } } function test_prettynum() { assert("0", prettynum(0)) assert("1", prettynum(1)) assert("1'000", prettynum(1000)) assert("36'000", prettynum(36000)) assert("0", prettynum(-0)) assert("-1", prettynum(-1)) assert("-1'000", prettynum(-1000)) assert("-36'000", prettynum(-36000)) assert("-36'600", prettynum(-36600)) } test_prettynum() const player_list = q("#info") function redraw_clients(me, clients) { if (!me) { return } clear(player_list) const player_tpl = q("template#player").content.firstElementChild for (const c of Object.values(clients)) { if (c.id === me.id) { continue } const player_el = node(player_tpl.cloneNode(true), { data: { cid: c.id }, appendTo: player_list, }) q(".name", player_el).textContent = c.name q(".points.fg", player_el).textContent = prettynum(c.points) q(".points.bg", player_el).textContent = prettynum(c.points) q(".tokens", player_el).textContent = '🔴 '.repeat(c.tokens) } } let highlighted = false function highlight(client_id, until_ns) { if (highlighted) { return } const timeout_ms = (until_ns - servertime_now_ns()) / ms_ns if (timeout_ms <= 10) { console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms) return } for (const li of player_list.children) { if (li.dataset.cid === client_id) { li.classList.add("buzzing") highlighted = true setTimeout(() => { highlighted = false li.classList.remove("buzzing") }, timeout_ms) return } } } function setup_ws() { const sid = session_id() socket = new WebSocket(session_url(sid)) socket.addEventListener("open", function (event) { send("name", "Monitor") }) socket.addEventListener("message", function (event) { const msg = JSON.parse(event.data) const { type, value } = msg if (msg.type === "time") { servertime = value.time toffset_ms = performance.now() } else if (msg.type === "id") { me = value redraw_clients(me, clients) } else if (msg.type === "buzz") { const buzztime_ns = value.time const client_id = value.client const duration_ns = 12 * s_ns const until_ns = buzztime_ns + duration_ns highlight(client_id, until_ns) } else if (msg.type === "clients") { clients = Object.fromEntries(value.clients.map((c) => [c.id, c])) redraw_clients(me, clients) } else if (msg.type === "client") { const client = value.client clients[client.id] = client redraw_clients(me, clients) } else if (type === "control") { // ignore } else if (type === "session_key") { // ignore } else if (type === "error") { console.error(`Error: ${value.reason}`) } else { console.error(`Unknown message: ${event.data}`) } }) } setup_url() setup_ws()