//! Information about a connected client use std::fmt; use std::io::{BufRead, BufReader, BufWriter, ErrorKind, Write}; use std::net::{Shutdown, SocketAddr}; use log::error; use mio::net::TcpStream; use mio::Token; use crate::result::RudeResult; use crate::state::*; use crate::try_log; /// `Client` struct for storing information about a connected client, also /// a few helper functions for communicating with the client. #[derive(Debug)] pub struct Client { /// TCP socket pub socket: TcpStream, /// Identifier token pub token: Token, /// IP information pub addr: SocketAddr, /// Client's play state pub state: State, } impl fmt::Display for Client { /// Only need the ip and port to be printed. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", self.addr.ip(), self.addr.port()) } } impl Into for Client { /// Convert the ip and port into a string. fn into(self) -> String { format!("{}:{}", self.addr.ip(), self.addr.port()) } } impl Client { /// Read a message from the client pub fn read(&self) -> RudeResult { let reader = BufReader::new(&self.socket); let mut buf = String::new(); for line in reader.lines() { match line { Ok(line) => buf += &line, Err(e) => match e.kind() { ErrorKind::WouldBlock => break, _ => return Err(e.into()), }, } } Ok(buf) } /// Send a string to the client. pub fn send_without_prompt>(&mut self, message: T) { let message = message.into(); let mut writer = BufWriter::new(&self.socket); if let Err(e) = writer.write_all(message.as_bytes()) { error!("Unable to send message to client ({:?}): {}", self, e); } } /// Send a string to the client, followed by a prompt. pub fn send_with_prompt>(&mut self, message: T) { let message = message.into() + self.prompt(); let mut writer = BufWriter::new(&self.socket); if let Err(e) = writer.write_all(message.as_bytes()) { error!("Unable to send message to client ({:?}): {}", self, e); } } fn prompt(&self) -> &str { "\n> " } pub fn close(&self) -> RudeResult<()> { Ok(try_log!( self.socket.shutdown(Shutdown::Both), "Unable to close socket" )) } }