client and server cli optimizations
This commit is contained in:
parent
bdf70ea8d5
commit
2697653b76
132
src/client.rs
132
src/client.rs
@ -58,12 +58,12 @@ fn read_messages(mut stream: TcpStream) {
|
|||||||
|
|
||||||
fn process_message(msg_bytes: &[u8]) {
|
fn process_message(msg_bytes: &[u8]) {
|
||||||
match msg_bytes[0] {
|
match msg_bytes[0] {
|
||||||
codes::ERROR => {
|
codes::ERROR =>
|
||||||
|
{
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("err: {:x?}", msg_bytes[1]);
|
|
||||||
match msg_bytes[1] {
|
match msg_bytes[1] {
|
||||||
codes::error::INVALID_ROOM => {
|
codes::error::INVALID_ROOM => {
|
||||||
println!("Attempted to message or list non-existant room. Try again");
|
println!("Operation Performed on an invalid room. Try again");
|
||||||
}
|
}
|
||||||
codes::error::NICKNAME_COLLISION => {
|
codes::error::NICKNAME_COLLISION => {
|
||||||
println!(
|
println!(
|
||||||
@ -98,11 +98,23 @@ fn process_message(msg_bytes: &[u8]) {
|
|||||||
|
|
||||||
fn disconnect() {}
|
fn disconnect() {}
|
||||||
|
|
||||||
fn show(stream: &mut TcpStream) {}
|
fn help() {
|
||||||
|
println!("Available commands:");
|
||||||
|
println!("/quit <- Disconnect and stop the client");
|
||||||
|
println!("/rooms <- List all of the rooms on the server");
|
||||||
|
println!("/users <- List all of the user connected to the server");
|
||||||
|
println!("/list [room-name] <- List all of the users in the given room");
|
||||||
|
println!("/join [room-name] <- Join the given room. Create the room if it does not exist");
|
||||||
|
println!(
|
||||||
|
"/leave [room-name] <- Leave the given room. Error if the you are not already in the room"
|
||||||
|
);
|
||||||
|
println!("/show [room-name] <- Switch your focus to the given room. It is suggested to join the room first");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start() {
|
pub fn start() {
|
||||||
println!("Starting the IRC client. No spaces allowed in nicknames or room names");
|
println!("Starting the IRC client. No spaces allowed in nicknames or room names");
|
||||||
let mut nick: String;
|
let mut nick: String;
|
||||||
|
let mut active_room: String = String::new();
|
||||||
loop {
|
loop {
|
||||||
nick = input!("Enter your nickname : ");
|
nick = input!("Enter your nickname : ");
|
||||||
if nick.contains(" ") {
|
if nick.contains(" ") {
|
||||||
@ -125,47 +137,87 @@ pub fn start() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//try to register the nickname
|
//try to register the nickname
|
||||||
let mut buf: Vec<u8> = vec![0; nick.capacity()];
|
one_param_op(codes::client::REGISTER_NICK, &mut stream, &nick);
|
||||||
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).unwrap();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let inp: String = input!(":");
|
let inp: String = input!(":");
|
||||||
let cmds: Vec<_> = inp.split(" ").collect();
|
let mut args: std::str::SplitWhitespace<'_> = inp.split_whitespace();
|
||||||
match *cmds.get(0).unwrap() {
|
let command: Option<&str> = args.next();
|
||||||
"/quit" => disconnect(),
|
|
||||||
"/rooms" => no_param_op(codes::client::LIST_ROOMS, &mut stream),
|
|
||||||
"/users" => no_param_op(codes::client::LIST_USERS, &mut stream),
|
|
||||||
"/list" => {
|
|
||||||
let room = *cmds.get(1).unwrap();
|
|
||||||
one_param_op(codes::client::LIST_USERS_IN_ROOM, &mut stream, room);
|
|
||||||
}
|
|
||||||
"/join" => {
|
|
||||||
let room = *cmds.get(1).unwrap();
|
|
||||||
one_param_op(codes::client::JOIN_ROOM, &mut stream, room);
|
|
||||||
}
|
|
||||||
"/show" => show(&mut stream),
|
|
||||||
"/leave" => {
|
|
||||||
let room: &str = *cmds.get(1).unwrap();
|
|
||||||
one_param_op(codes::client::LEAVE_ROOM, &mut stream, room);
|
|
||||||
}
|
|
||||||
"/msg" => {
|
|
||||||
let room: &str = *cmds.get(1).unwrap();
|
|
||||||
// let message = *cmds.
|
|
||||||
// two_param_op(
|
|
||||||
// codes::client::SEND_MESSAGE_TO_ROOM,
|
|
||||||
// &mut stream,
|
|
||||||
// param0,
|
|
||||||
// param1,
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
match command {
|
||||||
println!("Not implemented");
|
Some(cmd) => {
|
||||||
|
let param: Option<&str> = args.next();
|
||||||
|
match cmd {
|
||||||
|
"/quit" => disconnect(),
|
||||||
|
"/rooms" => no_param_op(codes::client::LIST_ROOMS, &mut stream),
|
||||||
|
"/users" => no_param_op(codes::client::LIST_USERS, &mut stream),
|
||||||
|
"/list" => match param {
|
||||||
|
Some(room) => {
|
||||||
|
one_param_op(codes::client::LIST_USERS_IN_ROOM, &mut stream, room);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Room name expected, but not provided");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/join" => match param {
|
||||||
|
Some(room) => {
|
||||||
|
one_param_op(codes::client::JOIN_ROOM, &mut stream, room);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Room name expected, but not provided");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/show" => match param {
|
||||||
|
Some(room) => {
|
||||||
|
active_room = room.to_string();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Room name expected, but not provided")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/leave" => match param {
|
||||||
|
Some(room) => {
|
||||||
|
one_param_op(codes::client::LEAVE_ROOM, &mut stream, room);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Room name expected, but not provided");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/msg" => match inp.split_once(" ") {
|
||||||
|
Some((room, msg)) => {
|
||||||
|
two_param_op(
|
||||||
|
codes::client::SEND_MESSAGE_TO_ROOM,
|
||||||
|
&mut stream,
|
||||||
|
room,
|
||||||
|
msg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("Usage: /msg [room] [message]");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/help" => {
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
"/" => {
|
||||||
|
println!("Invalid command");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if active_room.is_empty() {
|
||||||
|
println!("use '/show [room]' to set an active room before sending a message");
|
||||||
|
} else {
|
||||||
|
let message: String = inp;
|
||||||
|
two_param_op(
|
||||||
|
codes::client::SEND_MESSAGE_TO_ROOM,
|
||||||
|
&mut stream,
|
||||||
|
&active_room,
|
||||||
|
&message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -23,5 +23,11 @@ pub mod codes {
|
|||||||
pub const SERVER_FULL: u8 = 0x12;
|
pub const SERVER_FULL: u8 = 0x12;
|
||||||
pub const ALREADY_REGISTERED: u8 = 0x13;
|
pub const ALREADY_REGISTERED: u8 = 0x13;
|
||||||
pub const NOT_YET_REGISTERED: u8 = 0x14;
|
pub const NOT_YET_REGISTERED: u8 = 0x14;
|
||||||
|
pub const MALFORMED: u8 = 0x15;
|
||||||
|
pub const ALREADY_IN_ROOM: u8 = 0x16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear() {
|
||||||
|
print!("\x1B[2J");
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::HashMap,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
net::{TcpListener, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
thread,
|
thread,
|
||||||
@ -14,28 +14,28 @@ const MAX_USERS: usize = 20;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Server {
|
struct Server {
|
||||||
users: HashSet<String>,
|
users: HashMap<String, TcpStream>,
|
||||||
rooms: HashMap<String, Vec<String>>,
|
rooms: HashMap<String, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Server {
|
Server {
|
||||||
users: HashSet::new(),
|
users: HashMap::new(),
|
||||||
rooms: HashMap::new(),
|
rooms: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_all(op:u8, listener: TcpListener) {
|
fn message(room: &str, message: &str) {}
|
||||||
|
|
||||||
|
fn send_all(op: u8, listener: TcpListener) {
|
||||||
for tcpstream in listener.incoming() {
|
for tcpstream in listener.incoming() {
|
||||||
match tcpstream {
|
match tcpstream {
|
||||||
Ok(mut stream) => {
|
Ok(mut stream) => {
|
||||||
stream.write_all(&[op]).unwrap();
|
stream.write_all(&[op]).unwrap();
|
||||||
},
|
|
||||||
Err(_) => {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ fn handle_client(
|
|||||||
let unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
|
let unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
|
||||||
let mut buf_out: Vec<u8> = Vec::new();
|
let mut buf_out: Vec<u8> = Vec::new();
|
||||||
buf_out.extend_from_slice(&[codes::RESPONSE]);
|
buf_out.extend_from_slice(&[codes::RESPONSE]);
|
||||||
for user in &unlocked_server.users {
|
for (user, _) in &unlocked_server.users {
|
||||||
buf_out.extend_from_slice(user.as_bytes());
|
buf_out.extend_from_slice(user.as_bytes());
|
||||||
buf_out.extend_from_slice(&[0x20]);
|
buf_out.extend_from_slice(&[0x20]);
|
||||||
}
|
}
|
||||||
@ -99,22 +99,39 @@ fn handle_client(
|
|||||||
|
|
||||||
codes::client::JOIN_ROOM => {
|
codes::client::JOIN_ROOM => {
|
||||||
let p: String = String::from_utf8_lossy(param_bytes).to_string();
|
let p: String = String::from_utf8_lossy(param_bytes).to_string();
|
||||||
let params: Vec<&str> = p.split(' ').collect();
|
let params: Vec<&str> = p.split_whitespace().collect();
|
||||||
let room = params.get(0).unwrap();
|
let room = params.get(0).unwrap();
|
||||||
join_room(server, &nickname, room, stream)
|
join_room(server, &nickname, room, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
codes::client::LEAVE_ROOM => {
|
codes::client::LEAVE_ROOM => {
|
||||||
let p: String = String::from_utf8_lossy(param_bytes).to_string();
|
let p: String = String::from_utf8_lossy(param_bytes).to_string();
|
||||||
let params: Vec<&str> = p.split(' ').collect();
|
let params: Vec<&str> = p.split_whitespace().collect();
|
||||||
let room = params.get(0).unwrap();
|
let room = params.get(0).unwrap();
|
||||||
leave_room(server, &nickname, room, stream)
|
leave_room(server, &nickname, room, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
codes::client::SEND_MESSAGE => {
|
codes::client::SEND_MESSAGE => {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("SEND_MESSAGE");
|
println!("SEND_MESSAGE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codes::client::SEND_MESSAGE_TO_ROOM => {
|
||||||
|
let p: String = String::from_utf8_lossy(param_bytes).to_string();
|
||||||
|
let params: Option<(&str, &str)> = p.split_once(" ");
|
||||||
|
match params {
|
||||||
|
Some((room, msg)) => {
|
||||||
|
message(room, msg);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
stream
|
||||||
|
.write(&[codes::ERROR, codes::error::MALFORMED])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("SEND_MESSAGE_TO_ROOM, {} ", p);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("Unspecified client Op, {:x?}", cmd_bytes);
|
println!("Unspecified client Op, {:x?}", cmd_bytes);
|
||||||
@ -127,15 +144,16 @@ fn handle_client(
|
|||||||
fn register_nick(server: &Arc<Mutex<Server>>, nickname: &str, stream: &mut TcpStream) {
|
fn register_nick(server: &Arc<Mutex<Server>>, nickname: &str, stream: &mut TcpStream) {
|
||||||
// Check for nickname collision
|
// Check for nickname collision
|
||||||
let mut unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
|
let mut unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
|
||||||
if unlocked_server.users.contains(nickname) {
|
if unlocked_server.users.contains_key(nickname) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("Nickname Collision, {}", nickname);
|
println!("Nickname Collision, {}", nickname);
|
||||||
stream
|
stream
|
||||||
.write_all(&[codes::ERROR, codes::error::NICKNAME_COLLISION])
|
.write_all(&[codes::ERROR, codes::error::NICKNAME_COLLISION])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
let stream_clone = stream.try_clone().expect("failed to clone");
|
||||||
// Add the user to the user list
|
// Add the user to the user list
|
||||||
unlocked_server.users.insert(nickname.to_string());
|
unlocked_server.users.insert(nickname.to_string(), stream_clone);
|
||||||
|
|
||||||
// Send response ok
|
// Send response ok
|
||||||
stream.write_all(&[codes::RESPONSE_OK]).unwrap();
|
stream.write_all(&[codes::RESPONSE_OK]).unwrap();
|
||||||
@ -147,6 +165,12 @@ fn join_room(server: &Arc<Mutex<Server>>, user: &str, room: &str, stream: &mut T
|
|||||||
|
|
||||||
match unlocked_server.rooms.get_mut(room) {
|
match unlocked_server.rooms.get_mut(room) {
|
||||||
Some(l) => {
|
Some(l) => {
|
||||||
|
for ele in l.into_iter() {
|
||||||
|
if ele == user{
|
||||||
|
stream.write_all(&[codes::ERROR, codes::error::ALREADY_IN_ROOM]).unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
l.push(user.to_string());
|
l.push(user.to_string());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -184,7 +208,6 @@ fn leave_room(server: &Arc<Mutex<Server>>, user: &str, room: &str, stream: &mut
|
|||||||
|
|
||||||
pub fn start() {
|
pub fn start() {
|
||||||
let listener: TcpListener = TcpListener::bind(SERVER_ADDRESS).expect("Failed to bind to port");
|
let listener: TcpListener = TcpListener::bind(SERVER_ADDRESS).expect("Failed to bind to port");
|
||||||
// let incoming: &std::net::Incoming = &listener.incoming();
|
|
||||||
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);
|
||||||
println!("Server listening on {}", SERVER_ADDRESS);
|
println!("Server listening on {}", SERVER_ADDRESS);
|
||||||
@ -256,7 +279,9 @@ pub fn start() {
|
|||||||
let inp: String = input!(":");
|
let inp: String = input!(":");
|
||||||
match inp.parse::<u8>() {
|
match inp.parse::<u8>() {
|
||||||
Ok(num) => match num {
|
Ok(num) => match num {
|
||||||
0 => {println!("Goodbye"); },
|
0 => {
|
||||||
|
println!("Goodbye");
|
||||||
|
}
|
||||||
1 => println!("Users: {:?}", server.lock().unwrap().users),
|
1 => println!("Users: {:?}", server.lock().unwrap().users),
|
||||||
2 => println!("Rooms: {:?}", server.lock().unwrap().rooms),
|
2 => println!("Rooms: {:?}", server.lock().unwrap().rooms),
|
||||||
_ => println!("Invalid Input"),
|
_ => println!("Invalid Input"),
|
||||||
|
Reference in New Issue
Block a user