2022-09-20 15:53:53 -05:00
|
|
|
use std::net::TcpListener;
|
|
|
|
use std::thread;
|
2022-09-29 15:28:38 -05:00
|
|
|
use std::sync::{Arc, Mutex};
|
2022-10-03 13:18:40 -05:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use rand::RngCore;
|
2022-09-20 15:53:53 -05:00
|
|
|
|
|
|
|
use tungstenite::protocol::Message;
|
|
|
|
|
2022-09-29 15:28:38 -05:00
|
|
|
use sha2::{Sha256, Digest};
|
|
|
|
|
2022-09-20 15:53:53 -05:00
|
|
|
fn main() {
|
2022-10-03 13:18:40 -05:00
|
|
|
let code_generator = Arc::new(Mutex::new(CodeGenerator::default()));
|
2022-09-20 15:53:53 -05:00
|
|
|
let server = TcpListener::bind("127.0.0.1:8080").unwrap();
|
2022-10-03 13:18:40 -05:00
|
|
|
|
|
|
|
let rooms = Arc::new(Mutex::new(HashMap::new()));
|
|
|
|
|
2022-09-20 15:53:53 -05:00
|
|
|
for stream in server.incoming() {
|
2022-10-03 13:18:40 -05:00
|
|
|
let code_generator = Arc::clone(&code_generator);
|
|
|
|
let rooms = Arc::clone(&rooms);
|
|
|
|
thread::spawn (move || {
|
2022-09-20 15:53:53 -05:00
|
|
|
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);
|
2022-09-29 15:28:38 -05:00
|
|
|
match message {
|
|
|
|
Err(_) => break,
|
2022-10-03 13:18:40 -05:00
|
|
|
Ok(Message::Close(_)) => break,
|
2022-09-29 15:28:38 -05:00
|
|
|
Ok(Message::Text(msg)) =>
|
2022-10-03 13:18:40 -05:00
|
|
|
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();
|
2022-09-29 15:28:38 -05:00
|
|
|
},
|
2022-10-03 13:18:40 -05:00
|
|
|
Some(("JOIN:", args)) => {
|
|
|
|
let code = args[0];
|
|
|
|
let room = rooms.lock().unwrap().get(&code.to_string());
|
|
|
|
match room {
|
|
|
|
Some(mut room) => {
|
|
|
|
room.
|
|
|
|
}
|
2022-09-29 15:28:38 -05:00
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
_ => unimplemented!(),
|
|
|
|
|
2022-09-20 15:53:53 -05:00
|
|
|
}
|
|
|
|
}
|
2022-10-03 13:18:40 -05:00
|
|
|
});
|
2022-09-20 15:53:53 -05:00
|
|
|
}
|
|
|
|
}
|
2022-10-03 13:18:40 -05:00
|
|
|
#[derive(Default)]
|
2022-09-20 15:53:53 -05:00
|
|
|
struct Room {
|
|
|
|
players: Vec<Player>,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Player {
|
|
|
|
name: String,
|
|
|
|
}
|
2022-09-29 15:28:38 -05:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
2022-10-03 13:18:40 -05:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|