diff --git a/server/src/game_handler.rs b/server/src/game_handler.rs index 5304f29..10ba7cb 100644 --- a/server/src/game_handler.rs +++ b/server/src/game_handler.rs @@ -4,12 +4,12 @@ use crate::AppState; use crate::DmUserMethod::*; use crate::GameHandlerMessage::*; use crate::SendUserMessage::*; -use crate::Sender; use crate::UserHandlerMessage::*; use axum::extract::ws::Message; use lib::*; use serde_json::to_string; use std::{collections::HashMap, net::SocketAddr, sync::Arc}; +use tokio::sync::mpsc::Sender; /// For interacting with the game handler pub enum GameHandlerMessage { diff --git a/server/src/incoming_message_handler.rs b/server/src/incoming_message_handler.rs index 8e2fa44..b31048b 100644 --- a/server/src/incoming_message_handler.rs +++ b/server/src/incoming_message_handler.rs @@ -5,8 +5,7 @@ use crate::UserHandlerMessage::*; use axum::extract::ws::{CloseFrame, Message}; use lib::*; use serde_json::{from_str, to_string}; -use std::net::SocketAddr; -use std::sync::Arc; +use std::{net::SocketAddr, sync::Arc}; /// Handles incoming messages pub struct IncomingMessageHandler { diff --git a/server/src/lib.rs b/server/src/lib.rs index ba8ba37..b9eb5c0 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,11 +1,9 @@ #![feature(if_let_guard)] use crate::game_handler::*; -use anyhow::{Context, Result}; use axum::extract::ws::Message; -use lib::*; use std::{ - collections::{HashMap, HashSet}, + collections::HashMap, net::SocketAddr, sync::{Arc, RwLock}, }; @@ -17,6 +15,7 @@ pub mod card_loader; pub mod game; pub mod game_handler; pub mod incoming_message_handler; +pub mod name_generator; pub mod user_handler; pub mod websocket; diff --git a/server/src/name_generator.rs b/server/src/name_generator.rs new file mode 100644 index 0000000..2bff4ea --- /dev/null +++ b/server/src/name_generator.rs @@ -0,0 +1,54 @@ +use anyhow::{Context, Result}; +use rand::prelude::SliceRandom; +use std::{ + collections::HashSet, + fs::File, + io::{BufRead, BufReader}, +}; + +pub struct NameGenerator { + first_names: Vec, + last_names: Vec, +} + +/// Parse name list +pub fn load_names(path: &str) -> Result> { + let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?; + let f = BufReader::new(f); + + let mut buf = vec![]; + + for line in f.lines() { + buf.push(line?) + } + + Ok(buf) +} + +impl NameGenerator { + pub fn new() -> Self { + NameGenerator { + first_names: load_names("data/first.txt").unwrap(), + last_names: load_names("data/last.txt").unwrap(), + } + } + + pub fn generate(&mut self, reserved_names: &HashSet) -> String { + // Roll for username and re-roll if taken + let mut name; + + loop { + name = format!( + "{} {}", + self.first_names.choose(&mut rand::thread_rng()).unwrap(), + self.last_names.choose(&mut rand::thread_rng()).unwrap(), + ); + + if !reserved_names.contains(&name) { + break; + } + } + + name + } +} diff --git a/server/src/user_handler.rs b/server/src/user_handler.rs index df15918..892e8e3 100644 --- a/server/src/user_handler.rs +++ b/server/src/user_handler.rs @@ -1,41 +1,28 @@ +use crate::name_generator::*; use crate::AppState; use crate::DmUserMethod::*; +use crate::GameHandlerMessage; use crate::SendUserMessage::*; use crate::User; use crate::UserHandlerMessage::*; -use crate::*; -use rand::prelude::SliceRandom; +use axum::extract::ws::Message; +use lib::*; use serde_json::to_string; use std::{ - fs::File, - io::{BufRead, BufReader}, + collections::{HashMap, HashSet}, net::SocketAddr, sync::{Arc, RwLock}, }; +use tokio::sync::mpsc::Sender; // TODO: clean up all this tx/msg mess -/// Parse name list -pub fn load_names(path: &str) -> Result> { - let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?; - let f = BufReader::new(f); - - let mut buf = vec![]; - - for line in f.lines() { - buf.push(line?) - } - - Ok(buf) -} - /// Handles users pub struct UserHandler { /// Pointer to global state state: Arc, users_by_id: HashMap>>, - first_names: Vec, - last_names: Vec, + name_generator: NameGenerator, reserved_names: HashSet, } @@ -66,9 +53,8 @@ impl UserHandler { UserHandler { state, users_by_id: HashMap::>>::new(), - first_names: load_names("data/first.txt").unwrap(), - last_names: load_names("data/last.txt").unwrap(), reserved_names: HashSet::::new(), + name_generator: NameGenerator::new(), } } @@ -143,41 +129,26 @@ impl UserHandler { /// Create, register, and hydrate new user async fn set_up_new_user(&mut self, dm_tx: Sender, addr: SocketAddr) { - // Roll for username and re-roll if taken - let mut name; - - loop { - name = format!( - "{} {}", - self.first_names.choose(&mut rand::thread_rng()).unwrap(), - self.last_names.choose(&mut rand::thread_rng()).unwrap(), - ); - - if !self.reserved_names.contains(&name) { - break; - } - } + let name = self.name_generator.generate(&self.reserved_names); let new_user = Arc::new(RwLock::new(User::new(name, dm_tx.clone()))); - // Notify client of new username - let tx = dm_tx.clone(); - let msg = user_client_self_update(&new_user); - tokio::spawn(async move { tx.send(msg).await }); - // Register uuid self.users_by_id .insert(new_user.read().unwrap().uuid.clone(), new_user.clone()); // Register online using `addr` as key until something longer lived exists - self.state - .online_users - .write() - .unwrap() - .insert(addr, new_user.clone()); + self.set_user_online(addr, new_user.clone()); // Hydrate client if !dm_tx.is_closed() { + // Notify client of username + if let Err(e) = dm_tx.send(user_client_self_update(&new_user)).await { + tracing::error!("Error sending client update {}", e) + } + + // Send game update + // TODO: send single update instad of broadcasting to all users if let Err(e) = self .state .tx_game_handler @@ -187,6 +158,7 @@ impl UserHandler { tracing::error!("Error contacing game handler {}", e) } + // Send card packs for new game form if let Err(e) = self .state .tx_game_handler @@ -195,6 +167,8 @@ impl UserHandler { { tracing::error!("Error contacing game handler {}", e) } + } else { + self.user_cleanup(addr); } // Broadcast new user's existence @@ -398,15 +372,7 @@ impl UserHandler { }); // Move user to offline - self.state.offline_users.write().unwrap().insert( - user_name, - self.state - .online_users - .write() - .unwrap() - .remove(&addr) - .unwrap(), - ); + self.set_user_offline(user_name, &addr); self.broadcast_user_count(); @@ -418,6 +384,24 @@ impl UserHandler { } }); } + + /// Set user status to online + fn set_user_online(&self, addr: SocketAddr, user: Arc>) { + self.state.online_users.write().unwrap().insert(addr, user); + } + + /// Set user status to offline + fn set_user_offline(&self, user_name: String, addr: &SocketAddr) { + self.state.offline_users.write().unwrap().insert( + user_name, + self.state + .online_users + .write() + .unwrap() + .remove(addr) + .unwrap(), + ); + } } /// Generate message to notify client of user changes