diff options
Diffstat (limited to 'src/server_dev/auto/___server.rs')
| -rw-r--r-- | src/server_dev/auto/___server.rs | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/src/server_dev/auto/___server.rs b/src/server_dev/auto/___server.rs new file mode 100644 index 0000000..2f95952 --- /dev/null +++ b/src/server_dev/auto/___server.rs @@ -0,0 +1,266 @@ +use std::error::Error; +use crate::server::auto::cmd::property::{ + create_property_update_command, + create_property_request_command +}; +use crate::server::cmd::text::{create_text_command_with_action, create_text_command}; +use std::str::from_utf8; +use crate::server::cmd::buddy_list::create_buddy_list_notify_command; +use crate::server::auto::cmd::room::create_room_id_redirect_command; +use crate::server::auto::cmd::session::parse_session_initialization_command; +use crate::server::parser::get_commands_from_buffer; +use crate::server::cmd::property::parse_property_set_command; +use crate::config::get_config; +use mio::{Poll, Events, Token, Interest, Registry}; +use mio::net::{TcpListener, TcpStream}; +use std::collections::HashMap; +use mio::event::Event; +use std::io::{Read, ErrorKind, Write}; +use bytes::BytesMut; + +const SERVER: Token = Token(0); + +pub struct AutoServer { + pub clients: HashMap<Token, String>, + pub connections: HashMap<Token, TcpStream>, + pub room_ids: Vec<String>, +} +impl AutoServer { + pub fn listen(&mut self, addr: &str) -> Result<(), Box<dyn Error>> { + let mut server = TcpListener::bind(addr.parse().unwrap())?; + let mut poll = Poll::new()?; + let mut events = Events::with_capacity(1024); + let mut unique_token = Token(SERVER.0 + 1); + + poll.registry().register( + &mut server, + SERVER, + Interest::READABLE + )?; + + debug!("AutoServer now listening on {}", server.local_addr().unwrap()); + + loop { + poll.poll(&mut events, None)?; + + for event in &events { + match event.token() { + SERVER => loop { + let (mut stream, address) = match server.accept() { + Ok((stream, address)) => (stream, address), + Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => break, + Err(e) => return Err(Box::new(e)), + }; + + let token = AutoServer::next(&mut unique_token); + poll.registry().register( + &mut stream, + token, + Interest::READABLE, //.add(Interest::WRITABLE), + )?; + + self.connections.insert(token, stream); + + debug!("registered peer with address '{}' as '{}'", address, token.0); + }, + token => { + // let done = if let Some(stream) = self.connections.get_mut(&token) { + // self.process( + // poll.registry(), + // event, + // token, + // )? + // } else { + // false + // }; + + let done = self.process( + poll.registry(), + event, + token, + )?; + if done { self.connections.remove(&token); } + } + } + } + } + } + + fn next(current: &mut Token) -> Token { + let next = current.0; + current.0 += 1; + Token(next) + } + + fn broadcast(mut self, cmd: &[u8]) -> () { + self.connections.iter_mut() + .for_each(|c| + c.1.write_all(cmd).unwrap() + ); + } + + fn process( + &mut self, + _registry: &Registry, + event: &Event, + token: Token, + ) -> Result<bool, Box<dyn Error>> { + if event.is_readable() { + let mut connection_closed = false; + let mut received_data = vec![0; 4096]; + let mut bytes_read = 0; + + let stream = self.connections.get_mut(&token).unwrap(); + + loop { + match stream.read(&mut received_data[bytes_read..]) { + Ok(0) => { + connection_closed = true; + break; + } + Ok(n) => { + bytes_read += n; + if bytes_read == received_data.len() { + received_data.resize(received_data.len() + 1024, 0); + } + } + Err(ref err) if err.kind() == ErrorKind::WouldBlock => break, + Err(ref err) if err.kind() == ErrorKind::Interrupted => continue, + Err(err) => return Err(Box::new(err)), + } + } + + if bytes_read != 0 { + self.handle( + &mut received_data[..bytes_read], + token, + ); + } + if connection_closed { + println!("de-registered peer with token '{}'", token.0); + return Ok(true); + } + } + + Ok(false) + } + + fn handle( + &mut self, + data: &[u8], + // stream: &mut TcpStream, + token: Token, + ) -> () { + // trace!("i am client: {:?}", self.clients.get(&token)); + // debug!("{:?}", self.connections); + for cmd in get_commands_from_buffer(BytesMut::from(data)) { + debug!("received: {:?}", cmd); + match cmd.get(2).unwrap() { + 10 => { // PROPREQ + debug!("received property request command from client 'null'"); + self.connections.get_mut(&token).unwrap() + .write_all(&create_property_update_command()).unwrap(); + debug!("sent property update command to client 'null'"); + } + 6 => { // SESSINIT + let local_username = + parse_session_initialization_command(cmd).username; + self.clients.insert(token, local_username.clone()); + debug!( + "received session initialization command from client '{}'", + local_username, + ); + self.connections.get_mut(&token).unwrap() + .write_all(&create_property_request_command()).unwrap(); + debug!("sent session initialization command to client '{}'", local_username); + } + 15 => { // PROPSET + let avatar = parse_property_set_command(cmd); + debug!( + "received property set command from client '{}': {}", + self.clients.get(&token).unwrap(), + avatar, + ); + self.connections.get_mut(&token).unwrap() + .write_all(&create_text_command_with_action( + "WORLDSMASTER", &get_config().unwrap().worldsmaster_greeting, + )).unwrap(); + debug!( + "sent session initialization command to client '{}'", + self.clients.get(&token).unwrap(), + ); + } + 29 => { // BUDDYLISTUPDATE + let received_buddy = from_utf8( + cmd.get(4..cmd.get(0).unwrap().to_owned() as usize - 1).unwrap() + ).unwrap(); + debug!( + "received buddy list update command from client '{}': {}", + self.clients.get(&token).unwrap(), + received_buddy, + ); + self.connections.get_mut(&token).unwrap() + .write_all(&create_buddy_list_notify_command(received_buddy)).unwrap(); + debug!( + "sent buddy list notify command to client '{}'", + self.clients.get(&token).unwrap(), + ); + } + 20 => { // ROOMIDRQ + let room_name = from_utf8( + cmd.get(4..cmd.get(0).unwrap().to_owned() as usize).unwrap() + ).unwrap(); + debug!( + "received room id request command from client '{}': {}", + self.clients.get(&token).unwrap(), + room_name, + ); + let room_id; + if !self.room_ids.contains(&room_name.to_string()) { + self.room_ids.push(room_name.to_string()); + room_id = self.room_ids.iter() + .position(|i| i == &room_name.to_string()) + .unwrap(); + trace!("inserted room '{}' as '{}'", room_name, room_id); + } else { + let position = self.room_ids.iter() + .position(|i| i == &room_name.to_string()) + .unwrap(); + trace!("found room '{}' as '{}'", room_name, position); + room_id = position; + } + trace!("room name: {}, room id: {}", room_name, room_id); + trace!("{:?}", self.room_ids); + self.connections.get_mut(&token).unwrap() + .write_all(&create_room_id_redirect_command( + room_name, room_id, + )).unwrap(); + } + 14 => { // TEXT + let text = from_utf8( + cmd.get(6..cmd.get(0).unwrap().to_owned() as usize).unwrap() + ).unwrap(); + let username = self.clients.get(&token).unwrap().clone(); + debug!( + "received text command from client '{}': {}", + username, text, + ); + self.connections.iter_mut().for_each(|t| + t.1.write_all(&create_text_command( + &username, + text, + )).unwrap() + ); + debug!("broadcasted text command to clients"); + } + 7 => { // SESSEXIT + debug!( + "received session exit command from client '{}'", + self.clients.get(&token).unwrap(), + ); + } + _ => (), + } + } + } +} |