further work on server and client cmd implementation

This commit is contained in:
David Westgate 2023-11-25 13:53:52 -08:00
parent 7e4a6578dc
commit 52c757ea3a
3 changed files with 152 additions and 43 deletions

View File

@ -1,6 +1,6 @@
use prompted::input; use prompted::input;
use rust_irc::codes::client::*; use rust_irc::codes;
use std::io::{ Read, Write}; use std::io::{Read, Write};
use std::net::TcpStream; use std::net::TcpStream;
use std::thread; use std::thread;
@ -12,8 +12,8 @@ fn read_messages(mut stream: TcpStream) {
if size == 0 { if size == 0 {
break; //Server closed connection break; //Server closed connection
} }
let message: &[u8] = &buffer[..size]; let msg_bytes: &[u8] = &buffer[..size];
process_message(message); process_message(msg_bytes);
} }
Err(_) => { Err(_) => {
break; break;
@ -22,12 +22,62 @@ fn read_messages(mut stream: TcpStream) {
} }
} }
fn process_message(message: &[u8]) { fn process_message(msg_bytes: &[u8]) {
if let Ok(text) = String::from_utf8(message.to_vec()) { match msg_bytes[0] {
println!("from serv: {}", text); 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() { pub fn start() {
println!("Starting the IRC client"); println!("Starting the IRC client");
let nick: String = input!("Enter your nickname: "); 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") { if let Ok(mut stream) = TcpStream::connect(host.to_owned() + ":6667") {
println!("Connected to {}", host); println!("Connected to {}", host);
//try to register the nickname
let mut buf: Vec<u8> = 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 //another stream for reading messages
let stream_clone: TcpStream = stream.try_clone().expect("Failed to clone stream"); let stream_clone: TcpStream = stream.try_clone().expect("Failed to clone stream");
thread::spawn(move || { thread::spawn(move || {
read_messages(stream_clone); read_messages(stream_clone);
}); });
//try to register the nickname
let mut buf: Vec<u8> = 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 { loop {
let cmd: String = input!(":"); let cmd: String = input!(":");
match cmd.trim() { match cmd.trim() {
"/quit" => {} "/quit" => disconnect(),
"/list" => {} "/rooms" => rooms(&mut stream),
"/msq" => {} "/users" => users(&mut stream),
"/join" => {} "/join" => join(&mut stream),
"/show" => {} "/show" => show(&mut stream),
"/leave" => {} "/leave" => leave(&mut stream),
"/msg" => {} "/msg" => msg(&mut stream),
_ => { _ => msg(&mut stream),
stream.write(cmd.as_bytes());
}
} }
} }
} else { } else {

View File

@ -7,6 +7,7 @@ pub mod codes {
pub const LIST_ROOMS: u8 = 0x04; pub const LIST_ROOMS: u8 = 0x04;
pub const SEND_MESSAGE: u8 = 0x05; pub const SEND_MESSAGE: u8 = 0x05;
pub const REGISTER_NICK: u8 = 0x06; pub const REGISTER_NICK: u8 = 0x06;
pub const LIST_USERS: u8 = 0x07;
} }
pub const KEEP_ALIVE: u8 = 0x0C; pub const KEEP_ALIVE: u8 = 0x0C;
pub const RESPONSE: u8 = 0x0D; pub const RESPONSE: u8 = 0x0D;

View File

@ -27,31 +27,90 @@ impl Server {
} }
fn handle_client(&mut self, mut stream: TcpStream) { fn handle_client(&mut self, mut stream: TcpStream) {
let mut buffer: [u8; 1024] = [0; 1024]; // handle user commands
let nickname: String;
// Read the nickname from the client loop {
match stream.read(&mut buffer) { let mut buf_in: [u8; 1024] = [0; 1024];
match stream.read(&mut buf_in) {
Ok(size) => { Ok(size) => {
let nickname_bytes = &buffer[0..size]; let cmd_bytes: &[u8] = &buf_in[0..1];
nickname = String::from_utf8_lossy(nickname_bytes).to_string(); 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<u8> = 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<u8> = 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<u8> = 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,
} }
}
// Check for nickname collision
if self.users.contains(&nickname) {
stream.write_all(&[codes::ERROR, codes::error::NICKNAME_COLLISION]);
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]);
} else {
// Add the user to the user list // Add the user to the user list
self.users.insert(nickname.clone()); self.users.insert(nickname.clone());
// Send response ok // Send response ok
stream.write_all(&[codes::RESPONSE_OK]); stream.write_all(&[codes::RESPONSE_OK]);
}
// handle user commands
} }
} }
@ -87,7 +146,8 @@ pub fn start() {
Ok(mut stream) => { Ok(mut stream) => {
let mut cmd_buf: [i32; 2] = [0; 2]; let mut cmd_buf: [i32; 2] = [0; 2];
let mut local_server = server_mutx.lock().unwrap(); let mut local_server = server_mutx.lock().unwrap();
#[cfg(debug_assertions)]
println!("match stream");
if local_server.users.len() < MAX_USERS { if local_server.users.len() < MAX_USERS {
local_server.handle_client(stream); local_server.handle_client(stream);
} else { } else {