improve server threading
This commit is contained in:
parent
52c757ea3a
commit
f78acbdb10
132
src/server.rs
132
src/server.rs
@ -12,7 +12,7 @@ use rust_irc::codes;
|
|||||||
const SERVER_ADDRESS: &str = "0.0.0.0:6667";
|
const SERVER_ADDRESS: &str = "0.0.0.0:6667";
|
||||||
const MAX_USERS: usize = 20;
|
const MAX_USERS: usize = 20;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
struct Server {
|
struct Server {
|
||||||
users: HashSet<String>,
|
users: HashSet<String>,
|
||||||
rooms: HashMap<String, Vec<String>>,
|
rooms: HashMap<String, Vec<String>>,
|
||||||
@ -25,54 +25,51 @@ impl Server {
|
|||||||
rooms: HashMap::new(),
|
rooms: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_client(&mut self, mut stream: TcpStream) {
|
fn read_op() {}
|
||||||
|
|
||||||
|
fn write_op() {}
|
||||||
|
|
||||||
|
fn handle_client(
|
||||||
|
server: &Arc<Mutex<Server>>,
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
cmd_bytes: &[u8],
|
||||||
|
param_bytes: &[u8],
|
||||||
|
) {
|
||||||
// handle user commands
|
// handle user commands
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut buf_in: [u8; 1024] = [0; 1024];
|
|
||||||
|
|
||||||
match stream.read(&mut buf_in) {
|
|
||||||
Ok(size) => {
|
|
||||||
let cmd_bytes: &[u8] = &buf_in[0..1];
|
|
||||||
let param_bytes: &[u8] = &buf_in[1..size];
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
println!("Stream in ");
|
|
||||||
match cmd_bytes[0] {
|
match cmd_bytes[0] {
|
||||||
codes::client::REGISTER_NICK => {
|
codes::client::REGISTER_NICK => {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("REGISTER_NICK");
|
println!("REGISTER_NICK");
|
||||||
let nickname: String = String::from_utf8_lossy(param_bytes).to_string();
|
let nickname: String = String::from_utf8_lossy(param_bytes).to_string();
|
||||||
self.register_nick(nickname, &mut stream);
|
register_nick(server, nickname, stream);
|
||||||
}
|
}
|
||||||
codes::client::LIST_ROOMS => {
|
codes::client::LIST_ROOMS => {
|
||||||
|
let unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("LIST_ROOMS");
|
println!("LIST_ROOMS");
|
||||||
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 (room, user) in &self.rooms {
|
for (room, user) in &unlocked_server.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());
|
buf_out.extend_from_slice(room.as_bytes());
|
||||||
}
|
}
|
||||||
stream.write(&buf_out);
|
stream.write(&buf_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
codes::client::LIST_USERS => {
|
codes::client::LIST_USERS => {
|
||||||
|
let unlocked_server: std::sync::MutexGuard<'_, Server> = server.lock().unwrap();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("LIST_USERS");
|
println!("LIST_USERS");
|
||||||
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 &self.users {
|
for (user) in &unlocked_server.users {
|
||||||
buf_out.extend_from_slice(user.as_bytes());
|
buf_out.extend_from_slice(user.as_bytes());
|
||||||
}
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("buf users list {:?}", buf_out);
|
||||||
stream.write(&buf_out);
|
stream.write(&buf_out);
|
||||||
}
|
}
|
||||||
codes::client::JOIN_ROOM => {
|
codes::client::JOIN_ROOM => {
|
||||||
@ -92,71 +89,78 @@ impl Server {
|
|||||||
println!("Unspecified client Op");
|
println!("Unspecified client Op");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Err(_) => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_nick(&mut self, nickname: String, stream: &mut TcpStream) {
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_nick(server: &Arc<Mutex<Server>>, nickname: String, stream: &mut TcpStream) {
|
||||||
// Check for nickname collision
|
// Check for nickname collision
|
||||||
if self.users.contains(&nickname) {
|
let mut unlocked_server = server.lock().unwrap();
|
||||||
|
if unlocked_server.users.contains(&nickname) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("nickname collision, {}", nickname);
|
println!("nickname collision, {}", nickname);
|
||||||
stream.write_all(&[codes::ERROR, codes::error::NICKNAME_COLLISION]);
|
stream.write_all(&[codes::ERROR, codes::error::NICKNAME_COLLISION]);
|
||||||
} else {
|
} else {
|
||||||
// Add the user to the user list
|
// Add the user to the user list
|
||||||
self.users.insert(nickname.clone());
|
unlocked_server.users.insert(nickname.clone());
|
||||||
|
|
||||||
// Send response ok
|
// Send response ok
|
||||||
stream.write_all(&[codes::RESPONSE_OK]);
|
stream.write_all(&[codes::RESPONSE_OK]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 server = Server::new();
|
let server: Arc<Mutex<Server>> = Arc::new(Mutex::new(Server::new()));
|
||||||
let server_mutx = Arc::new(Mutex::new(server));
|
let server_outer: Arc<Mutex<Server>> = Arc::clone(&server);
|
||||||
let io_thread = Arc::clone(&server_mutx);
|
|
||||||
|
|
||||||
println!("Server listening on {}", SERVER_ADDRESS);
|
println!("Server listening on {}", SERVER_ADDRESS);
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
for tcpstream in listener.incoming() {
|
||||||
|
match tcpstream {
|
||||||
|
Ok(mut stream) => {
|
||||||
|
let mut buf_in: [u8; 1024] = [0; 1024];
|
||||||
|
let server_innter = Arc::clone(&server_outer);
|
||||||
|
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
println!("0: Quit Server");
|
match stream.read(&mut buf_in) {
|
||||||
println!("1: list connected users");
|
Ok(size) => {
|
||||||
println!("2: list rooms");
|
|
||||||
let inp: String = input!(":");
|
let cmd_bytes: &[u8] = &buf_in[0..1];
|
||||||
let local_server = io_thread.lock().unwrap();
|
let param_bytes: &[u8] = &buf_in[1..size];
|
||||||
match inp.parse::<u8>() {
|
|
||||||
Ok(num) => match num {
|
handle_client(&server_innter, &mut stream, cmd_bytes, param_bytes);
|
||||||
0 => break,
|
}
|
||||||
1 => println!("Users: {:?}", local_server.users),
|
|
||||||
2 => println!("Rooms: {:?}", local_server.rooms),
|
|
||||||
_ => println!("Invalid Input"),
|
|
||||||
},
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("Invalid input");
|
println!("Error parsing client");
|
||||||
|
stream.write(&[codes::END]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
|
||||||
match stream {
|
|
||||||
Ok(mut stream) => {
|
|
||||||
let mut cmd_buf: [i32; 2] = [0; 2];
|
|
||||||
let mut local_server = server_mutx.lock().unwrap();
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
println!("match stream");
|
|
||||||
if local_server.users.len() < MAX_USERS {
|
|
||||||
local_server.handle_client(stream);
|
|
||||||
} else {
|
|
||||||
let _ = stream.write_all(&[codes::ERROR, codes::error::SERVER_FULL]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error accepting connections!");
|
eprintln!("Error accepting connections!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop {
|
||||||
|
println!("0: Quit Server");
|
||||||
|
println!("1: list connected users");
|
||||||
|
println!("2: list rooms");
|
||||||
|
let inp: String = input!(":");
|
||||||
|
match inp.parse::<u8>() {
|
||||||
|
Ok(num) => match num {
|
||||||
|
0 => break,
|
||||||
|
1 => println!("Users: {:?}", server.lock().unwrap().users),
|
||||||
|
2 => println!("Rooms: {:?}", server.lock().unwrap().rooms),
|
||||||
|
_ => println!("Invalid Input"),
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
println!("Invalid input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user