You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
2.2 KiB
95 lines
2.2 KiB
//! 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<String> 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<String> {
|
|
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<T: Into<String>>(&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<T: Into<String>>(&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"
|
|
))
|
|
}
|
|
}
|