Add status response

This commit is contained in:
Vladislav Golub 2019-11-10 23:42:00 +03:00
parent 824061e9a9
commit 6fcf5fe0ed
3 changed files with 163 additions and 18 deletions

View File

@ -15,3 +15,7 @@ name = "mcpl"
[dependencies] [dependencies]
byteorder = "1" byteorder = "1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "0.7", features = ["v4", "serde"] }
mc-varint = { git = "https://github.com/luojia65/mc-varint" }

View File

@ -1,27 +1,111 @@
use mc_varint::{VarIntRead, VarIntWrite};
use std::io; use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::string::FromUtf8Error;
pub mod status; pub mod status;
/// Current supported protocol version. /// Current supported protocol version.
pub const PROTOCOL_VERSION: usize = 498; pub const PROTOCOL_VERSION: usize = 498;
/// Possible errors while decoding packet. /// Possible errors while encoding packet.
pub enum DecodePacketError { pub enum EncodeError {
UnknownPacketType { type_id: u8 }, StringTooLong,
IOError { io_error: io::Error }, IOError {
io_error: io::Error,
},
JsonError {
json_error: serde_json::error::Error,
},
} }
impl From<io::Error> for DecodePacketError { impl From<io::Error> for EncodeError {
fn from(io_error: io::Error) -> Self { fn from(io_error: io::Error) -> Self {
DecodePacketError::IOError { io_error } EncodeError::IOError { io_error }
}
}
impl From<serde_json::error::Error> for EncodeError {
fn from(json_error: serde_json::error::Error) -> Self {
EncodeError::JsonError { json_error }
}
}
/// Possible errors while decoding packet.
pub enum DecodeError {
UnknownPacketType {
type_id: u8,
},
StringTooLong,
IOError {
io_error: io::Error,
},
JsonError {
json_error: serde_json::error::Error,
},
Utf8Error {
utf8_error: FromUtf8Error,
},
}
impl From<io::Error> for DecodeError {
fn from(io_error: io::Error) -> Self {
DecodeError::IOError { io_error }
}
}
impl From<serde_json::error::Error> for DecodeError {
fn from(json_error: serde_json::error::Error) -> Self {
DecodeError::JsonError { json_error }
}
}
impl From<FromUtf8Error> for DecodeError {
fn from(utf8_error: FromUtf8Error) -> Self {
DecodeError::Utf8Error { utf8_error }
} }
} }
trait Packet { trait Packet {
type Output; type Output;
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error>; fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError>;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodePacketError>; fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>;
}
trait PacketRead {
fn read_string(&mut self) -> Result<String, DecodeError>;
}
trait PacketWrite {
fn write_string(&mut self, value: &str) -> Result<(), EncodeError>;
}
impl<R: Read> PacketRead for R {
fn read_string(&mut self) -> Result<String, DecodeError> {
let length = self.read_var_u32()?;
if length > 32_767 {
return Err(DecodeError::StringTooLong);
}
let mut buf = vec![0; length as usize];
self.read_exact(&mut buf)?;
Ok(String::from_utf8(buf)?)
}
}
impl<W: Write> PacketWrite for W {
fn write_string(&mut self, value: &str) -> Result<(), EncodeError> {
if value.len() > 32_767 {
return Err(EncodeError::StringTooLong);
}
self.write_var_u32(value.len() as u32)?;
self.write_all(value.as_bytes())?;
Ok(())
}
} }

View File

@ -1,7 +1,8 @@
use crate::{DecodePacketError, Packet}; use crate::{DecodeError, EncodeError, Packet, PacketWrite};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::io; use serde::{Deserialize, Serialize};
use std::io::{Read, Write}; use std::io::{Read, Write};
use uuid::Uuid;
pub enum StatusServerBoundPacket { pub enum StatusServerBoundPacket {
StatusRequest, StatusRequest,
@ -9,7 +10,7 @@ pub enum StatusServerBoundPacket {
} }
pub enum StatusClientBoundPacket { pub enum StatusClientBoundPacket {
StatusResponse, StatusResponse(StatusResponse),
PingResponse(PingResponse), PingResponse(PingResponse),
} }
@ -21,7 +22,7 @@ impl StatusServerBoundPacket {
} }
} }
pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodePacketError> { pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodeError> {
match type_id { match type_id {
0x0 => Ok(StatusServerBoundPacket::StatusRequest), 0x0 => Ok(StatusServerBoundPacket::StatusRequest),
0x1 => { 0x1 => {
@ -29,7 +30,7 @@ impl StatusServerBoundPacket {
Ok(StatusServerBoundPacket::PingRequest(ping_request)) Ok(StatusServerBoundPacket::PingRequest(ping_request))
} }
_ => Err(DecodePacketError::UnknownPacketType { type_id }), _ => Err(DecodeError::UnknownPacketType { type_id }),
} }
} }
} }
@ -37,7 +38,7 @@ impl StatusServerBoundPacket {
impl StatusClientBoundPacket { impl StatusClientBoundPacket {
pub fn get_type_id(&self) -> u8 { pub fn get_type_id(&self) -> u8 {
match self { match self {
StatusClientBoundPacket::StatusResponse => 0x0, StatusClientBoundPacket::StatusResponse(_) => 0x0,
StatusClientBoundPacket::PingResponse(_) => 0x1, StatusClientBoundPacket::PingResponse(_) => 0x1,
} }
} }
@ -58,13 +59,13 @@ impl PingRequest {
impl Packet for PingRequest { impl Packet for PingRequest {
type Output = Self; type Output = Self;
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> { fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u64::<BigEndian>(self.time)?; writer.write_u64::<BigEndian>(self.time)?;
Ok(()) Ok(())
} }
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodePacketError> { fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let time = reader.read_u64::<BigEndian>()?; let time = reader.read_u64::<BigEndian>()?;
Ok(PingRequest { time }) Ok(PingRequest { time })
@ -86,15 +87,71 @@ impl PingResponse {
impl Packet for PingResponse { impl Packet for PingResponse {
type Output = Self; type Output = Self;
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> { fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u64::<BigEndian>(self.time)?; writer.write_u64::<BigEndian>(self.time)?;
Ok(()) Ok(())
} }
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodePacketError> { fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let time = reader.read_u64::<BigEndian>()?; let time = reader.read_u64::<BigEndian>()?;
Ok(PingResponse { time }) Ok(PingResponse { time })
} }
} }
#[derive(Serialize, Deserialize)]
pub struct ServerStatus {
pub version: ServerVersion,
pub description: String,
pub players: OnlinePlayers,
}
#[derive(Serialize, Deserialize)]
pub struct ServerVersion {
pub name: String,
pub protocol: u32,
}
#[derive(Serialize, Deserialize)]
pub struct OnlinePlayers {
pub online: u32,
pub max: u32,
pub sample: Vec<OnlinePlayer>,
}
#[derive(Serialize, Deserialize)]
pub struct OnlinePlayer {
pub id: Uuid,
pub name: String,
}
pub struct StatusResponse {
pub server_status: ServerStatus,
}
impl StatusResponse {
pub fn new(server_status: ServerStatus) -> StatusClientBoundPacket {
let status_response = StatusResponse { server_status };
StatusClientBoundPacket::StatusResponse(status_response)
}
}
impl Packet for StatusResponse {
type Output = Self;
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
let json = serde_json::to_string(&self.server_status)?;
writer.write_string(&json)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let server_status = serde_json::from_reader(reader)?;
let status_response = StatusResponse { server_status };
Ok(status_response)
}
}