Add status response
This commit is contained in:
parent
824061e9a9
commit
6fcf5fe0ed
@ -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" }
|
||||
|
100
src/lib.rs
100
src/lib.rs
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user