more modularization; add comments

This commit is contained in:
David Westgate 2023-12-03 20:20:26 -08:00
parent 60b5013337
commit 8f3dcaac5a
4 changed files with 117 additions and 61 deletions

View File

@ -1,5 +1,6 @@
use prompted::input; use prompted::input;
use rust_irc::{clear, codes, one_op_buf, one_param_buf, two_param_buf, DEFAULT_PORT}; use rust_irc::buf_helpers::{one_op_buf, one_param_buf, two_param_buf};
use rust_irc::{clear, codes, DEFAULT_PORT};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::TcpStream; use std::net::TcpStream;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -43,7 +44,7 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
eprintln!("Server is full. Try again later"); eprintln!("Server is full. Try again later");
} }
codes::error::NOT_IN_ROOM => { codes::error::NOT_IN_ROOM => {
eprintln!("Cannot send a message before joining room. Use /join [room].") eprintln!("Cannot interact with a room you have not joined. Use /join [room].")
} }
codes::error::EMPTY_ROOM => { codes::error::EMPTY_ROOM => {
eprintln!("Room is Empty"); eprintln!("Room is Empty");
@ -200,7 +201,7 @@ pub fn start() {
}, },
"/msg" => match param.split_once(' ') { "/msg" => match param.split_once(' ') {
Some((room, msg)) => { Some((room, msg)) => {
let out_buf = two_param_buf(codes::MESSAGE_ROOM, room, msg); let out_buf: Vec<u8> = two_param_buf(codes::MESSAGE_ROOM, room, msg);
stream.write_all(&out_buf).unwrap(); stream.write_all(&out_buf).unwrap();
} }
_ => { _ => {

View File

@ -29,11 +29,10 @@ pub mod codes {
} }
pub const DEFAULT_PORT: u16 = 6667; pub const DEFAULT_PORT: u16 = 6667;
pub fn clear() { pub fn clear() {
print!("\x1B[2J"); print!("\x1B[2J");
} }
pub mod buf_helpers {
pub const SPACE_BYTES: &[u8] = &[0x20]; pub const SPACE_BYTES: &[u8] = &[0x20];
pub fn one_op_buf(opcode: u8) -> [u8; 1] { pub fn one_op_buf(opcode: u8) -> [u8; 1] {
@ -76,3 +75,4 @@ pub fn three_param_buf(opcode: u8, param0: &str, param1: &str, param2: &str) ->
.concat(); .concat();
out_buf out_buf
} }
}

View File

@ -8,9 +8,8 @@ use std::{
}; };
use prompted::input; use prompted::input;
use rust_irc::{ use rust_irc::buf_helpers::{one_op_buf, one_param_buf, three_param_buf, two_op_buf};
clear, codes, one_op_buf, one_param_buf, three_param_buf, two_op_buf, DEFAULT_PORT, use rust_irc::{clear, codes, DEFAULT_PORT};
};
#[derive(Debug)] #[derive(Debug)]
struct Server { struct Server {
@ -43,10 +42,8 @@ fn message_room(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>
.unwrap() .unwrap()
.try_clone() .try_clone()
.expect("Clone issue"); .expect("Clone issue");
//1
match room_users { match room_users {
Some(users) => { Some(users) => {
//2
let mut is_member = false; let mut is_member = false;
for user in users { for user in users {
if user.eq(sender) { if user.eq(sender) {
@ -57,12 +54,10 @@ fn message_room(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>
if is_member { if is_member {
for user in users { for user in users {
if user.eq(sender) { if user.eq(sender) {
//4
sender_stream sender_stream
.write_all(&one_op_buf(codes::RESPONSE_OK)) .write_all(&one_op_buf(codes::RESPONSE_OK))
.unwrap(); .unwrap();
} else { } else {
//3
let recipient_stream: Option<&mut TcpStream> = server.users.get_mut(user); let recipient_stream: Option<&mut TcpStream> = server.users.get_mut(user);
match recipient_stream { match recipient_stream {
Some(str) => { Some(str) => {
@ -305,18 +300,15 @@ fn leave_room(server: &Arc<Mutex<Server>>, user: &str, room: &str, stream: &mut
Some(l) => { Some(l) => {
let before_len: usize = l.len(); let before_len: usize = l.len();
l.retain(|item: &String| item != user); l.retain(|item: &String| item != user);
if l.is_empty() {
unlocked_server.rooms.remove(room); // case when the user was not found to be in the room.
drop(unlocked_server); if l.len() == before_len {
let rooms: Vec<String> = get_rooms_of_user(server, user); let err_buf: [u8; 2] = two_op_buf(codes::ERROR, codes::error::NOT_IN_ROOM);
let rooms_expanded: String = rooms.join(",");
let response: String = format!("Left {}. Current rooms: {}", room, rooms_expanded);
let out_buf: Vec<u8> = one_param_buf(codes::RESPONSE, &response);
stream.write_all(&out_buf).unwrap();
} else if l.len() == before_len {
let err_buf: [u8; 2] = two_op_buf(codes::ERROR, codes::error::INVALID_ROOM);
stream.write_all(&err_buf).unwrap(); stream.write_all(&err_buf).unwrap();
} else { } else {
if l.is_empty() {
unlocked_server.rooms.remove(room); //drop the room if this was the last member
}
drop(unlocked_server); drop(unlocked_server);
let rooms: Vec<String> = get_rooms_of_user(server, user); let rooms: Vec<String> = get_rooms_of_user(server, user);
let rooms_expanded: String = rooms.join(","); let rooms_expanded: String = rooms.join(",");
@ -350,6 +342,11 @@ fn get_rooms_of_user(server: &Arc<Mutex<Server>>, user: &str) -> Vec<String> {
result result
} }
/// Entrypoint for the server
/// Main thread -> Main Menu
/// We spawn one thread to manage the entire TCP incoming process (seperate from main thread)
/// Each connected IP gets a spawned thread in the `for` loop
/// Before looping to handle generic client input, we handle the special case of the nickname registration requirnment
pub fn start() { pub fn start() {
let mut host: String = "0.0.0.0:".to_string(); let mut host: String = "0.0.0.0:".to_string();
host.push_str(&DEFAULT_PORT.to_string()); host.push_str(&DEFAULT_PORT.to_string());

58
tests/test_lib.rs Normal file
View File

@ -0,0 +1,58 @@
use rust_irc::{
buf_helpers::{
one_op_buf, one_param_buf, three_param_buf, two_op_buf, two_param_buf, SPACE_BYTES,
},
codes,
};
#[test]
pub fn test_one_op_buf() {
let buf_in: [u8; 1] = one_op_buf(codes::RESPONSE_OK);
assert_eq!(buf_in, [codes::RESPONSE_OK])
}
#[test]
pub fn test_two_op_buf() {
let buf_in: [u8; 2] = two_op_buf(codes::ERROR, codes::error::ALREADY_IN_ROOM);
assert_eq!(buf_in, [codes::ERROR, codes::error::ALREADY_IN_ROOM]);
}
#[test]
pub fn test_one_param_buf() {
let opcode_buf: &[u8; 1] = &[codes::MESSAGE];
let string_buf: &[u8] = "hello world".as_bytes();
let checker_buf: Vec<u8> = [opcode_buf, string_buf].concat();
let result: Vec<u8> = one_param_buf(codes::MESSAGE, "hello world");
assert_eq!(result, checker_buf);
}
#[test]
pub fn test_two_param_buf() {
let opcode_buf: &[u8; 1] = &[codes::MESSAGE];
let string0_buf: &[u8] = "cat".as_bytes();
let string1_buf: &[u8] = "dog".as_bytes();
let checker_buf: Vec<u8> = [opcode_buf, string0_buf, SPACE_BYTES, string1_buf].concat();
let result: Vec<u8> = two_param_buf(codes::MESSAGE, "cat", "dog");
assert_eq!(result, checker_buf);
}
#[test]
pub fn test_three_param_buf() {
let opcode_buf: &[u8; 1] = &[codes::MESSAGE];
let string0_buf: &[u8] = "cat".as_bytes();
let string1_buf: &[u8] = "dog".as_bytes();
let string2_buf: &[u8] = "frog".as_bytes();
let checker_buf: Vec<u8> = [
opcode_buf,
string0_buf,
SPACE_BYTES,
string1_buf,
SPACE_BYTES,
string2_buf,
]
.concat();
let result: Vec<u8> = three_param_buf(codes::MESSAGE, "cat", "dog", "frog");
assert_eq!(result, checker_buf);
}