From de2a434c119104e0132e3f7988f5717eff23d4c5 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Fri, 31 Dec 2021 02:05:32 +0100 Subject: [PATCH] Move structs/enums into own module --- src/chat_error.rs | 18 ++++++++ src/chat_server.rs | 68 ++++++++++++++++++++++++++++ src/chat_user.rs | 19 ++++++++ src/config.rs | 9 ++++ src/main.rs | 108 +++------------------------------------------ 5 files changed, 121 insertions(+), 101 deletions(-) create mode 100644 src/chat_error.rs create mode 100644 src/chat_server.rs create mode 100644 src/chat_user.rs create mode 100644 src/config.rs diff --git a/src/chat_error.rs b/src/chat_error.rs new file mode 100644 index 0000000..2c66f68 --- /dev/null +++ b/src/chat_error.rs @@ -0,0 +1,18 @@ +#[derive(Debug)] +pub enum ChatError { + IOError(std::io::Error), + MutexPoisonError(), + Protocol(String), +} + +impl From for ChatError { + fn from(error: std::io::Error) -> Self { + ChatError::IOError(error) + } +} + +impl <'a, T> From>> for ChatError { + fn from(_error: std::sync::PoisonError>) -> Self { + ChatError::MutexPoisonError() + } +} diff --git a/src/chat_server.rs b/src/chat_server.rs new file mode 100644 index 0000000..c88ed8e --- /dev/null +++ b/src/chat_server.rs @@ -0,0 +1,68 @@ +use std::collections::BTreeMap; +use crate::chat_user::ChatUser; +use chrono::{DateTime, Utc}; +use crate::config::ConfigArgs; +use std::net::TcpStream; +use std::io::Write; +use crate::chat_error::ChatError; + + + + +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 }) + } +} + diff --git a/src/chat_user.rs b/src/chat_user.rs new file mode 100644 index 0000000..e9bca6f --- /dev/null +++ b/src/chat_user.rs @@ -0,0 +1,19 @@ +use std::net::TcpStream; + +/// Represent one single chat user and their network stuff +pub struct ChatUser { + /// user id + pub id: u64, + + /// Name of the chat user + pub name: String, + + /// TCPStream socket object thingy + pub socket: TcpStream, +} + +impl ChatUser { + pub fn new(id: u64, name: String, socket: TcpStream) -> Self { + Self{id, name, socket} + } +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..24bdaee --- /dev/null +++ b/src/config.rs @@ -0,0 +1,9 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct ConfigArgs { + pub host: String, + pub port: u16, + pub greeting_msg: String, +} + diff --git a/src/main.rs b/src/main.rs index 1df0d7a..e708939 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,105 +4,19 @@ use std::thread; use clap::Parser; use std::io::Write; use std::io::{self, BufRead}; -use chrono::{DateTime, Utc}; -use std::collections::BTreeMap; -use serde::{Serialize, Deserialize}; use std::fs::File; +mod chat_error; +use chat_error::ChatError; -/// Represent one single chat user and their network stuff -struct ChatUser { - /// user id - id: u64, +mod chat_user; - /// Name of the chat user - name: String, +mod chat_server; +use chat_server::ChatServer; - /// TCPStream socket object thingy - socket: TcpStream, -} - -impl ChatUser { - pub fn new(id: u64, name: String, socket: TcpStream) -> Self { - Self{id, name, socket} - } -} - -struct ChatServer { - 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 }) - } -} - -#[derive(Debug)] -enum ChatError { - IOError(std::io::Error), - MutexPoisonError(), - Protocol(String), -} +mod config; +use config::ConfigArgs; -impl From for ChatError { - fn from(error: std::io::Error) -> Self { - ChatError::IOError(error) - } -} - -impl <'a, T> From>> for ChatError { - fn from(_error: std::sync::PoisonError>) -> Self { - ChatError::MutexPoisonError() - } -} fn handle_client(mut stream: TcpStream, server: Arc>, client_id: &mut Option) -> Result<(), ChatError> { let mut writer = stream.try_clone()?; @@ -178,14 +92,6 @@ struct Args { port: Option, } - -#[derive(Debug, Serialize, Deserialize)] -struct ConfigArgs { - host: String, - port: u16, - greeting_msg: String, -} - fn main() -> std::io::Result<()> { // argument parsing let args = Args::parse();