handle quitting finally

This commit is contained in:
David Westgate 2023-11-29 16:36:50 -08:00
parent 0de646a74e
commit 01ae72c6cc
2 changed files with 53 additions and 9 deletions

View File

@ -59,6 +59,7 @@ fn read_messages(mut stream: TcpStream, nick: &str) {
} }
fn process_message(msg_bytes: &[u8], nick: &str) { fn process_message(msg_bytes: &[u8], nick: &str) {
println!();
match msg_bytes[0] { match msg_bytes[0] {
codes::ERROR => codes::ERROR =>
{ {
@ -70,11 +71,9 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
println!( println!(
"Nickname already in use on server. Connect again with a different one" "Nickname already in use on server. Connect again with a different one"
); );
disconnect();
} }
codes::error::SERVER_FULL => { codes::error::SERVER_FULL => {
println!("Server is full. Try again later"); println!("Server is full. Try again later");
disconnect();
} }
_ => { _ => {
println!("Error code: {:x?}", msg_bytes[1]); println!("Error code: {:x?}", msg_bytes[1]);
@ -113,6 +112,10 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
let message = String::from_utf8(msg_bytes[1..msg_bytes.len()].to_vec()).unwrap(); let message = String::from_utf8(msg_bytes[1..msg_bytes.len()].to_vec()).unwrap();
println!("{}", message); println!("{}", message);
} }
codes::QUIT => {
println!("Server has closed the connection. Stopping client");
std::process::exit(0);
}
_ => { _ => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("BAD RESPONSE = {:x?} ", msg_bytes[0]); println!("BAD RESPONSE = {:x?} ", msg_bytes[0]);
@ -120,7 +123,10 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
} }
} }
fn disconnect() {} fn disconnect(stream: &mut TcpStream) {
stream.write_all(&[codes::QUIT]).unwrap();
stream.shutdown(std::net::Shutdown::Both).unwrap();
}
fn help() { fn help() {
clear(); clear();
@ -179,7 +185,7 @@ pub fn start() {
Some(cmd) => { Some(cmd) => {
let param: Option<&str> = args.next(); let param: Option<&str> = args.next();
match cmd { match cmd {
"/quit" => disconnect(), "/quit" => {disconnect(&mut stream); break},
"/rooms" => no_param_op(codes::client::LIST_ROOMS, &mut stream), "/rooms" => no_param_op(codes::client::LIST_ROOMS, &mut stream),
"/users" => no_param_op(codes::client::LIST_USERS, &mut stream), "/users" => no_param_op(codes::client::LIST_USERS, &mut stream),
"/list" => match param { "/list" => match param {

View File

@ -30,7 +30,6 @@ impl Server {
fn message(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>) { fn message(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>) {
println!("message fn {} {}", room, msg);
let size = room.len() + msg.len() + sender.len() + 3; let size = room.len() + msg.len() + sender.len() + 3;
let mut out_buf: Vec<u8> = vec![0; size]; let mut out_buf: Vec<u8> = vec![0; size];
@ -59,7 +58,7 @@ fn message(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>) {
byte += 1; byte += 1;
} }
let mut guard = server.lock().unwrap(); let mut guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
let server: &mut Server = guard.deref_mut(); let server: &mut Server = guard.deref_mut();
let room_users: Option<&Vec<String>> = server.rooms.get(room); let room_users: Option<&Vec<String>> = server.rooms.get(room);
@ -95,12 +94,22 @@ fn broadcast(op: u8, server: &Arc<Mutex<Server>>, message: &str) {
} }
let mut unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap(); let mut unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
let streams = unlocked_server.users.values_mut(); let streams: std::collections::hash_map::ValuesMut<'_, String, TcpStream> = unlocked_server.users.values_mut();
for stream in streams { for stream in streams {
stream.write_all(&out_buf).unwrap(); stream.write_all(&out_buf).unwrap();
} }
} }
fn disconnect_all(server: &Arc<Mutex<Server>>,) {
let mut guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
let users: std::collections::hash_map::ValuesMut<'_, String, TcpStream> = guard.users.values_mut();
users.for_each(|user: &mut TcpStream| {
user.write(&[codes::QUIT]).unwrap();
user.shutdown(std::net::Shutdown::Both);
})
}
fn handle_client( fn handle_client(
server: &Arc<Mutex<Server>>, server: &Arc<Mutex<Server>>,
stream: &mut TcpStream, stream: &mut TcpStream,
@ -193,6 +202,9 @@ fn handle_client(
} }
} }
} }
codes::QUIT => {
remove_user(server, nickname,stream);
}
_ => { _ => {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("Unspecified client Op, {:x?}", cmd_bytes); println!("Unspecified client Op, {:x?}", cmd_bytes);
@ -202,6 +214,18 @@ fn handle_client(
// } // }
} }
fn remove_user(server: &Arc<Mutex<Server>>, nickname: &str, stream: &mut TcpStream) {
let mut guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
let server: &mut Server = guard.deref_mut();
let mut rooms: &mut HashMap<String, Vec<String>> = &mut server.rooms;
rooms.values_mut().for_each(|room: &mut Vec<String>| {
room.retain(|u| !u.eq(nickname));
});
let users: &mut HashMap<String, TcpStream> = &mut server.users;
users.remove(nickname);
}
fn register_nick(server: &Arc<Mutex<Server>>, nickname: &str, stream: &mut TcpStream) { fn register_nick(server: &Arc<Mutex<Server>>, nickname: &str, stream: &mut TcpStream) {
// Check for nickname collision // Check for nickname collision
let mut unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap(); let mut unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
@ -214,10 +238,13 @@ fn register_nick(server: &Arc<Mutex<Server>>, nickname: &str, stream: &mut TcpSt
} else { } else {
// Add the user to the user list // Add the user to the user list
let clone = stream.try_clone().expect("fail to clone"); let clone = stream.try_clone().expect("fail to clone");
unlocked_server.users.insert(nickname.to_string(), clone); let addr = clone.peer_addr().unwrap().to_string();
unlocked_server.users.insert(nickname.to_string(), clone);
// Send response ok // Send response ok
stream.write_all(&[codes::RESPONSE_OK]).unwrap(); stream.write_all(&[codes::RESPONSE_OK]).unwrap();
println!("{} has registered nickname {}", addr, nickname);
} }
} }
@ -285,7 +312,11 @@ pub fn start() {
thread::spawn(move || { thread::spawn(move || {
let nickname: String; let nickname: String;
println!("IP {} has connected", stream.peer_addr().unwrap().to_string());
match stream.read(&mut buf_in) { match stream.read(&mut buf_in) {
Ok(0) => {
println!("IP {} has closed the connection", stream.peer_addr().unwrap().to_string());
}
Ok(size) => { Ok(size) => {
let cmd_bytes: &[u8] = &buf_in[0..1]; let cmd_bytes: &[u8] = &buf_in[0..1];
let param_bytes: &[u8] = &buf_in[1..size]; let param_bytes: &[u8] = &buf_in[1..size];
@ -294,6 +325,10 @@ pub fn start() {
register_nick(&server_inner, &nickname, &mut stream); register_nick(&server_inner, &nickname, &mut stream);
loop { loop {
match stream.read(&mut buf_in) { match stream.read(&mut buf_in) {
Ok(0) => {
println!("IP {} wit nickname {} has closed the connection", stream.peer_addr().unwrap().to_string(), nickname);
break;
}
Ok(size) => { Ok(size) => {
let cmd_bytes: &[u8] = &buf_in[0..1]; let cmd_bytes: &[u8] = &buf_in[0..1];
let param_bytes: &[u8] = &buf_in[1..size]; let param_bytes: &[u8] = &buf_in[1..size];
@ -345,7 +380,10 @@ pub fn start() {
match inp.parse::<u8>() { match inp.parse::<u8>() {
Ok(num) => match num { Ok(num) => match num {
0 => { 0 => {
println!("Goodbye"); println!("Stopping Server");
disconnect_all(&server);
break;
} }
1 => println!("Users: {:?}", server.lock().unwrap().users), 1 => println!("Users: {:?}", server.lock().unwrap().users),
2 => println!("Rooms: {:?}", server.lock().unwrap().rooms), 2 => println!("Rooms: {:?}", server.lock().unwrap().rooms),