Move structs/enums into own module
This commit is contained in:
parent
8e6e310a18
commit
de2a434c11
|
@ -0,0 +1,18 @@
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ChatError {
|
||||||
|
IOError(std::io::Error),
|
||||||
|
MutexPoisonError(),
|
||||||
|
Protocol(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for ChatError {
|
||||||
|
fn from(error: std::io::Error) -> Self {
|
||||||
|
ChatError::IOError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a, T> From<std::sync::PoisonError<std::sync::MutexGuard<'a, T>>> for ChatError {
|
||||||
|
fn from(_error: std::sync::PoisonError<std::sync::MutexGuard<'a, T>>) -> Self {
|
||||||
|
ChatError::MutexPoisonError()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<u64, ChatUser>,
|
||||||
|
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<ChatUser> {
|
||||||
|
self.user_map.remove(&client_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_to_all(&mut self, msg: &str) -> Result<(), ChatError> {
|
||||||
|
let now: DateTime<Utc> = 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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
108
src/main.rs
108
src/main.rs
|
@ -4,105 +4,19 @@ use std::thread;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::{self, BufRead};
|
use std::io::{self, BufRead};
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
|
mod chat_error;
|
||||||
|
use chat_error::ChatError;
|
||||||
|
|
||||||
/// Represent one single chat user and their network stuff
|
mod chat_user;
|
||||||
struct ChatUser {
|
|
||||||
/// user id
|
|
||||||
id: u64,
|
|
||||||
|
|
||||||
/// Name of the chat user
|
mod chat_server;
|
||||||
name: String,
|
use chat_server::ChatServer;
|
||||||
|
|
||||||
/// TCPStream socket object thingy
|
mod config;
|
||||||
socket: TcpStream,
|
use config::ConfigArgs;
|
||||||
}
|
|
||||||
|
|
||||||
impl ChatUser {
|
|
||||||
pub fn new(id: u64, name: String, socket: TcpStream) -> Self {
|
|
||||||
Self{id, name, socket}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ChatServer {
|
|
||||||
config: ConfigArgs,
|
|
||||||
user_map: BTreeMap<u64, ChatUser>,
|
|
||||||
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<ChatUser> {
|
|
||||||
self.user_map.remove(&client_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_to_all(&mut self, msg: &str) -> Result<(), ChatError> {
|
|
||||||
let now: DateTime<Utc> = 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),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::io::Error> for ChatError {
|
|
||||||
fn from(error: std::io::Error) -> Self {
|
|
||||||
ChatError::IOError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a, T> From<std::sync::PoisonError<std::sync::MutexGuard<'a, T>>> for ChatError {
|
|
||||||
fn from(_error: std::sync::PoisonError<std::sync::MutexGuard<'a, T>>) -> Self {
|
|
||||||
ChatError::MutexPoisonError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_client(mut stream: TcpStream, server: Arc<Mutex<ChatServer>>, client_id: &mut Option<u64>) -> Result<(), ChatError> {
|
fn handle_client(mut stream: TcpStream, server: Arc<Mutex<ChatServer>>, client_id: &mut Option<u64>) -> Result<(), ChatError> {
|
||||||
let mut writer = stream.try_clone()?;
|
let mut writer = stream.try_clone()?;
|
||||||
|
@ -178,14 +92,6 @@ struct Args {
|
||||||
port: Option<u16>,
|
port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
struct ConfigArgs {
|
|
||||||
host: String,
|
|
||||||
port: u16,
|
|
||||||
greeting_msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
// argument parsing
|
// argument parsing
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
Loading…
Reference in New Issue