From 52c757ea3ae4acc4afb8c325be5b5b683955a64e Mon Sep 17 00:00:00 2001 From: David Westgate Date: Sat, 25 Nov 2023 13:53:52 -0800 Subject: [PATCH] further work on server and client cmd implementation --- src/client.rs | 98 ++++++++++++++++++++++++++++++++++++++------------- src/lib.rs | 1 + src/server.rs | 96 +++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 152 insertions(+), 43 deletions(-) diff --git a/src/client.rs b/src/client.rs index 41893a4..7125664 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,6 +1,6 @@ use prompted::input; -use rust_irc::codes::client::*; -use std::io::{ Read, Write}; +use rust_irc::codes; +use std::io::{Read, Write}; use std::net::TcpStream; use std::thread; @@ -12,8 +12,8 @@ fn read_messages(mut stream: TcpStream) { if size == 0 { break; //Server closed connection } - let message: &[u8] = &buffer[..size]; - process_message(message); + let msg_bytes: &[u8] = &buffer[..size]; + process_message(msg_bytes); } Err(_) => { break; @@ -22,12 +22,62 @@ fn read_messages(mut stream: TcpStream) { } } -fn process_message(message: &[u8]) { - if let Ok(text) = String::from_utf8(message.to_vec()) { - println!("from serv: {}", text); +fn process_message(msg_bytes: &[u8]) { + match msg_bytes[0] { + codes::ERROR => { + #[cfg(debug_assertions)] + println!("err: {:x?}", msg_bytes[1]); + match msg_bytes[1] { + codes::error::INVALID_ROOM => { + println!("Attempted to message non-existant room. Try again"); + } + codes::error::NICKNAME_COLLISION => { + println!( + "Nickname already in use on server. Connect again with a different one" + ); + disconnect(); + } + codes::error::SERVER_FULL => { + println!("Server is full. Try again later"); + disconnect(); + } + _ => { + #[cfg(debug_assertions)] + println!("Unknown error code {:x?}", msg_bytes[1]); + } + } + } + codes::RESPONSE_OK => { + #[cfg(debug_assertions)] + println!("RESPONSE_OK"); + } + codes::RESPONSE => { + let message = String::from_utf8(msg_bytes[1..msg_bytes.len()].to_vec()).unwrap(); + println!("{}", message); + } + _ => { + #[cfg(debug_assertions)] + println!("BAD RESPONSE = {:x?} ", msg_bytes[0]); + } } } +fn disconnect() {} + +fn rooms(stream: &mut TcpStream) { + stream.write(&[codes::client::LIST_ROOMS]); +} +fn users(stream: &mut TcpStream) { + stream.write(&[codes::client::LIST_USERS]); +} + +fn msg(stream: &mut TcpStream) {} + +fn join(stream: &mut TcpStream) {} + +fn show(stream: &mut TcpStream) {} +fn leave(stream: &mut TcpStream) {} + pub fn start() { println!("Starting the IRC client"); let nick: String = input!("Enter your nickname: "); @@ -37,34 +87,32 @@ pub fn start() { if let Ok(mut stream) = TcpStream::connect(host.to_owned() + ":6667") { println!("Connected to {}", host); - //try to register the nickname - let mut buf: Vec = vec![0; nick.capacity()]; - buf[0] = REGISTER_NICK; - for i in 1..nick.len()+1 { - buf[i] = *nick.as_bytes().get(i - 1).unwrap(); - } - stream.write(&buf); - //another stream for reading messages let stream_clone: TcpStream = stream.try_clone().expect("Failed to clone stream"); thread::spawn(move || { read_messages(stream_clone); }); + //try to register the nickname + let mut buf: Vec = vec![0; nick.capacity()]; + buf[0] = codes::client::REGISTER_NICK; + for i in 1..nick.len() + 1 { + buf[i] = *nick.as_bytes().get(i - 1).unwrap(); + } + stream.write(&buf); + loop { let cmd: String = input!(":"); match cmd.trim() { - "/quit" => {} - "/list" => {} - "/msq" => {} - "/join" => {} - "/show" => {} - "/leave" => {} - "/msg" => {} + "/quit" => disconnect(), + "/rooms" => rooms(&mut stream), + "/users" => users(&mut stream), + "/join" => join(&mut stream), + "/show" => show(&mut stream), + "/leave" => leave(&mut stream), + "/msg" => msg(&mut stream), - _ => { - stream.write(cmd.as_bytes()); - } + _ => msg(&mut stream), } } } else { diff --git a/src/lib.rs b/src/lib.rs index 5b59839..15c8b61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod codes { pub const LIST_ROOMS: u8 = 0x04; pub const SEND_MESSAGE: u8 = 0x05; pub const REGISTER_NICK: u8 = 0x06; + pub const LIST_USERS: u8 = 0x07; } pub const KEEP_ALIVE: u8 = 0x0C; pub const RESPONSE: u8 = 0x0D; diff --git a/src/server.rs b/src/server.rs index 2059bda..e503582 100644 --- a/src/server.rs +++ b/src/server.rs @@ -27,31 +27,90 @@ impl Server { } fn handle_client(&mut self, mut stream: TcpStream) { - let mut buffer: [u8; 1024] = [0; 1024]; - let nickname: String; + // handle user commands - // Read the nickname from the client - match stream.read(&mut buffer) { - Ok(size) => { - let nickname_bytes = &buffer[0..size]; - nickname = String::from_utf8_lossy(nickname_bytes).to_string(); + loop { + let mut buf_in: [u8; 1024] = [0; 1024]; + + match stream.read(&mut buf_in) { + Ok(size) => { + let cmd_bytes: &[u8] = &buf_in[0..1]; + let param_bytes: &[u8] = &buf_in[1..size]; + #[cfg(debug_assertions)] + println!("Stream in "); + match cmd_bytes[0] { + codes::client::REGISTER_NICK => { + #[cfg(debug_assertions)] + println!("REGISTER_NICK"); + let nickname: String = String::from_utf8_lossy(param_bytes).to_string(); + self.register_nick(nickname, &mut stream); + } + codes::client::LIST_ROOMS => { + #[cfg(debug_assertions)] + println!("LIST_ROOMS"); + let mut buf_out: Vec = Vec::new(); + buf_out.extend_from_slice(&[codes::RESPONSE]); + for (room, user) in &self.rooms { + buf_out.extend_from_slice(room.as_bytes()); + } + stream.write(&buf_out); + } + codes::client::LIST_ROOMS => { + #[cfg(debug_assertions)] + println!("LIST_ROOMS"); + let mut buf_out: Vec = Vec::new(); + buf_out.extend_from_slice(&[codes::RESPONSE]); + for (room, user) in &self.rooms { + buf_out.extend_from_slice(room.as_bytes()); + } + stream.write(&buf_out); + } + codes::client::LIST_USERS => { + #[cfg(debug_assertions)] + println!("LIST_USERS"); + let mut buf_out: Vec = Vec::new(); + buf_out.extend_from_slice(&[codes::RESPONSE]); + for (user) in &self.users { + buf_out.extend_from_slice(user.as_bytes()); + } + stream.write(&buf_out); + } + codes::client::JOIN_ROOM => { + #[cfg(debug_assertions)] + println!("JOIN_ROOM"); + } + codes::client::LEAVE_ROOM => { + #[cfg(debug_assertions)] + println!("LEAVE_ROOM"); + } + codes::client::SEND_MESSAGE => { + #[cfg(debug_assertions)] + println!("SEND_MESSAGE"); + } + _ => { + #[cfg(debug_assertions)] + println!("Unspecified client Op"); + } + } + } + Err(_) => return, } - Err(_) => return, } + } + fn register_nick(&mut self, nickname: String, stream: &mut TcpStream) { // Check for nickname collision if self.users.contains(&nickname) { + #[cfg(debug_assertions)] + println!("nickname collision, {}", nickname); stream.write_all(&[codes::ERROR, codes::error::NICKNAME_COLLISION]); - return; + } else { + // Add the user to the user list + self.users.insert(nickname.clone()); + + // Send response ok + stream.write_all(&[codes::RESPONSE_OK]); } - - // Add the user to the user list - self.users.insert(nickname.clone()); - - // Send response ok - stream.write_all(&[codes::RESPONSE_OK]); - - // handle user commands } } @@ -87,7 +146,8 @@ pub fn start() { Ok(mut stream) => { let mut cmd_buf: [i32; 2] = [0; 2]; let mut local_server = server_mutx.lock().unwrap(); - + #[cfg(debug_assertions)] + println!("match stream"); if local_server.users.len() < MAX_USERS { local_server.handle_client(stream); } else {