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 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::net::TcpStream;
use std::sync::{Arc, Mutex};
@ -43,7 +44,7 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
eprintln!("Server is full. Try again later");
}
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 => {
eprintln!("Room is Empty");
@ -200,7 +201,7 @@ pub fn start() {
},
"/msg" => match param.split_once(' ') {
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();
}
_ => {

View File

@ -29,37 +29,36 @@ pub mod codes {
}
pub const DEFAULT_PORT: u16 = 6667;
pub fn clear() {
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] {
[opcode]
}
}
pub fn two_op_buf(opcode0: u8, opcode1: u8) -> [u8; 2] {
pub fn two_op_buf(opcode0: u8, opcode1: u8) -> [u8; 2] {
[opcode0, opcode1]
}
}
pub fn one_param_buf(opcode: u8, param: &str) -> Vec<u8> {
pub fn one_param_buf(opcode: u8, param: &str) -> Vec<u8> {
let opcode_buf: &[u8; 1] = &[opcode];
let param_buf: &[u8] = param.as_bytes();
let out_buf: Vec<u8> = [opcode_buf, param_buf].concat();
out_buf
}
}
pub fn two_param_buf(opcode: u8, param0: &str, param1: &str) -> Vec<u8> {
pub fn two_param_buf(opcode: u8, param0: &str, param1: &str) -> Vec<u8> {
let opcode_buf: &[u8; 1] = &[opcode];
let param0_buf: &[u8] = param0.as_bytes();
let param1_buf: &[u8] = param1.as_bytes();
let out_buf: Vec<u8> = [opcode_buf, param0_buf, SPACE_BYTES, param1_buf].concat();
out_buf
}
}
pub fn three_param_buf(opcode: u8, param0: &str, param1: &str, param2: &str) -> Vec<u8> {
pub fn three_param_buf(opcode: u8, param0: &str, param1: &str, param2: &str) -> Vec<u8> {
let opcode_buf: &[u8; 1] = &[opcode];
let param0_buf: &[u8] = param0.as_bytes();
let param1_buf: &[u8] = param1.as_bytes();
@ -75,4 +74,5 @@ pub fn three_param_buf(opcode: u8, param0: &str, param1: &str, param2: &str) ->
]
.concat();
out_buf
}
}

View File

@ -8,9 +8,8 @@ use std::{
};
use prompted::input;
use rust_irc::{
clear, codes, one_op_buf, one_param_buf, three_param_buf, two_op_buf, DEFAULT_PORT,
};
use rust_irc::buf_helpers::{one_op_buf, one_param_buf, three_param_buf, two_op_buf};
use rust_irc::{clear, codes, DEFAULT_PORT};
#[derive(Debug)]
struct Server {
@ -43,10 +42,8 @@ fn message_room(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>
.unwrap()
.try_clone()
.expect("Clone issue");
//1
match room_users {
Some(users) => {
//2
let mut is_member = false;
for user in users {
if user.eq(sender) {
@ -57,12 +54,10 @@ fn message_room(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>
if is_member {
for user in users {
if user.eq(sender) {
//4
sender_stream
.write_all(&one_op_buf(codes::RESPONSE_OK))
.unwrap();
} else {
//3
let recipient_stream: Option<&mut TcpStream> = server.users.get_mut(user);
match recipient_stream {
Some(str) => {
@ -305,18 +300,15 @@ fn leave_room(server: &Arc<Mutex<Server>>, user: &str, room: &str, stream: &mut
Some(l) => {
let before_len: usize = l.len();
l.retain(|item: &String| item != user);
if l.is_empty() {
unlocked_server.rooms.remove(room);
drop(unlocked_server);
let rooms: Vec<String> = get_rooms_of_user(server, user);
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);
// case when the user was not found to be in the room.
if l.len() == before_len {
let err_buf: [u8; 2] = two_op_buf(codes::ERROR, codes::error::NOT_IN_ROOM);
stream.write_all(&err_buf).unwrap();
} else {
if l.is_empty() {
unlocked_server.rooms.remove(room); //drop the room if this was the last member
}
drop(unlocked_server);
let rooms: Vec<String> = get_rooms_of_user(server, user);
let rooms_expanded: String = rooms.join(",");
@ -350,6 +342,11 @@ fn get_rooms_of_user(server: &Arc<Mutex<Server>>, user: &str) -> Vec<String> {
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() {
let mut host: String = "0.0.0.0:".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);
}