use std::net::TcpListener; use std::thread; use std::sync::{Arc, Mutex}; use std::collections::HashMap; use rand::RngCore; use tungstenite::protocol::Message; use sha2::{Sha256, Digest}; fn main() { let code_generator = Arc::new(Mutex::new(CodeGenerator::default())); let server = TcpListener::bind("127.0.0.1:8080").unwrap(); let rooms = Arc::new(Mutex::new(HashMap::new())); for stream in server.incoming() { let code_generator = Arc::clone(&code_generator); let rooms = Arc::clone(&rooms); thread::spawn (move || { let mut ws = tungstenite::accept(stream.unwrap()).unwrap(); println!("New client!"); ws.write_message(Message::Text("HOSTJOIN:".to_string())).unwrap(); loop { let message = ws.read_message(); println!("{:?}", message); match message { Err(_) => break, Ok(Message::Close(_)) => break, Ok(Message::Text(msg)) => match parse(msg.as_str().trim()) { Some(("HOST:", _)) => { let code = code_generator.lock().unwrap().generate(); let mut room = Room::default(); let player = Player { name: "Guest".to_string() }; room.players.push(player); rooms.lock().unwrap().insert(code.clone(), room); ws.write_message(Message::Text(code)).unwrap(); }, Some(("JOIN:", args)) => { let code = args[0]; let room = rooms.lock().unwrap().get(&code.to_string()); match room { Some(mut room) => { room. } _ => unimplemented!(), }, _ => unimplemented!(), } } }); } } #[derive(Default)] struct Room { players: Vec, } struct Player { name: String, } struct CodeGenerator { counter: u64, salt: [u8; 32], } impl CodeGenerator { fn generate(&mut self) -> String { let count = self.counter; self.counter += 1; let mut hasher = Sha256::new(); hasher.update(self.salt); hasher.update(count.to_be_bytes()); format!("{:x}", hasher.finalize())[..6].to_string() } } impl Default for CodeGenerator { fn default() -> Self { let mut salt = [0; 32]; rand::thread_rng().fill_bytes(&mut salt); CodeGenerator { counter: 0, salt, } } } fn parse(s: &str) -> Option<(&str, Vec<&str>)> { let re = regex::Regex::new(r"(^[A-Z_]):\w*(.*)").unwrap(); match re.captures(s) { Some(captures) => { if captures.len() < 3 { None } else { Some(( captures.get(1).unwrap().as_str(), captures.get(2).unwrap().as_str().split(',').collect(), )) } } None => None, } }