add user session reclaiming
In its current state the implementation should allow a user to resume their session if the websocket connection is reset, for whatever reason. This could be expanded to allow session sharing (multiple agents logging in to the same client), or manual session resume via some sort of password (encode uid & key to some pass-phrase kinda thing, or QR code).
This commit is contained in:
parent
476f3d7a49
commit
4908b1fc6e
10 changed files with 376 additions and 77 deletions
|
|
@ -3,6 +3,7 @@
|
|||
/* global document, window */
|
||||
const crypto = window.crypto
|
||||
const location = document.location
|
||||
const performance = window.performance
|
||||
const storage = window.sessionStorage
|
||||
|
||||
// TODOs
|
||||
|
|
@ -18,17 +19,16 @@ const buzzer_key = {
|
|||
|
||||
const q = (selector, root) => (root || document).querySelector(selector)
|
||||
const on = (event, cb) => document.addEventListener(event, cb)
|
||||
function node(type, { appendTo, cls, text, data, ...attrs } = {}) {
|
||||
let elem = document.createElement(type)
|
||||
function node(type, { appendTo, cls, text, data, style, ...attrs } = {}) {
|
||||
let elem = typeof type === "string" ? document.createElement(type) : type
|
||||
if (cls) {
|
||||
elem.className = cls
|
||||
}
|
||||
if (text) {
|
||||
elem.textContent = text
|
||||
}
|
||||
for (const name in data ?? {}) {
|
||||
elem.dataset[name] = data[name]
|
||||
}
|
||||
Object.assign(elem.dataset, data ?? {})
|
||||
Object.assign(elem.style, style ?? {})
|
||||
for (const name in attrs) {
|
||||
elem.setAttribute(name, attrs[name])
|
||||
}
|
||||
|
|
@ -53,11 +53,13 @@ let socket,
|
|||
session_key
|
||||
|
||||
function hide(e) {
|
||||
q(`#${e}`).style.display = "none"
|
||||
e = typeof e === "string" ? q(`#${e}`) : e
|
||||
e.style.display = "none"
|
||||
}
|
||||
|
||||
function show(e) {
|
||||
q(`#${e}`).style.display = "block"
|
||||
e = typeof e === "string" ? q(`#${e}`) : e
|
||||
e.style.display = "block"
|
||||
}
|
||||
|
||||
function session_id() {
|
||||
|
|
@ -97,8 +99,9 @@ function redraw_clients(me, clients) {
|
|||
return
|
||||
}
|
||||
clear(ul)
|
||||
const player_tpl = q("template#player").content.firstElementChild
|
||||
for (const c of clients) {
|
||||
node("li", {
|
||||
node(player_tpl.cloneNode(), {
|
||||
text: c.name,
|
||||
data: { cid: c.id },
|
||||
appendTo: ul,
|
||||
|
|
@ -180,18 +183,41 @@ function setup_ui() {
|
|||
}
|
||||
})
|
||||
|
||||
q("#username").addEventListener("change", (event) => {
|
||||
send("name", event.target.value)
|
||||
const username_el = q("#username")
|
||||
if (storage["my_name"]) {
|
||||
username_el.value = storage["my_name"]
|
||||
}
|
||||
username_el.addEventListener("change", (event) => {
|
||||
set_name(event.target.value)
|
||||
})
|
||||
|
||||
ul = q("#info ul")
|
||||
}
|
||||
|
||||
function set_name(name) {
|
||||
storage["my_name"] = name
|
||||
send("name", name)
|
||||
}
|
||||
|
||||
function session_url(sid) {
|
||||
return `${config.wsurl}/${sid}`
|
||||
}
|
||||
|
||||
function session_id_from_url(url) {
|
||||
const wsurl = new URL(config.wsurl)
|
||||
const match = RegExp(`${wsurl.pathname}/([^/]+)$`).exec(url)
|
||||
return !match ? null : match[1]
|
||||
}
|
||||
|
||||
function setup_ws() {
|
||||
const sid = session_id()
|
||||
socket = new WebSocket(`${config.wsurl}/quiz/${sid}`)
|
||||
const credentials = { id: storage["my_uid"], key: storage["my_key"] }
|
||||
socket = new WebSocket(`${session_url(sid)}`)
|
||||
socket.addEventListener("open", function (event) {
|
||||
send("name", q("#username").value)
|
||||
if (sid === storage["my_sid"]) {
|
||||
send("login", credentials)
|
||||
}
|
||||
set_name(q("#username").value)
|
||||
})
|
||||
socket.addEventListener("message", function (event) {
|
||||
const msg = JSON.parse(event.data)
|
||||
|
|
@ -199,9 +225,10 @@ function setup_ws() {
|
|||
servertime = msg.value
|
||||
toffset_ms = performance.now()
|
||||
} else if (msg.type === "id") {
|
||||
me = { id: msg.id, key: msg.key }
|
||||
storage["my_id"] = me.id
|
||||
me = { id: msg.id, key: msg.key, path: msg.path }
|
||||
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 (msg.type === "session_key") {
|
||||
session_key = { path: msg.path, key: msg.key }
|
||||
|
|
@ -217,7 +244,7 @@ function setup_ws() {
|
|||
clients = msg.value
|
||||
redraw_clients(me, clients)
|
||||
} else if (msg.type === "client") {
|
||||
const client = msg.value
|
||||
const client = { name: msg.name, id: msg.id, active: msg.active }
|
||||
for (const c of clients) {
|
||||
if (c.id === client.id) {
|
||||
c.name = client.name
|
||||
|
|
@ -227,6 +254,11 @@ function setup_ws() {
|
|||
}
|
||||
clients.push(client)
|
||||
redraw_clients(me, clients)
|
||||
} else if (msg.type === "error") {
|
||||
console.error(`Error: ${msg.reason}`)
|
||||
const errorbox = q("#error")
|
||||
q("code", errorbox).textContent = JSON.stringify(msg, null, 2)
|
||||
show(errorbox)
|
||||
} else {
|
||||
console.error(`Unknown message: ${event.data}`)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue