From 1897492cf4b62901ebc450fdff35e7e231d3c7e3 Mon Sep 17 00:00:00 2001 From: Thinkofdeath Date: Fri, 25 Sep 2015 14:00:49 +0100 Subject: [PATCH] Kinda functional server list --- protocol/src/protocol/mod.rs | 102 +++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/protocol/src/protocol/mod.rs b/protocol/src/protocol/mod.rs index 1aacef2..483f314 100644 --- a/protocol/src/protocol/mod.rs +++ b/protocol/src/protocol/mod.rs @@ -30,6 +30,9 @@ use std::convert; use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; use flate2::read::{ZlibDecoder, ZlibEncoder}; use flate2; +use time; + +pub const SUPPORTED_PROTOCOL: i32 = 73; /// Helper macro for defining packets #[macro_export] @@ -130,7 +133,7 @@ macro_rules! state_packets { pub mod packet; -pub trait Serializable { +pub trait Serializable: Sized { fn read_from(buf: &mut io::Read) -> Result; fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error>; } @@ -651,11 +654,14 @@ pub struct Conn { impl Conn { pub fn new(target: &str) -> Result{ // TODO SRV record support - let stream = match TcpStream::connect(target) { - Ok(val) => val, - Err(err) => return Result::Err(Error::IOError(err)) + let mut parts = target.split(":").collect::>(); + let address = if parts.len() == 1 { + parts.push("25565"); + format!("{}:25565", parts[0]) + } else { + format!("{}:{}", parts[0], parts[1]) }; - let parts = target.split(":").collect::>(); + let stream = try!(TcpStream::connect(&*address)); Result::Ok(Conn { stream: stream, host: parts[0].to_owned(), @@ -748,6 +754,91 @@ impl Conn { self.compression_read = Some(ZlibDecoder::new(io::Cursor::new(Vec::new()))); } } + + pub fn do_status(mut self) -> Result<(Status, time::Duration), Error>{ + use serde_json::Value; + use self::packet::status::serverbound::*; + use self::packet::handshake::serverbound::*; + use self::packet::Packet; + let host = self.host.clone(); + let port = self.port; + try!(self.write_packet(Handshake{ + protocol_version: VarInt(SUPPORTED_PROTOCOL), + host: host, + port: port, + next: VarInt(1), + })); + self.state = State::Status; + + try!(self.write_packet(StatusRequest{empty: ()})); + + let status = if let Packet::StatusResponse(res) = try!(self.read_packet()) { + res.status + } else { + return Err(Error::Err("Wrong packet".to_owned())); + }; + + let start = time::now(); + try!(self.write_packet(StatusPing{ping: 42})); + + if let Packet::StatusPong(_) = try!(self.read_packet()) { + } else { + return Err(Error::Err("Wrong packet".to_owned())); + }; + + let ping = time::now() - start; + + let val: Value = match serde_json::from_str(&status) { + Ok(val) => val, + Err(_) => return Err(Error::Err("Json parse error".to_owned())), + }; + + let invalid_status = || Error::Err("Invalid status".to_owned()); + + let version = try!(val.find("version").ok_or(invalid_status())); + let players = try!(val.find("players").ok_or(invalid_status())); + + Ok((Status { + version: StatusVersion { + name: try!(version.find("name").and_then(Value::as_string).ok_or(invalid_status())).to_owned(), + protocol: try!(version.find("protocol").and_then(Value::as_i64).ok_or(invalid_status())) as i32, + }, + players: StatusPlayers { + max: try!(players.find("max").and_then(Value::as_i64).ok_or(invalid_status())) as i32, + online: try!(players.find("online").and_then(Value::as_i64).ok_or(invalid_status())) as i32, + sample: Vec::new(), // TODO + }, + description: format::Component::from_value(try!(val.find("description").ok_or(invalid_status()))), + favicon: val.find("favicon").and_then(Value::as_string).map(|v| v.to_owned()), + }, ping)) + } +} + +#[derive(Debug)] +pub struct Status { + pub version: StatusVersion, + pub players: StatusPlayers, + pub description: format::Component, + pub favicon: Option, +} + +#[derive(Debug)] +pub struct StatusVersion { + pub name: String, + pub protocol: i32, +} + +#[derive(Debug)] +pub struct StatusPlayers { + pub max: i32, + pub online: i32, + pub sample: Vec, +} + +#[derive(Debug)] +pub struct StatusPlayer { + name: String, + id: String, } impl Read for Conn { @@ -805,6 +896,7 @@ pub trait PacketType { fn write(self, buf: &mut io::Write) -> Result<(), io::Error>; } +// REMOVE ME // #[test] pub fn test() { let mut c = Conn::new("localhost:25565").unwrap();