refactor client to lib code; abstract default port

This commit is contained in:
David Westgate 2023-12-03 17:51:33 -08:00
parent c67f358d4a
commit 60b5013337
3 changed files with 52 additions and 62 deletions

View File

@ -1,44 +1,12 @@
use prompted::input; use prompted::input;
use rust_irc::{clear, codes}; use rust_irc::{clear, codes, one_op_buf, one_param_buf, two_param_buf, 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};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
fn no_param_op(opcode: u8, stream: &mut TcpStream) { const DEFAULT_HOST: &str = "localhost";
stream.write_all(&[opcode]).unwrap();
}
fn one_param_op(opcode: u8, stream: &mut TcpStream, param: &str) {
let size: usize = param.to_string().capacity() + 1;
let mut out_buf: Vec<u8> = vec![0; size];
out_buf[0] = opcode;
for i in 1..param.len() + 1 {
out_buf[i] = *param.as_bytes().get(i - 1).unwrap();
}
stream.write_all(&out_buf).unwrap();
}
fn two_param_op(opcode: u8, stream: &mut TcpStream, param0: &str, param1: &str) {
let size: usize = param0.to_string().capacity() + param1.to_string().capacity() + 2;
let mut out_buf: Vec<u8> = vec![0; size];
let mut byte: usize = 0;
out_buf[byte] = opcode;
byte += 1;
for i in 0..param0.len() {
out_buf[byte] = *param0.as_bytes().get(i).unwrap();
byte += 1;
}
out_buf[byte] = 0x20;
byte += 1;
for i in 0..param1.len() {
out_buf[byte] = *param1.as_bytes().get(i).unwrap();
byte += 1;
}
stream.write_all(&out_buf).unwrap();
}
fn read_messages(mut stream: TcpStream, nick: &str, timestamp: &mut Arc<Mutex<Instant>>) { fn read_messages(mut stream: TcpStream, nick: &str, timestamp: &mut Arc<Mutex<Instant>>) {
let mut buffer: [u8; 1024] = [0; 1024]; let mut buffer: [u8; 1024] = [0; 1024];
@ -49,7 +17,7 @@ fn read_messages(mut stream: TcpStream, nick: &str, timestamp: &mut Arc<Mutex<In
std::process::exit(0); std::process::exit(0);
} }
Ok(size) => { Ok(size) => {
let mut lock = timestamp.lock().unwrap(); let mut lock: std::sync::MutexGuard<'_, Instant> = timestamp.lock().unwrap();
*lock = Instant::now(); *lock = Instant::now();
let msg_bytes: &[u8] = &buffer[..size]; let msg_bytes: &[u8] = &buffer[..size];
process_message(msg_bytes, nick); process_message(msg_bytes, nick);
@ -94,7 +62,7 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
println!("[server]:{}", message); println!("[server]:{}", message);
} }
codes::MESSAGE_ROOM => { codes::MESSAGE_ROOM => {
let params = String::from_utf8(msg_bytes[1..msg_bytes.len()].to_vec()).unwrap(); let params: String = String::from_utf8(msg_bytes[1..msg_bytes.len()].to_vec()).unwrap();
match params.split_once(' ') { match params.split_once(' ') {
Some((room, remainder)) => match remainder.split_once(' ') { Some((room, remainder)) => match remainder.split_once(' ') {
Some((user, msg)) => { Some((user, msg)) => {
@ -122,8 +90,7 @@ fn process_message(msg_bytes: &[u8], nick: &str) {
std::process::exit(0); std::process::exit(0);
} }
_ => { _ => {
#[cfg(debug_assertions)] eprintln!("BAD RESPONSE = {:x?} ", msg_bytes[0]);
println!("BAD RESPONSE = {:x?} ", msg_bytes[0]);
} }
} }
} }
@ -160,10 +127,14 @@ pub fn start() {
} }
} }
let host: String = input!("Enter the server host: "); let mut host: String = input!("Enter the server host (empty for {}): ", DEFAULT_HOST);
if host.is_empty() {
if let Ok(mut stream) = TcpStream::connect(host.to_owned() + ":6667") { host = DEFAULT_HOST.to_owned();
println!("Connected to {}. /help to see available commands", host); }
host.push(':');
host.push_str(&DEFAULT_PORT.to_string());
if let Ok(mut stream) = TcpStream::connect(host.to_owned()) {
println!("Connected to {}.\n/help to see available commands", host);
//another stream for reading messages //another stream for reading messages
let reader_clone: TcpStream = stream.try_clone().expect("Failed to clone stream"); let reader_clone: TcpStream = stream.try_clone().expect("Failed to clone stream");
@ -192,8 +163,8 @@ pub fn start() {
}); });
//try to register the nickname //try to register the nickname
one_param_op(codes::REGISTER_NICK, &mut stream, &nick); let nick_reg_buff: Vec<u8> = one_param_buf(codes::REGISTER_NICK, &nick);
stream.write_all(&nick_reg_buff).unwrap();
loop { loop {
let inp: String = input!(""); let inp: String = input!("");
@ -204,7 +175,8 @@ pub fn start() {
eprintln!("Malformaed. Try /list [room-name]"); eprintln!("Malformaed. Try /list [room-name]");
} }
_ => { _ => {
one_param_op(codes::LIST_USERS_IN_ROOM, &mut stream, param); let out_buf: Vec<u8> = one_param_buf(codes::LIST_USERS_IN_ROOM, param);
stream.write_all(&out_buf).unwrap();
} }
}, },
"/join" => match param.split_once(' ') { "/join" => match param.split_once(' ') {
@ -212,7 +184,8 @@ pub fn start() {
eprintln!("Malformed. Try /join [room-name]"); eprintln!("Malformed. Try /join [room-name]");
} }
_ => { _ => {
one_param_op(codes::JOIN_ROOM, &mut stream, param); let out_buf: Vec<u8> = one_param_buf(codes::JOIN_ROOM, param);
stream.write_all(&out_buf).unwrap();
} }
}, },
@ -221,18 +194,23 @@ pub fn start() {
eprintln!("Malformed. Try /leave [room-name]"); eprintln!("Malformed. Try /leave [room-name]");
} }
_ => { _ => {
one_param_op(codes::LEAVE_ROOM, &mut stream, param); let out_buf: Vec<u8> = one_param_buf(codes::LEAVE_ROOM, param);
stream.write_all(&out_buf).unwrap();
} }
}, },
"/msg" => match param.split_once(' ') { "/msg" => match param.split_once(' ') {
Some((room, msg)) => { Some((room, msg)) => {
two_param_op(codes::MESSAGE_ROOM, &mut stream, room, msg); let out_buf = two_param_buf(codes::MESSAGE_ROOM, room, msg);
stream.write_all(&out_buf).unwrap();
} }
_ => { _ => {
eprintln!("Usage: /msg [room] [message]"); eprintln!("Usage: /msg [room] [message]");
} }
}, },
_ => one_param_op(codes::MESSAGE, &mut stream, &inp), _ => {
let out_buf: Vec<u8> = one_param_buf(codes::MESSAGE, &inp);
stream.write_all(&out_buf).unwrap();
}
}, },
_ => match inp.as_str() { _ => match inp.as_str() {
@ -240,15 +218,24 @@ pub fn start() {
disconnect(&mut stream); disconnect(&mut stream);
break; break;
} }
"/rooms" => no_param_op(codes::LIST_ROOMS, &mut stream), "/rooms" => {
"/users" => no_param_op(codes::LIST_USERS, &mut stream), let out_buf: [u8; 1] = one_op_buf(codes::LIST_ROOMS);
stream.write_all(&out_buf).unwrap();
}
"/users" => {
let out_buf: [u8; 1] = one_op_buf(codes::LIST_USERS);
stream.write_all(&out_buf).unwrap();
}
"/help" => { "/help" => {
help(); help();
} }
"/" => { "/" => {
println!("Invalid command"); eprintln!("Invalid command");
}
_ => {
let out_buf: Vec<u8> = one_param_buf(codes::MESSAGE, &inp);
stream.write_all(&out_buf).unwrap();
} }
_ => one_param_op(codes::MESSAGE, &mut stream, &inp),
}, },
} }
} }

View File

@ -28,6 +28,8 @@ pub mod codes {
} }
} }
pub const DEFAULT_PORT: u16 = 6667;
pub fn clear() { pub fn clear() {
print!("\x1B[2J"); print!("\x1B[2J");
} }

View File

@ -8,9 +8,9 @@ use std::{
}; };
use prompted::input; use prompted::input;
use rust_irc::{clear, codes, one_op_buf, one_param_buf, three_param_buf, two_op_buf}; use rust_irc::{
clear, codes, one_op_buf, one_param_buf, three_param_buf, two_op_buf, DEFAULT_PORT,
const SERVER_ADDRESS: &str = "0.0.0.0:6667"; };
#[derive(Debug)] #[derive(Debug)]
struct Server { struct Server {
@ -66,7 +66,6 @@ fn message_room(room: &str, msg: &str, sender: &str, server: &Arc<Mutex<Server>>
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) => {
println!("Sending msg {:?}", out_buf.to_ascii_lowercase());
str.write_all(&out_buf).unwrap(); str.write_all(&out_buf).unwrap();
} }
None => { None => {
@ -227,7 +226,7 @@ fn message_all_senders_rooms(
let mut guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap(); let mut guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
for room in rooms { for room in rooms {
let users: Vec<String> = guard.rooms.get(&room).unwrap().clone(); let users: Vec<String> = guard.rooms.get(&room).unwrap().clone();
let out_buf: Vec<u8> = three_param_buf(codes::MESSAGE_ROOM, &room, &sender, &message); let out_buf: Vec<u8> = three_param_buf(codes::MESSAGE_ROOM, &room, sender, message);
for user in users { for user in users {
if !user.eq(sender) { if !user.eq(sender) {
let stream: Option<&mut TcpStream> = guard.users.get_mut(&user); let stream: Option<&mut TcpStream> = guard.users.get_mut(&user);
@ -339,8 +338,8 @@ fn get_rooms_of_user(server: &Arc<Mutex<Server>>, user: &str) -> Vec<String> {
let mut result: Vec<String> = vec![]; let mut result: Vec<String> = vec![];
let guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap(); let guard: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
let rooms: std::collections::hash_map::Keys<'_, String, Vec<String>> = guard.rooms.keys(); let rooms: std::collections::hash_map::Keys<'_, String, Vec<String>> = guard.rooms.keys();
rooms.for_each(|room| { rooms.for_each(|room: &String| {
let user_vec = guard.rooms.get(room).unwrap(); let user_vec: &Vec<String> = guard.rooms.get(room).unwrap();
for usr in user_vec { for usr in user_vec {
if usr.eq(user) { if usr.eq(user) {
result.push(room.to_string()); result.push(room.to_string());
@ -352,13 +351,15 @@ fn get_rooms_of_user(server: &Arc<Mutex<Server>>, user: &str) -> Vec<String> {
} }
pub fn start() { pub fn start() {
let listener_result: Result<TcpListener, std::io::Error> = TcpListener::bind(SERVER_ADDRESS); let mut host: String = "0.0.0.0:".to_string();
host.push_str(&DEFAULT_PORT.to_string());
let listener_result: Result<TcpListener, std::io::Error> = TcpListener::bind(host.to_owned());
match listener_result { match listener_result {
Ok(listener) => { Ok(listener) => {
let server: Arc<Mutex<Server>> = Arc::new(Mutex::new(Server::new())); let server: Arc<Mutex<Server>> = Arc::new(Mutex::new(Server::new()));
let server_outer: Arc<Mutex<Server>> = Arc::clone(&server); let server_outer: Arc<Mutex<Server>> = Arc::clone(&server);
clear(); clear();
println!("Server listening on {}", SERVER_ADDRESS); println!("Server listening on {}", host);
thread::spawn(move || { thread::spawn(move || {
for tcpstream in listener.incoming() { for tcpstream in listener.incoming() {