From 0b6185a9fcb23486ff3e697e0f93201a8f8d9c31 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 4 Jun 2021 10:14:27 +0200 Subject: [PATCH 1/8] Add missing derives. --- protocol/src/data/chat.rs | 1 + protocol/src/lib.rs | 2 ++ protocol/src/version/v1_14_4/game.rs | 6 ++++-- protocol/src/version/v1_14_4/handshake.rs | 1 + protocol/src/version/v1_14_4/login.rs | 2 ++ protocol/src/version/v1_14_4/status.rs | 2 ++ 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/protocol/src/data/chat.rs b/protocol/src/data/chat.rs index 6f21fa6..8c55f29 100644 --- a/protocol/src/data/chat.rs +++ b/protocol/src/data/chat.rs @@ -339,6 +339,7 @@ impl Message { impl_json_encoder_decoder!(Message); +#[derive(Debug)] pub struct MessageBuilder { current: Message, root: Option, diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index 2f42969..3040683 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -1,6 +1,8 @@ //! This crate implements Minecraft protocol. //! //! Information about protocol can be found at https://wiki.vg/Protocol. +#![warn(missing_debug_implementations)] + pub mod data; pub mod decoder; pub mod encoder; diff --git a/protocol/src/version/v1_14_4/game.rs b/protocol/src/version/v1_14_4/game.rs index 4400831..f740002 100644 --- a/protocol/src/version/v1_14_4/game.rs +++ b/protocol/src/version/v1_14_4/game.rs @@ -9,12 +9,14 @@ use nbt::CompoundTag; use std::io::Read; use uuid::Uuid; +#[derive(Debug)] pub enum GameServerBoundPacket { ServerBoundChatMessage(ServerBoundChatMessage), ServerBoundKeepAlive(ServerBoundKeepAlive), ServerBoundAbilities(ServerBoundAbilities), } +#[derive(Debug)] pub enum GameClientBoundPacket { ClientBoundChatMessage(ClientBoundChatMessage), JoinGame(JoinGame), @@ -177,7 +179,7 @@ impl JoinGame { } } -#[derive(Encoder, Decoder)] +#[derive(Encoder, Decoder, Debug)] pub struct ServerBoundKeepAlive { pub id: u64, } @@ -190,7 +192,7 @@ impl ServerBoundKeepAlive { } } -#[derive(Encoder, Decoder)] +#[derive(Encoder, Decoder, Debug)] pub struct ClientBoundKeepAlive { pub id: u64, } diff --git a/protocol/src/version/v1_14_4/handshake.rs b/protocol/src/version/v1_14_4/handshake.rs index f678043..caceda3 100644 --- a/protocol/src/version/v1_14_4/handshake.rs +++ b/protocol/src/version/v1_14_4/handshake.rs @@ -3,6 +3,7 @@ use crate::error::DecodeError; use minecraft_protocol_derive::{Decoder, Encoder}; use std::io::Read; +#[derive(Debug)] pub enum HandshakeServerBoundPacket { Handshake(Handshake), } diff --git a/protocol/src/version/v1_14_4/login.rs b/protocol/src/version/v1_14_4/login.rs index 14248a3..3ee8ad8 100644 --- a/protocol/src/version/v1_14_4/login.rs +++ b/protocol/src/version/v1_14_4/login.rs @@ -6,12 +6,14 @@ use crate::decoder::Decoder; use crate::error::DecodeError; use minecraft_protocol_derive::{Decoder, Encoder}; +#[derive(Debug)] pub enum LoginServerBoundPacket { LoginStart(LoginStart), EncryptionResponse(EncryptionResponse), LoginPluginResponse(LoginPluginResponse), } +#[derive(Debug)] pub enum LoginClientBoundPacket { LoginDisconnect(LoginDisconnect), EncryptionRequest(EncryptionRequest), diff --git a/protocol/src/version/v1_14_4/status.rs b/protocol/src/version/v1_14_4/status.rs index 57c281a..588303e 100644 --- a/protocol/src/version/v1_14_4/status.rs +++ b/protocol/src/version/v1_14_4/status.rs @@ -4,11 +4,13 @@ use crate::error::DecodeError; use minecraft_protocol_derive::{Decoder, Encoder}; use std::io::Read; +#[derive(Debug)] pub enum StatusServerBoundPacket { StatusRequest, PingRequest(PingRequest), } +#[derive(Debug)] pub enum StatusClientBoundPacket { StatusResponse(StatusResponse), PingResponse(PingResponse), From 0506fc9ca0f452c4055a2f8b7aa2e17cb3ffa5e9 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 7 Dec 2021 19:54:19 +0100 Subject: [PATCH 2/8] Add missing `favicon` field. --- protocol/src/data/server_status.rs | 2 ++ protocol/src/version/v1_14_4/status.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/protocol/src/data/server_status.rs b/protocol/src/data/server_status.rs index e3fdeac..e17697d 100644 --- a/protocol/src/data/server_status.rs +++ b/protocol/src/data/server_status.rs @@ -8,6 +8,8 @@ pub struct ServerStatus { pub version: ServerVersion, pub players: OnlinePlayers, pub description: Message, + #[serde(skip_serializing_if = "Option::is_none")] + pub favicon: Option, } #[derive(Clone, Serialize, Deserialize, Debug)] diff --git a/protocol/src/version/v1_14_4/status.rs b/protocol/src/version/v1_14_4/status.rs index 588303e..173de4c 100644 --- a/protocol/src/version/v1_14_4/status.rs +++ b/protocol/src/version/v1_14_4/status.rs @@ -164,6 +164,7 @@ mod tests { version, description: Message::new(Payload::text("Description")), players, + favicon: None, }; let status_response = StatusResponse { server_status }; From 37c683786cbf4b13479e73a6c24f59506c25cf89 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 4 Jun 2021 10:25:47 +0200 Subject: [PATCH 3/8] Add `Packet` struct. --- protocol/src/lib.rs | 1 + protocol/src/packet.rs | 87 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 protocol/src/packet.rs diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index 3040683..cf57940 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -7,6 +7,7 @@ pub mod data; pub mod decoder; pub mod encoder; pub mod error; +pub mod packet; pub mod version; /// Protocol limits maximum string length. diff --git a/protocol/src/packet.rs b/protocol/src/packet.rs new file mode 100644 index 0000000..7115687 --- /dev/null +++ b/protocol/src/packet.rs @@ -0,0 +1,87 @@ +use std::io::{Cursor, Read, Write}; + +use crate::decoder::{Decoder, DecoderReadExt}; +use crate::encoder::{Encoder, EncoderWriteExt}; +use crate::error::{DecodeError, EncodeError}; + +#[derive(Debug)] +pub struct Packet { + pub id: i32, + pub data: Vec, +} + +impl Encoder for Packet { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + let mut id_buf = Vec::new(); + id_buf.write_var_i32(self.id)?; + + writer.write_var_i32((id_buf.len() + self.data.len()) as i32)?; + writer.write(&id_buf)?; + writer.write(&self.data)?; + + Ok(()) + } +} + +impl Decoder for Packet { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + let length = reader.read_var_i32()?; + + let mut buf = vec![0; length as usize]; + reader.read_exact(&mut buf)?; + + let mut cursor = Cursor::new(&mut buf); + let id = cursor.read_var_i32()?; + let position = cursor.position() as usize; + let data = buf.split_off(position); + + Ok(Self { id, data }) + } +} + +#[cfg(test)] +mod tests { + use std::convert::TryInto; + + use super::*; + + use crate::version::v1_14_4::status::*; + + const PING_REQUEST_BYTES: &'static [u8] = + include_bytes!("../test/packet/status/ping_request.dat"); + + fn ping_request_packet_bytes() -> Vec { + let len = (1 + PING_REQUEST_BYTES.len()).try_into().unwrap(); + let mut vec = vec![len, 1]; + vec.extend(PING_REQUEST_BYTES); + vec + } + + #[test] + fn test_packet_encode() { + let ping_request = PingRequest { + time: 1577735845610, + }; + + let mut data = Vec::new(); + ping_request.encode(&mut data).unwrap(); + + let packet = Packet { id: 1, data }; + + let mut vec = Vec::new(); + packet.encode(&mut vec).unwrap(); + + assert_eq!(vec, ping_request_packet_bytes()); + } + + #[test] + fn test_packet_decode() { + let mut cursor = Cursor::new(ping_request_packet_bytes()); + let packet = Packet::decode(&mut cursor).unwrap(); + + assert_eq!(packet.id, 1); + assert_eq!(packet.data, PING_REQUEST_BYTES); + } +} From b0034dd3b8f5c91af9eb077c7de854d149ccbf59 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 17 Dec 2021 12:17:37 +0100 Subject: [PATCH 4/8] Support compression for packets. --- protocol/Cargo.toml | 1 + protocol/src/error.rs | 1 + protocol/src/packet.rs | 154 +++++++++++++++++++++++++++++++++++------ 3 files changed, 134 insertions(+), 22 deletions(-) diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index ee36759..c40266e 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -17,3 +17,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "0.7", features = ["v4", "serde"] } named-binary-tag = "0.2" +flate2 = "1.0.22" diff --git a/protocol/src/error.rs b/protocol/src/error.rs index 55a790d..9ec0538 100644 --- a/protocol/src/error.rs +++ b/protocol/src/error.rs @@ -73,6 +73,7 @@ pub enum DecodeError { VarIntTooLong { max_bytes: usize, }, + DecompressionError, } impl From for DecodeError { diff --git a/protocol/src/packet.rs b/protocol/src/packet.rs index 7115687..1150c17 100644 --- a/protocol/src/packet.rs +++ b/protocol/src/packet.rs @@ -1,43 +1,124 @@ -use std::io::{Cursor, Read, Write}; +use std::io::{Read, Write}; + +use flate2::read::ZlibDecoder; +use flate2::write::ZlibEncoder; +use flate2::Compression; use crate::decoder::{Decoder, DecoderReadExt}; use crate::encoder::{Encoder, EncoderWriteExt}; use crate::error::{DecodeError, EncodeError}; #[derive(Debug)] -pub struct Packet { +pub struct RawPacket { pub id: i32, pub data: Vec, } -impl Encoder for Packet { +impl Encoder for RawPacket { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + writer.write_var_i32(self.id)?; + writer.write_all(&self.data)?; + + Ok(()) + } +} + +impl Decoder for RawPacket { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + let id = reader.read_var_i32()?; + + let mut data = Vec::new(); + reader.read_to_end(&mut data)?; + + Ok(Self { id, data }) + } +} + +#[derive(Debug)] +pub struct CompressedRawPacket { + packet: RawPacket, + threshold: i32, +} + +impl Encoder for CompressedRawPacket { fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - let mut id_buf = Vec::new(); - id_buf.write_var_i32(self.id)?; + let mut packet_buf = Vec::new(); + self.packet.encode(&mut packet_buf)?; + + let data_len = packet_buf.len() as i32; + let mut packet = Vec::new(); + if self.threshold >= 0 && data_len > self.threshold { + packet.write_var_i32(data_len)?; + let mut encoder = ZlibEncoder::new(&mut packet, Compression::default()); + encoder.write_all(&packet_buf)?; + encoder.finish()?; + } else { + packet.write_var_i32(0)?; + packet.write_all(&packet_buf)?; + }; - writer.write_var_i32((id_buf.len() + self.data.len()) as i32)?; - writer.write(&id_buf)?; - writer.write(&self.data)?; + writer.write_var_i32(packet.len() as i32)?; + writer.write_all(&packet)?; Ok(()) } } -impl Decoder for Packet { +impl Decoder for CompressedRawPacket { type Output = Self; fn decode(reader: &mut R) -> Result { - let length = reader.read_var_i32()?; + let packet_len = reader.read_var_i32()? as u64; + let mut reader = reader.take(packet_len); - let mut buf = vec![0; length as usize]; - reader.read_exact(&mut buf)?; + let data_len = reader.read_var_i32()? as usize; + let packet = if data_len == 0 { + RawPacket::decode(&mut reader)? + } else { + let mut decompressed = Vec::with_capacity(data_len); + ZlibDecoder::new(reader).read_to_end(&mut decompressed)?; - let mut cursor = Cursor::new(&mut buf); - let id = cursor.read_var_i32()?; - let position = cursor.position() as usize; - let data = buf.split_off(position); + if decompressed.len() != data_len { + return Err(DecodeError::DecompressionError); + } - Ok(Self { id, data }) + RawPacket::decode(&mut decompressed.as_slice())? + }; + + Ok(CompressedRawPacket { + packet, + threshold: Default::default(), + }) + } +} + +#[derive(Debug)] +pub struct UncompressedRawPacket { + packet: RawPacket, +} + +impl Encoder for UncompressedRawPacket { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + let mut packet_buf = Vec::new(); + self.packet.encode(&mut packet_buf)?; + + writer.write_var_i32(packet_buf.len() as i32)?; + writer.write_all(&packet_buf)?; + + Ok(()) + } +} + +impl Decoder for UncompressedRawPacket { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + let len = reader.read_var_i32()? as u64; + let packet = RawPacket::decode(&mut reader.take(len))?; + + Ok(Self { packet }) } } @@ -60,7 +141,7 @@ mod tests { } #[test] - fn test_packet_encode() { + fn test_uncompressed_packet_encode() { let ping_request = PingRequest { time: 1577735845610, }; @@ -68,7 +149,9 @@ mod tests { let mut data = Vec::new(); ping_request.encode(&mut data).unwrap(); - let packet = Packet { id: 1, data }; + let packet = UncompressedRawPacket { + packet: RawPacket { id: 1, data }, + }; let mut vec = Vec::new(); packet.encode(&mut vec).unwrap(); @@ -77,9 +160,36 @@ mod tests { } #[test] - fn test_packet_decode() { - let mut cursor = Cursor::new(ping_request_packet_bytes()); - let packet = Packet::decode(&mut cursor).unwrap(); + fn test_uncompressed_packet_decode() { + let vec = ping_request_packet_bytes(); + let packet = UncompressedRawPacket::decode(&mut vec.as_slice()) + .unwrap() + .packet; + + assert_eq!(packet.id, 1); + assert_eq!(packet.data, PING_REQUEST_BYTES); + } + + #[test] + fn test_compressed_packet_encode_decode() { + let ping_request = PingRequest { + time: 1577735845610, + }; + + let mut data = Vec::new(); + ping_request.encode(&mut data).unwrap(); + + let packet = CompressedRawPacket { + packet: RawPacket { id: 1, data }, + threshold: 0, + }; + + let mut vec = Vec::new(); + packet.encode(&mut vec).unwrap(); + + let packet = CompressedRawPacket::decode(&mut vec.as_slice()) + .unwrap() + .packet; assert_eq!(packet.id, 1); assert_eq!(packet.data, PING_REQUEST_BYTES); From fab8ee7cabee7d1b1dc5d8fbc6884d4a0c941a75 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 17 Dec 2021 13:00:11 +0100 Subject: [PATCH 5/8] Decode `CompressedRawPacket` to `UncompressedRawPacket`. --- protocol/src/packet.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/protocol/src/packet.rs b/protocol/src/packet.rs index 1150c17..d35f4f2 100644 --- a/protocol/src/packet.rs +++ b/protocol/src/packet.rs @@ -8,7 +8,7 @@ use crate::decoder::{Decoder, DecoderReadExt}; use crate::encoder::{Encoder, EncoderWriteExt}; use crate::error::{DecodeError, EncodeError}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RawPacket { pub id: i32, pub data: Vec, @@ -36,7 +36,7 @@ impl Decoder for RawPacket { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CompressedRawPacket { packet: RawPacket, threshold: i32, @@ -67,7 +67,7 @@ impl Encoder for CompressedRawPacket { } impl Decoder for CompressedRawPacket { - type Output = Self; + type Output = UncompressedRawPacket; fn decode(reader: &mut R) -> Result { let packet_len = reader.read_var_i32()? as u64; @@ -87,18 +87,25 @@ impl Decoder for CompressedRawPacket { RawPacket::decode(&mut decompressed.as_slice())? }; - Ok(CompressedRawPacket { - packet, - threshold: Default::default(), - }) + Ok(UncompressedRawPacket { packet }) } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct UncompressedRawPacket { packet: RawPacket, } +impl UncompressedRawPacket { + /// Compress the packet if is is bigger than given threshold. A negative threshold disables compression. + pub fn compress(self, threshold: i32) -> CompressedRawPacket { + CompressedRawPacket { + packet: self.packet, + threshold, + } + } +} + impl Encoder for UncompressedRawPacket { fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { let mut packet_buf = Vec::new(); From 12ac52da8231d90d20e70b377c915d8cba995fe6 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 17 Dec 2021 15:10:25 +0100 Subject: [PATCH 6/8] Add `Incomplete` error variant for incomplete packets. --- protocol/src/error.rs | 13 +++++++++---- protocol/src/packet.rs | 24 ++++++++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/protocol/src/error.rs b/protocol/src/error.rs index 9ec0538..8167e1a 100644 --- a/protocol/src/error.rs +++ b/protocol/src/error.rs @@ -14,7 +14,7 @@ pub enum EncodeError { /// Max string length. max_length: u16, }, - IOError { + IoError { io_error: IoError, }, JsonError { @@ -24,7 +24,7 @@ pub enum EncodeError { impl From for EncodeError { fn from(io_error: IoError) -> Self { - EncodeError::IOError { io_error } + EncodeError::IoError { io_error } } } @@ -37,6 +37,11 @@ impl From for EncodeError { /// Possible errors while decoding packet. #[derive(Debug)] pub enum DecodeError { + /// Packet is incomplete. + Incomplete { + /// Minimum number of bytes needed to complete the packet. + bytes_needed: usize, + }, /// Packet was not recognized. Invalid data or wrong protocol version. UnknownPacketType { type_id: u8, @@ -48,7 +53,7 @@ pub enum DecodeError { /// Max string length. max_length: u16, }, - IOError { + IoError { io_error: IoError, }, JsonError { @@ -78,7 +83,7 @@ pub enum DecodeError { impl From for DecodeError { fn from(io_error: IoError) -> Self { - DecodeError::IOError { io_error } + DecodeError::IoError { io_error } } } diff --git a/protocol/src/packet.rs b/protocol/src/packet.rs index d35f4f2..81e9ae1 100644 --- a/protocol/src/packet.rs +++ b/protocol/src/packet.rs @@ -8,6 +8,19 @@ use crate::decoder::{Decoder, DecoderReadExt}; use crate::encoder::{Encoder, EncoderWriteExt}; use crate::error::{DecodeError, EncodeError}; +fn read_n(reader: R, len: usize) -> Result, DecodeError> { + let mut buf = Vec::with_capacity(len); + let bytes_read = reader.take(len as u64).read_to_end(&mut buf)?; + + if bytes_read != len { + return Err(DecodeError::Incomplete { + bytes_needed: len - bytes_read, + }); + } + + Ok(buf) +} + #[derive(Debug, Clone)] pub struct RawPacket { pub id: i32, @@ -70,8 +83,10 @@ impl Decoder for CompressedRawPacket { type Output = UncompressedRawPacket; fn decode(reader: &mut R) -> Result { - let packet_len = reader.read_var_i32()? as u64; - let mut reader = reader.take(packet_len); + let packet_len = reader.read_var_i32()? as usize; + let packet_buf = read_n(reader, packet_len)?; + + let mut reader = &mut packet_buf.as_slice(); let data_len = reader.read_var_i32()? as usize; let packet = if data_len == 0 { @@ -122,8 +137,9 @@ impl Decoder for UncompressedRawPacket { type Output = Self; fn decode(reader: &mut R) -> Result { - let len = reader.read_var_i32()? as u64; - let packet = RawPacket::decode(&mut reader.take(len))?; + let packet_len = reader.read_var_i32()? as usize; + let packet_buf = read_n(reader, packet_len)?; + let packet = RawPacket::decode(&mut packet_buf.as_slice())?; Ok(Self { packet }) } From 12f1086f307a63c1deaeb573454b818b7d20e467 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 17 Dec 2021 16:49:30 +0100 Subject: [PATCH 7/8] Add `Packet` with custom `encode`/`decode` methods. --- protocol/src/packet.rs | 164 +++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 97 deletions(-) diff --git a/protocol/src/packet.rs b/protocol/src/packet.rs index 81e9ae1..b85cba5 100644 --- a/protocol/src/packet.rs +++ b/protocol/src/packet.rs @@ -1,56 +1,83 @@ -use std::io::{Read, Write}; +use std::io::{self, Read, Write}; use flate2::read::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; +use minecraft_protocol_derive::{Decoder, Encoder}; use crate::decoder::{Decoder, DecoderReadExt}; use crate::encoder::{Encoder, EncoderWriteExt}; use crate::error::{DecodeError, EncodeError}; -fn read_n(reader: R, len: usize) -> Result, DecodeError> { - let mut buf = Vec::with_capacity(len); - let bytes_read = reader.take(len as u64).read_to_end(&mut buf)?; - - if bytes_read != len { - return Err(DecodeError::Incomplete { - bytes_needed: len - bytes_read, - }); - } - - Ok(buf) -} - #[derive(Debug, Clone)] -pub struct RawPacket { +pub struct Packet { pub id: i32, pub data: Vec, } -impl Encoder for RawPacket { - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i32(self.id)?; - writer.write_all(&self.data)?; +impl Packet { + pub fn encode( + &self, + writer: &mut W, + compression_threshold: Option, + ) -> Result<(), EncodeError> { + let mut buf = Vec::new(); + let packet = RawPacket { + id: self.id, + data: self.data.clone(), + }; + if let Some(threshold) = compression_threshold { + CompressedRawPacket { packet, threshold }.encode(&mut buf)?; + } else { + packet.encode(&mut buf)?; + } + + writer.write_var_i32(buf.len() as i32)?; + writer.write_all(&buf)?; Ok(()) } -} -impl Decoder for RawPacket { - type Output = Self; + pub fn decode(reader: &mut R, compressed: bool) -> Result { + let len = match reader.read_var_i32() { + Ok(len) => len as usize, + Err(DecodeError::IoError { io_error }) + if io_error.kind() == io::ErrorKind::UnexpectedEof => + { + return Err(DecodeError::Incomplete { bytes_needed: 1 }) + } + Err(err) => return Err(err.into()), + }; + + let mut buf = Vec::with_capacity(len); + let bytes_read = reader.take(len as u64).read_to_end(&mut buf)?; - fn decode(reader: &mut R) -> Result { - let id = reader.read_var_i32()?; + if bytes_read != len { + return Err(DecodeError::Incomplete { + bytes_needed: len - bytes_read, + }); + } - let mut data = Vec::new(); - reader.read_to_end(&mut data)?; + let RawPacket { id, data } = if compressed { + CompressedRawPacket::decode(&mut buf.as_slice())? + } else { + RawPacket::decode(&mut buf.as_slice())? + }; Ok(Self { id, data }) } } +#[derive(Debug, Clone, Encoder, Decoder)] +struct RawPacket { + #[data_type(with = "var_int")] + pub id: i32, + #[data_type(with = "rest")] + pub data: Vec, +} + #[derive(Debug, Clone)] -pub struct CompressedRawPacket { +struct CompressedRawPacket { packet: RawPacket, threshold: i32, } @@ -61,36 +88,27 @@ impl Encoder for CompressedRawPacket { self.packet.encode(&mut packet_buf)?; let data_len = packet_buf.len() as i32; - let mut packet = Vec::new(); if self.threshold >= 0 && data_len > self.threshold { - packet.write_var_i32(data_len)?; - let mut encoder = ZlibEncoder::new(&mut packet, Compression::default()); + writer.write_var_i32(data_len)?; + let mut encoder = ZlibEncoder::new(writer, Compression::default()); encoder.write_all(&packet_buf)?; encoder.finish()?; } else { - packet.write_var_i32(0)?; - packet.write_all(&packet_buf)?; + writer.write_var_i32(0)?; + writer.write_all(&packet_buf)?; }; - writer.write_var_i32(packet.len() as i32)?; - writer.write_all(&packet)?; - Ok(()) } } impl Decoder for CompressedRawPacket { - type Output = UncompressedRawPacket; + type Output = RawPacket; fn decode(reader: &mut R) -> Result { - let packet_len = reader.read_var_i32()? as usize; - let packet_buf = read_n(reader, packet_len)?; - - let mut reader = &mut packet_buf.as_slice(); - let data_len = reader.read_var_i32()? as usize; let packet = if data_len == 0 { - RawPacket::decode(&mut reader)? + RawPacket::decode(reader)? } else { let mut decompressed = Vec::with_capacity(data_len); ZlibDecoder::new(reader).read_to_end(&mut decompressed)?; @@ -102,46 +120,7 @@ impl Decoder for CompressedRawPacket { RawPacket::decode(&mut decompressed.as_slice())? }; - Ok(UncompressedRawPacket { packet }) - } -} - -#[derive(Debug, Clone)] -pub struct UncompressedRawPacket { - packet: RawPacket, -} - -impl UncompressedRawPacket { - /// Compress the packet if is is bigger than given threshold. A negative threshold disables compression. - pub fn compress(self, threshold: i32) -> CompressedRawPacket { - CompressedRawPacket { - packet: self.packet, - threshold, - } - } -} - -impl Encoder for UncompressedRawPacket { - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - let mut packet_buf = Vec::new(); - self.packet.encode(&mut packet_buf)?; - - writer.write_var_i32(packet_buf.len() as i32)?; - writer.write_all(&packet_buf)?; - - Ok(()) - } -} - -impl Decoder for UncompressedRawPacket { - type Output = Self; - - fn decode(reader: &mut R) -> Result { - let packet_len = reader.read_var_i32()? as usize; - let packet_buf = read_n(reader, packet_len)?; - let packet = RawPacket::decode(&mut packet_buf.as_slice())?; - - Ok(Self { packet }) + Ok(packet) } } @@ -172,12 +151,10 @@ mod tests { let mut data = Vec::new(); ping_request.encode(&mut data).unwrap(); - let packet = UncompressedRawPacket { - packet: RawPacket { id: 1, data }, - }; + let packet = Packet { id: 1, data }; let mut vec = Vec::new(); - packet.encode(&mut vec).unwrap(); + packet.encode(&mut vec, None).unwrap(); assert_eq!(vec, ping_request_packet_bytes()); } @@ -185,9 +162,7 @@ mod tests { #[test] fn test_uncompressed_packet_decode() { let vec = ping_request_packet_bytes(); - let packet = UncompressedRawPacket::decode(&mut vec.as_slice()) - .unwrap() - .packet; + let packet = Packet::decode(&mut vec.as_slice(), false).unwrap(); assert_eq!(packet.id, 1); assert_eq!(packet.data, PING_REQUEST_BYTES); @@ -202,17 +177,12 @@ mod tests { let mut data = Vec::new(); ping_request.encode(&mut data).unwrap(); - let packet = CompressedRawPacket { - packet: RawPacket { id: 1, data }, - threshold: 0, - }; + let packet = Packet { id: 1, data }; let mut vec = Vec::new(); - packet.encode(&mut vec).unwrap(); + packet.encode(&mut vec, Some(0)).unwrap(); - let packet = CompressedRawPacket::decode(&mut vec.as_slice()) - .unwrap() - .packet; + let packet = Packet::decode(&mut vec.as_slice(), true).unwrap(); assert_eq!(packet.id, 1); assert_eq!(packet.data, PING_REQUEST_BYTES); From 71e34f115182562c0123172687b1319f632d7b1a Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 5 Feb 2022 18:16:34 +0100 Subject: [PATCH 8/8] Avoid cloning. --- protocol/src/packet.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/src/packet.rs b/protocol/src/packet.rs index b85cba5..c1d1918 100644 --- a/protocol/src/packet.rs +++ b/protocol/src/packet.rs @@ -17,14 +17,14 @@ pub struct Packet { impl Packet { pub fn encode( - &self, + self, writer: &mut W, compression_threshold: Option, ) -> Result<(), EncodeError> { let mut buf = Vec::new(); let packet = RawPacket { id: self.id, - data: self.data.clone(), + data: self.data, }; if let Some(threshold) = compression_threshold { CompressedRawPacket { packet, threshold }.encode(&mut buf)?;