use std::collections::HashMap; use std::sync::Arc; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::{TcpListener, TcpStream}; use tokio::sync::RwLock; // Use Tokio's async-aware lock // Type alias for our shared thread-safe state type Db = Arc>>; #[tokio::main] async fn main() -> Result<(), Box> { // Bind to all interfaces on port 5901 let listener = TcpListener::bind("0.0.0.0:5901").await?; let db: Db = Arc::new(RwLock::new(HashMap::new())); println!("🚀 Escape Room Server active on port 5901"); println!("Waiting for teams to connect..."); loop { let (socket, _) = listener.accept().await?; let db_clone = Arc::clone(&db); // Spawn a new async task for every connection tokio::spawn(async move { if let Err(e) = handle_connection(socket, db_clone).await { eprintln!("[SOCKET ERROR] {}", e); } }); } } async fn handle_connection(mut socket: TcpStream, db: Db) -> std::io::Result<()> { let mut buf = [0; 1024]; let n = socket.read(&mut buf).await?; // Connection closed if n == 0 { return Ok(()); } let request = String::from_utf8_lossy(&buf[..n]); let parts: Vec<&str> = request.trim().split_whitespace().collect(); if parts.is_empty() { return Ok(()); } match parts[0].to_uppercase().as_str() { // Teams submit their solution: PUT [team_id] [value] "PUT" => { if parts.len() == 3 { let team_id = parts[1].to_string(); let val = parts[2].to_string(); let mut data = db.write().await; // Async lock data.insert(team_id.clone(), val.clone()); socket.write_all(b"ACK\n").await?; println!("[LOG] Team {} submitted solution: {}", team_id, val); } } // Teams request previous solution: GET [prev_team_id] "GET" => { if parts.len() == 2 { let target_id = parts[1]; let data = db.read().await; // Async lock let response = data .get(target_id) .cloned() .unwrap_or_else(|| "-1".to_string()); if response == "-1" { println!("[WAIT] Team requested {}, but no data yet.", target_id); } socket.write_all(response.as_bytes()).await?; } } // Admin override: ADMIN SET [team_id] [value] "ADMIN" => { if parts.len() == 4 && parts[1].to_uppercase() == "SET" { let team_id = parts[2].to_string(); let val = parts[3].to_string(); let mut data = db.write().await; data.insert(team_id.clone(), val.clone()); socket.write_all(b"ADMIN_OK\n").await?; println!("[ADMIN] Manual set: Team {} -> {}", team_id, val); } } _ => { socket.write_all(b"ERR_INVALID_CMD\n").await?; } } Ok(()) }