summaryrefslogtreecommitdiffstats
path: root/webd/src/main.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-08 03:29:35 +0100
committersalmonik <salmonik@tuta.io>2026-11-08 03:29:35 +0100
commit058432130628d00764663ecf819a9adc6793768d (patch)
treed3f49f111fbfaa48647cca2600adcf9017af2d30 /webd/src/main.rs
parentweb: serve latest.php through PHP and refuse stray PHP files (diff)
downloadzagan-bet-058432130628d00764663ecf819a9adc6793768d.tar.gz
zagan-bet-058432130628d00764663ecf819a9adc6793768d.zip
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.
Diffstat (limited to 'webd/src/main.rs')
-rw-r--r--webd/src/main.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/webd/src/main.rs b/webd/src/main.rs
new file mode 100644
index 0000000..c2cf0ff
--- /dev/null
+++ b/webd/src/main.rs
@@ -0,0 +1,61 @@
1//! Browser gateway for zagan-bet.
2//!
3//! nginx terminates TLS, serves the static app and proxies `/ws` here. This
4//! process owns one upstream TLS connection and one `ClientCore` per browser
5//! session, so the browser never speaks the game wire protocol and never sees
6//! a certificate.
7
8mod config;
9mod session;
10
11use std::net::TcpListener;
12use std::sync::Arc;
13use std::thread;
14
15use config::Config;
16
17fn main() {
18 let config = match Config::from_env() {
19 Ok(config) => config,
20 Err(error) => {
21 eprintln!("webd: {error}");
22 std::process::exit(2);
23 }
24 };
25
26 let listener = match TcpListener::bind(&config.bind) {
27 Ok(listener) => listener,
28 Err(error) => {
29 eprintln!("webd: could not bind {}: {error}", config.bind);
30 std::process::exit(1);
31 }
32 };
33
34 println!(
35 "webd listening on ws://{} for origin {}; upstream {} pinned to {}; grace {}s",
36 config.bind,
37 config.origin,
38 config.upstream,
39 config.fingerprint,
40 config.grace.as_secs()
41 );
42
43 let registry = session::new_registry();
44 for stream in listener.incoming() {
45 let stream = match stream {
46 Ok(stream) => stream,
47 Err(error) => {
48 eprintln!("webd: accept failed: {error}");
49 continue;
50 }
51 };
52 let _ = stream.set_nodelay(true);
53 let config = config.clone();
54 let registry = Arc::clone(&registry);
55 thread::spawn(move || {
56 if let Err(error) = session::accept(stream, config, registry) {
57 eprintln!("webd: {error}");
58 }
59 });
60 }
61}