use crate::chat_error::ChatError; use crate::chat_user::ChatUser; use crate::config::ConfigArgs; use chrono::{DateTime, Utc}; use std::collections::BTreeMap; use std::io::Write; use std::net::TcpStream; pub struct ChatServer { pub config: ConfigArgs, user_map: BTreeMap, user_id_counter: u64, } impl ChatServer { pub fn new(config: ConfigArgs) -> Self { Self { config, user_map: BTreeMap::new(), user_id_counter: 1, } } pub fn get_user_count(&self) -> usize { self.user_map.len() } /// register a client by creating a ChatUser for it and assigning it a user id pub fn register(&mut self, name: String, socket: TcpStream) -> u64 { let chat_user = ChatUser::new(self.user_id_counter, name, socket); let client_id = chat_user.id; self.user_map.insert(chat_user.id, chat_user); self.user_id_counter += 1; client_id } pub fn deregister(&mut self, client_id: u64) -> Option { self.user_map.remove(&client_id) } pub fn send_to_all(&mut self, msg: &str) -> Result<(), ChatError> { let now: DateTime = Utc::now(); let time_msg = format!("[{}] {}", now.format("%H:%M:%S"), msg); let mut broken_clients = vec![]; for (user_id, user) in self.user_map.iter_mut() { if write!(user.socket, "{}\n", time_msg).is_err() { broken_clients.push((*user_id, user.name.clone())); } } // remove users from map for (user_id, _) in broken_clients.iter() { self.deregister(*user_id); } // send out the news for (_, name) in broken_clients.iter() { self.send_to_all(&format!("* {} has left the chat (broken pipe)", name))?; } Ok(()) } pub fn is_nick_in_use(&self, name: &str) -> bool { self.user_map.values().any(|client| client.name == name) } }