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.
This commit is contained in:
parent
f900542765
commit
9e7000054b
3 changed files with 132 additions and 112 deletions
|
|
@ -12,6 +12,7 @@ const storage = window.sessionStorage
|
||||||
|
|
||||||
import {
|
import {
|
||||||
clear,
|
clear,
|
||||||
|
Connection,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
isString,
|
isString,
|
||||||
ms_ns,
|
ms_ns,
|
||||||
|
|
@ -20,7 +21,6 @@ import {
|
||||||
on,
|
on,
|
||||||
q,
|
q,
|
||||||
s_ns,
|
s_ns,
|
||||||
servertime_now_ns,
|
|
||||||
session_id,
|
session_id,
|
||||||
session_id_from_url,
|
session_id_from_url,
|
||||||
session_url,
|
session_url,
|
||||||
|
|
@ -32,8 +32,7 @@ const buzzer_key = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let socket,
|
let socket,
|
||||||
servertime,
|
conn,
|
||||||
toffset_ms,
|
|
||||||
clients = [],
|
clients = [],
|
||||||
me,
|
me,
|
||||||
session_key
|
session_key
|
||||||
|
|
@ -66,11 +65,6 @@ function setup_url() {
|
||||||
location.hash = sid
|
location.hash = sid
|
||||||
}
|
}
|
||||||
|
|
||||||
function send(type, value) {
|
|
||||||
// console.debug('sending', value)
|
|
||||||
socket.send(JSON.stringify({ type, value }))
|
|
||||||
}
|
|
||||||
|
|
||||||
const player_list = q("#info ul")
|
const player_list = q("#info ul")
|
||||||
function redraw_clients(me, clients) {
|
function redraw_clients(me, clients) {
|
||||||
if (!me) {
|
if (!me) {
|
||||||
|
|
@ -98,7 +92,7 @@ function highlight(client_id, until_ns) {
|
||||||
if (highlights[client_id]) {
|
if (highlights[client_id]) {
|
||||||
return
|
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) {
|
if (timeout_ms <= 10) {
|
||||||
console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms)
|
console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms)
|
||||||
return
|
return
|
||||||
|
|
@ -144,7 +138,7 @@ function setup_ui() {
|
||||||
on("keydown", (event) => {
|
on("keydown", (event) => {
|
||||||
if (!buzzing && event.keyCode === buzzer_key.code) {
|
if (!buzzing && event.keyCode === buzzer_key.code) {
|
||||||
buzzing = true
|
buzzing = true
|
||||||
send("buzz", servertime_now_ns())
|
conn.send("buzz", conn.servertime_now_ns())
|
||||||
show("active")
|
show("active")
|
||||||
hide("ready")
|
hide("ready")
|
||||||
}
|
}
|
||||||
|
|
@ -220,48 +214,37 @@ function enable_admin_ui() {
|
||||||
|
|
||||||
function set_name(name) {
|
function set_name(name) {
|
||||||
storage["my_name"] = name
|
storage["my_name"] = name
|
||||||
send("name", name)
|
conn.send("name", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup_ws() {
|
function setup_ws() {
|
||||||
const sid = session_id()
|
const sid = session_id()
|
||||||
const credentials = { id: storage["my_uid"], key: storage["my_key"] }
|
const credentials = { id: storage["my_uid"], key: storage["my_key"] }
|
||||||
socket = new WebSocket(session_url(sid))
|
conn = new Connection()
|
||||||
socket.addEventListener("open", function (event) {
|
conn.on("helo", () => {
|
||||||
if (sid === storage["my_sid"]) {
|
if (sid === storage["my_sid"]) {
|
||||||
send("login", credentials)
|
conn.send("login", credentials)
|
||||||
}
|
}
|
||||||
set_name(q("#username").value)
|
set_name(q("#username").value)
|
||||||
})
|
})
|
||||||
socket.addEventListener("message", function (event) {
|
conn.on("id", ({ value }) => {
|
||||||
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
|
me = value
|
||||||
storage["my_uid"] = me.id
|
storage["my_uid"] = me.id
|
||||||
storage["my_key"] = me.key
|
storage["my_key"] = me.key
|
||||||
storage["my_sid"] = session_id_from_url(me.path)
|
storage["my_sid"] = session_id_from_url(me.path)
|
||||||
redraw_clients(me, clients)
|
redraw_clients(me, clients)
|
||||||
} else if (type === "session_key") {
|
})
|
||||||
session_key = value
|
conn.on("buzz", ({ value }) => {
|
||||||
storage["session_path"] = session_key.path
|
const { time: buzztime_ns, client: client_id } = value
|
||||||
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 duration_ns = 3 * s_ns
|
||||||
const until_ns = buzztime_ns + duration_ns
|
const until_ns = buzztime_ns + duration_ns
|
||||||
highlight(client_id, until_ns)
|
highlight(client_id, until_ns)
|
||||||
} else if (type === "clients") {
|
})
|
||||||
|
conn.on("clients", ({ value }) => {
|
||||||
clients = value.clients
|
clients = value.clients
|
||||||
redraw_clients(me, clients)
|
redraw_clients(me, clients)
|
||||||
} else if (type === "client") {
|
})
|
||||||
const client = value.client
|
conn.on("client", ({ value: { client } }) => {
|
||||||
const idx = clients.findIndex((c) => c.id === client.id)
|
const idx = clients.findIndex((c) => c.id === client.id)
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
clients[idx] = client
|
clients[idx] = client
|
||||||
|
|
@ -269,17 +252,24 @@ function setup_ws() {
|
||||||
clients.push(client)
|
clients.push(client)
|
||||||
}
|
}
|
||||||
redraw_clients(me, clients)
|
redraw_clients(me, clients)
|
||||||
} else if (type === "control") {
|
})
|
||||||
|
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
|
// ignore
|
||||||
} else if (type === "error") {
|
})
|
||||||
console.error(`Error: ${value.reason}`)
|
conn.on("error", (msg) => {
|
||||||
|
console.error(`Error: ${msg.value.reason}`)
|
||||||
const errorbox = q("#error")
|
const errorbox = q("#error")
|
||||||
q("code", errorbox).textContent = JSON.stringify(msg, null, 2)
|
q("code", errorbox).textContent = JSON.stringify(msg, null, 2)
|
||||||
q("body").classList.add("error")
|
q("body").classList.add("error")
|
||||||
} else {
|
|
||||||
console.error(`Unknown message: ${event.data}`)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
conn.connect(session_url(sid))
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_url()
|
setup_url()
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,16 @@ const performance = window.performance
|
||||||
|
|
||||||
import {
|
import {
|
||||||
clear,
|
clear,
|
||||||
|
Connection,
|
||||||
ms_ns,
|
ms_ns,
|
||||||
node,
|
node,
|
||||||
q,
|
q,
|
||||||
s_ns,
|
s_ns,
|
||||||
servertime_now_ns,
|
|
||||||
session_id,
|
session_id,
|
||||||
session_url,
|
session_url,
|
||||||
} from "./shared.js"
|
} from "./shared.js"
|
||||||
|
|
||||||
let socket,
|
let conn,
|
||||||
servertime,
|
|
||||||
toffset_ms,
|
|
||||||
clients = {},
|
clients = {},
|
||||||
me
|
me
|
||||||
|
|
||||||
|
|
@ -26,11 +24,6 @@ function setup_url() {
|
||||||
location.hash = sid
|
location.hash = sid
|
||||||
}
|
}
|
||||||
|
|
||||||
function send(type, value) {
|
|
||||||
// console.debug('sending', value)
|
|
||||||
socket.send(JSON.stringify({ type, value }))
|
|
||||||
}
|
|
||||||
|
|
||||||
function prettynum(n) {
|
function prettynum(n) {
|
||||||
let i = Math.abs(n) | 0
|
let i = Math.abs(n) | 0
|
||||||
let s = []
|
let s = []
|
||||||
|
|
@ -84,7 +77,7 @@ function redraw_clients(me, clients) {
|
||||||
q(".name", player_el).textContent = c.name
|
q(".name", player_el).textContent = c.name
|
||||||
q(".points.fg", player_el).textContent = prettynum(c.points)
|
q(".points.fg", player_el).textContent = prettynum(c.points)
|
||||||
q(".points.bg", 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) {
|
if (highlighted) {
|
||||||
return
|
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) {
|
if (timeout_ms <= 10) {
|
||||||
console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms)
|
console.warn("That highlight timeout was ridiculously low:", client_id, timeout_ms)
|
||||||
return
|
return
|
||||||
|
|
@ -113,42 +106,32 @@ function highlight(client_id, until_ns) {
|
||||||
|
|
||||||
function setup_ws() {
|
function setup_ws() {
|
||||||
const sid = session_id()
|
const sid = session_id()
|
||||||
socket = new WebSocket(session_url(sid))
|
conn = new Connection()
|
||||||
socket.addEventListener("open", function (event) {
|
conn.on("helo", () => {
|
||||||
send("name", "Monitor")
|
conn.send("name", "Monitor")
|
||||||
})
|
})
|
||||||
socket.addEventListener("message", function (event) {
|
conn.on("id", ({ value }) => {
|
||||||
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
|
me = value
|
||||||
redraw_clients(me, clients)
|
redraw_clients(me, clients)
|
||||||
} else if (msg.type === "buzz") {
|
})
|
||||||
const buzztime_ns = value.time
|
conn.on("buzz", ({ value }) => {
|
||||||
const client_id = value.client
|
const { time: buzztime_ns, client: client_id } = value
|
||||||
const duration_ns = 12 * s_ns
|
const duration_ns = 12 * s_ns
|
||||||
const until_ns = buzztime_ns + duration_ns
|
const until_ns = buzztime_ns + duration_ns
|
||||||
highlight(client_id, until_ns)
|
highlight(client_id, until_ns)
|
||||||
} else if (msg.type === "clients") {
|
})
|
||||||
|
conn.on("clients", ({ value }) => {
|
||||||
clients = Object.fromEntries(value.clients.map((c) => [c.id, c]))
|
clients = Object.fromEntries(value.clients.map((c) => [c.id, c]))
|
||||||
redraw_clients(me, clients)
|
redraw_clients(me, clients)
|
||||||
} else if (msg.type === "client") {
|
})
|
||||||
const client = value.client
|
conn.on("client", ({ value: { client } }) => {
|
||||||
clients[client.id] = client
|
clients[client.id] = client
|
||||||
redraw_clients(me, clients)
|
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("control", ({ value }) => {
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
conn.connect(session_url(sid))
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_url()
|
setup_url()
|
||||||
|
|
|
||||||
|
|
@ -105,11 +105,58 @@ export function session_id() {
|
||||||
return match ? match[1] : null
|
return match ? match[1] : null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
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.
|
* Guess the exact current server time.
|
||||||
*/
|
*/
|
||||||
export function servertime_now_ns() {
|
servertime_now_ns() {
|
||||||
const now_ms = performance.now()
|
const now_ms = performance.now()
|
||||||
const delta_ns = ms_ns * (now_ms - toffset_ms)
|
const delta_ns = ms_ns * (now_ms - this.toffset_ms)
|
||||||
return servertime + delta_ns
|
return this.servertime + delta_ns
|
||||||
|
}
|
||||||
|
|
||||||
|
send(type, value) {
|
||||||
|
// console.debug('sending', value)
|
||||||
|
this.socket.send(JSON.stringify({ type, value }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue