From 9e7000054b47e719cb67ee2cd5d61203475d9278 Mon Sep 17 00:00:00 2001 From: ducklet Date: Tue, 2 Feb 2021 21:02:30 +0100 Subject: [PATCH] fix connection time syncing handling Share the time syncing code, and while we're at it wrap the whole connection thing in a class. Makes it easier to pass the connection around & later on add more advanced handler registration if we want to. --- public/buzzer.js | 110 +++++++++++++++++++++------------------------- public/monitor.js | 73 ++++++++++++------------------ public/shared.js | 61 ++++++++++++++++++++++--- 3 files changed, 132 insertions(+), 112 deletions(-) diff --git a/public/buzzer.js b/public/buzzer.js index 04e8111..2f4dd6d 100644 --- a/public/buzzer.js +++ b/public/buzzer.js @@ -12,6 +12,7 @@ const storage = window.sessionStorage import { clear, + Connection, isEmpty, isString, ms_ns, @@ -20,7 +21,6 @@ import { on, q, s_ns, - servertime_now_ns, session_id, session_id_from_url, session_url, @@ -32,8 +32,7 @@ const buzzer_key = { } let socket, - servertime, - toffset_ms, + conn, clients = [], me, session_key @@ -66,11 +65,6 @@ function setup_url() { location.hash = sid } -function send(type, value) { - // console.debug('sending', value) - socket.send(JSON.stringify({ type, value })) -} - const player_list = q("#info ul") function redraw_clients(me, clients) { if (!me) { @@ -98,7 +92,7 @@ function highlight(client_id, until_ns) { if (highlights[client_id]) { return } - const timeout_ms = (until_ns - servertime_now_ns()) / ms_ns + const timeout_ms = (until_ns - conn.servertime_now_ns()) / ms_ns if (timeout_ms <= 10) { console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms) return @@ -144,7 +138,7 @@ function setup_ui() { on("keydown", (event) => { if (!buzzing && event.keyCode === buzzer_key.code) { buzzing = true - send("buzz", servertime_now_ns()) + conn.send("buzz", conn.servertime_now_ns()) show("active") hide("ready") } @@ -220,66 +214,62 @@ function enable_admin_ui() { function set_name(name) { storage["my_name"] = name - send("name", name) + conn.send("name", name) } function setup_ws() { const sid = session_id() const credentials = { id: storage["my_uid"], key: storage["my_key"] } - socket = new WebSocket(session_url(sid)) - socket.addEventListener("open", function (event) { + conn = new Connection() + conn.on("helo", () => { if (sid === storage["my_sid"]) { - send("login", credentials) + conn.send("login", credentials) } set_name(q("#username").value) }) - socket.addEventListener("message", function (event) { - const msg = JSON.parse(event.data) - const { type, value } = msg - if (type === "time") { - servertime = value.time - toffset_ms = performance.now() - } else if (type === "id") { - me = value - storage["my_uid"] = me.id - storage["my_key"] = me.key - storage["my_sid"] = session_id_from_url(me.path) - redraw_clients(me, clients) - } else if (type === "session_key") { - session_key = value - storage["session_path"] = session_key.path - storage["session_key"] = session_key.key - disable_player_ui() - enable_admin_ui() - } else if (type === "buzz") { - const buzztime_ns = value.time - const client_id = value.client - const duration_ns = 3 * s_ns - const until_ns = buzztime_ns + duration_ns - highlight(client_id, until_ns) - } else if (type === "clients") { - clients = value.clients - redraw_clients(me, clients) - } else if (type === "client") { - const client = value.client - const idx = clients.findIndex((c) => c.id === client.id) - if (idx >= 0) { - clients[idx] = client - } else { - clients.push(client) - } - redraw_clients(me, clients) - } else if (type === "control") { - // ignore - } else if (type === "error") { - console.error(`Error: ${value.reason}`) - const errorbox = q("#error") - q("code", errorbox).textContent = JSON.stringify(msg, null, 2) - q("body").classList.add("error") - } else { - console.error(`Unknown message: ${event.data}`) - } + conn.on("id", ({ value }) => { + me = value + storage["my_uid"] = me.id + storage["my_key"] = me.key + storage["my_sid"] = session_id_from_url(me.path) + redraw_clients(me, clients) }) + conn.on("buzz", ({ value }) => { + const { time: buzztime_ns, client: client_id } = value + const duration_ns = 3 * s_ns + const until_ns = buzztime_ns + duration_ns + highlight(client_id, until_ns) + }) + conn.on("clients", ({ value }) => { + clients = value.clients + redraw_clients(me, clients) + }) + conn.on("client", ({ value: { client } }) => { + const idx = clients.findIndex((c) => c.id === client.id) + if (idx >= 0) { + clients[idx] = client + } else { + clients.push(client) + } + redraw_clients(me, clients) + }) + conn.on("session_key", ({ value }) => { + session_key = value + storage["session_path"] = session_key.path + storage["session_key"] = session_key.key + disable_player_ui() + enable_admin_ui() + }) + conn.on("control", ({ value }) => { + // ignore + }) + conn.on("error", (msg) => { + console.error(`Error: ${msg.value.reason}`) + const errorbox = q("#error") + q("code", errorbox).textContent = JSON.stringify(msg, null, 2) + q("body").classList.add("error") + }) + conn.connect(session_url(sid)) } setup_url() diff --git a/public/monitor.js b/public/monitor.js index afdb1c6..844476d 100644 --- a/public/monitor.js +++ b/public/monitor.js @@ -6,18 +6,16 @@ const performance = window.performance import { clear, + Connection, ms_ns, node, q, s_ns, - servertime_now_ns, session_id, session_url, } from "./shared.js" -let socket, - servertime, - toffset_ms, +let conn, clients = {}, me @@ -26,11 +24,6 @@ function setup_url() { 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 = [] @@ -84,7 +77,7 @@ function redraw_clients(me, clients) { 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) + q(".tokens", player_el).textContent = "🔴 ".repeat(c.tokens) } } @@ -93,7 +86,7 @@ function highlight(client_id, until_ns) { if (highlighted) { return } - const timeout_ms = (until_ns - servertime_now_ns()) / ms_ns + const timeout_ms = (until_ns - conn.servertime_now_ns()) / ms_ns if (timeout_ms <= 10) { console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms) return @@ -113,42 +106,32 @@ function highlight(client_id, until_ns) { function setup_ws() { const sid = session_id() - socket = new WebSocket(session_url(sid)) - socket.addEventListener("open", function (event) { - send("name", "Monitor") + conn = new Connection() + conn.on("helo", () => { + conn.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}`) - } + conn.on("id", ({ value }) => { + me = value + redraw_clients(me, clients) }) + conn.on("buzz", ({ value }) => { + const { time: buzztime_ns, client: client_id } = value + const duration_ns = 12 * s_ns + const until_ns = buzztime_ns + duration_ns + highlight(client_id, until_ns) + }) + conn.on("clients", ({ value }) => { + clients = Object.fromEntries(value.clients.map((c) => [c.id, c])) + redraw_clients(me, clients) + }) + conn.on("client", ({ value: { client } }) => { + clients[client.id] = client + redraw_clients(me, clients) + }) + conn.on("control", ({ value }) => { + // ... + }) + conn.connect(session_url(sid)) } setup_url() diff --git a/public/shared.js b/public/shared.js index 18257d3..882dcc5 100644 --- a/public/shared.js +++ b/public/shared.js @@ -105,11 +105,58 @@ export function session_id() { return match ? match[1] : null } -/** - * Guess the exact current server time. - */ -export function servertime_now_ns() { - const now_ms = performance.now() - const delta_ns = ms_ns * (now_ms - toffset_ms) - return servertime + delta_ns +export class Connection { + constructor() { + this.socket = null + this.toffset_ms = null + this.servertime = null + this.handlers = { + time: this._handler_time.bind(this), + error: this._handler_error.bind(this), + } + } + + _handler_time({ value: { time } }) { + this.servertime = time + this.toffset_ms = performance.now() + } + + _handler_error({ value: { reason } }) { + console.error(`Error: ${reason}`) + } + + connect(url) { + this.socket = new WebSocket(url) + this.socket.addEventListener("open", (event) => { + if ("helo" in this.handlers) { + this.handlers["helo"](event) + } + }) + this.socket.addEventListener("message", (event) => { + const msg = JSON.parse(event.data) + if (msg.type in this.handlers) { + this.handlers[msg.type](msg) + } else { + console.error(`Unhandled message: ${event.data}`) + } + }) + } + + on(type, callback) { + this.handlers[type] = callback + } + + /** + * Guess the exact current server time. + */ + servertime_now_ns() { + const now_ms = performance.now() + const delta_ns = ms_ns * (now_ms - this.toffset_ms) + return this.servertime + delta_ns + } + + send(type, value) { + // console.debug('sending', value) + this.socket.send(JSON.stringify({ type, value })) + } }