From 058432130628d00764663ecf819a9adc6793768d Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 8 Nov 2026 03:29:35 +0100 Subject: v5.0.0: protocol v5 and the browser frontend Protocol v5 replaces newline lines with bounded [u32 len][text] frames and REQ/RES/EVT envelopes. Requests carry correlation ids and the server replays the last 256 replies per connection, so a gateway retry cannot double-debit and a late reply cannot clobber a newer request. HELLO/PONG carry server time; crash rounds announce started_at and push coalesced 10 Hz ticks. Crash now commits sha256(seed) before a round and reveals the seed when it ends, so clients recompute the crash point. Adds the webd/ gateway: one blocking thread, one ClientCore and one pinned upstream TLS connection per session, an HttpOnly session cookie, takeover, and a 60-second grace window. The browser sends Command JSON and renders View JSON; it never speaks the game protocol or stores credentials. Adds the vanilla TypeScript browser app at /play/ (login, lobby, all four games, history, notices, crash verification), the nginx /play and /ws routes, and the headless DOM smoke test. webd and the app stay out of the TUI/GUI/server build graph. The client/server version moves to 5.0.0 in lockstep; v4 peers are refused at HELLO. --- src/bin/server/handler.rs | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) (limited to 'src/bin/server/handler.rs') diff --git a/src/bin/server/handler.rs b/src/bin/server/handler.rs index dffae69..e6b623f 100644 --- a/src/bin/server/handler.rs +++ b/src/bin/server/handler.rs @@ -1,6 +1,7 @@ use std::time::Duration; use crate::tls::TlsStream; +use zagan_bet::protocol::{event_line, parse_request, reply_line}; use zagan_bet::server::core::{ConnectionState, ServerCore}; /// How long the connection waits for a request before advancing timed games. @@ -30,24 +31,35 @@ pub fn handle_client_tls(mut stream: TlsStream) { } let mut state = ConnectionState::default(); + let mut event_seq = 0u64; println!("[TLS Client connected] {client_addr}"); 'connection: loop { - let mut line = String::new(); - match stream.read_line(&mut line) { + let mut frame = String::new(); + match stream.read_frame(&mut frame) { Ok(0) => break, Ok(_) => { - let line = line.trim(); - if !line.is_empty() { - let user = state.user().unwrap_or("guest").to_string(); - println!("[{user} @ {client_addr}] Received: {line}"); - let response = core.handle_message(&mut state, line); - if let Err(error) = stream.write_line(&response) { - eprintln!("Write error: {error}"); - break; + let user = state.user().unwrap_or("guest").to_string(); + println!("[{user} @ {client_addr}] Received: {frame}"); + match parse_request(&frame) { + Ok(request) => { + let response = core.handle_request(&mut state, &request); + let reply = reply_line(request.id, &response); + if let Err(error) = stream.write_frame(&reply) { + eprintln!("Write error: {error}"); + break; + } + let user = state.user().unwrap_or("guest"); + println!("[{user} @ {client_addr}] Sent: {reply}"); + } + Err(message) => { + let reply = reply_line(0, &format!("ERROR {message}")); + if let Err(error) = stream.write_frame(&reply) { + eprintln!("Write error: {error}"); + break; + } + eprintln!("Malformed request from {client_addr}: {reply}"); } - let user = state.user().unwrap_or("guest"); - println!("[{user} @ {client_addr}] Sent: {response}"); } } Err(error) @@ -65,12 +77,17 @@ pub fn handle_client_tls(mut stream: TlsStream) { } for push in core.poll(&state) { - if let Err(error) = stream.write_line(&push) { + event_seq = event_seq.wrapping_add(1); + let event = event_line(event_seq, &push); + if let Err(error) = stream.write_frame(&event) { eprintln!("Write error: {error}"); break 'connection; } - let user = state.user().unwrap_or("guest"); - println!("[{user} @ {client_addr}] Pushed: {push}"); + // Ticks are 10 Hz per live round; logging them floods the disk. + if !push.starts_with("crash.tick ") { + let user = state.user().unwrap_or("guest"); + println!("[{user} @ {client_addr}] Pushed: {event}"); + } } } -- cgit v1.2.3