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]
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::{Read, Write};
use std::string::FromUtf8Error;
pub mod status;
/// Current supported protocol version.
pub const PROTOCOL_VERSION: usize = 498;
/// Possible errors while decoding packet.
pub enum DecodePacketError {
UnknownPacketType { type_id: u8 },
IOError { io_error: io::Error },
/// Possible errors while encoding packet.
pub enum EncodeError {
StringTooLong,
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 {
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 {
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 std::io;
use serde::{Deserialize, Serialize};
use std::io::{Read, Write};
use uuid::Uuid;
pub enum StatusServerBoundPacket {
StatusRequest,
@ -9,7 +10,7 @@ pub enum StatusServerBoundPacket {
}
pub enum StatusClientBoundPacket {
StatusResponse,
StatusResponse(StatusResponse),
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 {
0x0 => Ok(StatusServerBoundPacket::StatusRequest),
0x1 => {
@ -29,7 +30,7 @@ impl StatusServerBoundPacket {
Ok(StatusServerBoundPacket::PingRequest(ping_request))
}
_ => Err(DecodePacketError::UnknownPacketType { type_id }),
_ => Err(DecodeError::UnknownPacketType { type_id }),
}
}
}
@ -37,7 +38,7 @@ impl StatusServerBoundPacket {
impl StatusClientBoundPacket {
pub fn get_type_id(&self) -> u8 {
match self {
StatusClientBoundPacket::StatusResponse => 0x0,
StatusClientBoundPacket::StatusResponse(_) => 0x0,
StatusClientBoundPacket::PingResponse(_) => 0x1,
}
}
@ -58,13 +59,13 @@ impl PingRequest {
impl Packet for PingRequest {
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)?;
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>()?;
Ok(PingRequest { time })
@ -86,15 +87,71 @@ impl PingResponse {
impl Packet for PingResponse {
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)?;
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>()?;
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)
}
}