Spaces:
Runtime error
Runtime error
| let socket; | |
| let username; | |
| let sessionToken; | |
| let nextId = 0; | |
| let pendingMessages = {}; | |
| async function init() { | |
| try { | |
| const res = await fetch("/api/session"); | |
| const data = await res.json(); | |
| if (data.authenticated) { | |
| username = data.username; | |
| sessionToken = data.token; | |
| showChat(); | |
| connectWebSocket(); | |
| } else { | |
| showLogin(); | |
| } | |
| } catch { | |
| showLogin(); | |
| } | |
| } | |
| function showLogin() { | |
| document.getElementById("auth-container").style.display = "block"; | |
| document.getElementById("login-form").style.display = "block"; | |
| document.getElementById("signup-form").style.display = "none"; | |
| document.getElementById("chat-app").style.display = "none"; | |
| document.getElementById("login-error").textContent = ""; | |
| } | |
| function showSignup() { | |
| document.getElementById("auth-container").style.display = "block"; | |
| document.getElementById("login-form").style.display = "none"; | |
| document.getElementById("signup-form").style.display = "block"; | |
| document.getElementById("chat-app").style.display = "none"; | |
| document.getElementById("signup-error").textContent = ""; | |
| } | |
| function showChat() { | |
| document.getElementById("auth-container").style.display = "none"; | |
| document.getElementById("chat-app").style.display = "block"; | |
| document.getElementById("display-username").textContent = username; | |
| document.getElementById("chat-window").innerHTML = ""; | |
| } | |
| async function handleLogin(e) { | |
| e.preventDefault(); | |
| const login = e.target.login.value; | |
| const password = e.target.password.value; | |
| const error = document.getElementById("login-error"); | |
| try { | |
| const res = await fetch("/api/login", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ login, password }), | |
| }); | |
| const data = await res.json(); | |
| if (res.ok) { | |
| username = data.username; | |
| sessionToken = data.token; | |
| showChat(); | |
| connectWebSocket(); | |
| } else { | |
| error.textContent = data.error; | |
| e.target.password.value = ""; | |
| } | |
| } catch { | |
| error.textContent = "Network error."; | |
| } | |
| } | |
| async function handleSignup(e) { | |
| e.preventDefault(); | |
| const email = e.target.email.value; | |
| const usernameVal = e.target.username.value; | |
| const password = e.target.password.value; | |
| const confirm = e.target.confirm_password.value; | |
| const error = document.getElementById("signup-error"); | |
| if (password !== confirm) { | |
| error.textContent = "Passwords do not match."; | |
| return; | |
| } | |
| try { | |
| const res = await fetch("/api/signup", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ email, username: usernameVal, password }), | |
| }); | |
| const data = await res.json(); | |
| if (res.ok) { | |
| username = data.username; | |
| sessionToken = data.token; | |
| showChat(); | |
| connectWebSocket(); | |
| } else { | |
| error.textContent = data.error; | |
| } | |
| } catch { | |
| error.textContent = "Network error."; | |
| } | |
| } | |
| async function logout() { | |
| if (socket) { socket.close(); socket = null; } | |
| try { await fetch("/api/logout", { method: "POST" }); } catch {} | |
| username = ""; | |
| sessionToken = ""; | |
| showLogin(); | |
| } | |
| function connectWebSocket() { | |
| const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"; | |
| const url = protocol + "//" + window.location.host + "/ws?token=" + encodeURIComponent(sessionToken); | |
| socket = new WebSocket(url); | |
| socket.onmessage = function (event) { | |
| const data = JSON.parse(event.data); | |
| const now = Date.now(); | |
| const win = document.getElementById("chat-window"); | |
| const el = document.createElement("div"); | |
| if (data.is_system) { | |
| el.style.fontStyle = "italic"; | |
| el.style.color = "#ffcc00"; | |
| el.textContent = "[System] " + data.msg; | |
| } else { | |
| let text = data.user + ": " + data.msg; | |
| if (data.user === username && pendingMessages[data.id] !== undefined) { | |
| const rtt = now - pendingMessages[data.id]; | |
| text += " (rtt: " + rtt + "ms)"; | |
| delete pendingMessages[data.id]; | |
| } else if (data.server_time) { | |
| const sp = now - data.server_time; | |
| text += " (sping: " + sp + "ms)"; | |
| } | |
| el.textContent = text; | |
| } | |
| win.appendChild(el); | |
| win.scrollTop = win.scrollHeight; | |
| }; | |
| socket.onclose = function (event) { | |
| if (event.code === 4002) { | |
| location.reload(); | |
| return; | |
| } | |
| const win = document.getElementById("chat-window"); | |
| if (win) { | |
| const el = document.createElement("div"); | |
| el.style.fontStyle = "italic"; | |
| el.style.color = "#e94560"; | |
| if (event.code === 4001) { | |
| el.textContent = "Session expired. Logging out..."; | |
| setTimeout(() => { logout(); }, 1500); | |
| } else { | |
| el.textContent = "Connection lost. Refresh the page."; | |
| } | |
| win.appendChild(el); | |
| } | |
| }; | |
| } | |
| function sendMessage() { | |
| if (!socket || socket.readyState !== WebSocket.OPEN) return; | |
| const input = document.getElementById("message-input"); | |
| const msg = input.value.trim(); | |
| if (!msg) return; | |
| const id = nextId++; | |
| pendingMessages[id] = Date.now(); | |
| socket.send(JSON.stringify({ msg, id })); | |
| input.value = ""; | |
| input.focus(); | |
| } | |
| init(); | |