aboutsummaryrefslogtreecommitdiff
path: root/azalea-protocol/src
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2022-08-06 07:22:19 +0000
committerGitHub <noreply@github.com>2022-08-06 02:22:19 -0500
commit5a9fca0ca9cdb46f4b866781f219756c89e2293a (patch)
treeb006e28b91a181734fb9702bb6ec510f5b2af3df /azalea-protocol/src
parent1d48c3fe34edd4e2295f54bd3d79f81f58c38a8e (diff)
downloadazalea-drasl-5a9fca0ca9cdb46f4b866781f219756c89e2293a.tar.xz
Better errors (#14)
* make reading use thiserror * finish implementing all the error things * clippy warnings related to ok_or * fix some errors in other places * thiserror in more places * don't use closures in a couple places * errors in writing packet * rip backtraces * change some BufReadError::Custom to UnexpectedEnumVariant * Errors say what packet is bad * error on leftover data and fix it wasn't reading the properties for gameprofile
Diffstat (limited to 'azalea-protocol/src')
-rwxr-xr-xazalea-protocol/src/connect.rs25
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs4
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_info_packet.rs6
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_position_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_recipe_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_equipment_packet.rs12
-rw-r--r--azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs6
-rw-r--r--azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs6
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_update_tags_packet.rs6
-rwxr-xr-xazalea-protocol/src/packets/login/clientbound_game_profile_packet.rs29
-rwxr-xr-xazalea-protocol/src/packets/login/clientbound_login_compression_packet.rs4
-rw-r--r--azalea-protocol/src/packets/login/serverbound_key_packet.rs4
-rw-r--r--azalea-protocol/src/packets/mod.rs11
-rwxr-xr-xazalea-protocol/src/packets/status/clientbound_status_response_packet.rs11
-rwxr-xr-xazalea-protocol/src/read.rs118
-rwxr-xr-xazalea-protocol/src/resolver.rs20
-rwxr-xr-xazalea-protocol/src/write.rs63
22 files changed, 217 insertions, 147 deletions
diff --git a/azalea-protocol/src/connect.rs b/azalea-protocol/src/connect.rs
index cd51f86c..e29ba1df 100755
--- a/azalea-protocol/src/connect.rs
+++ b/azalea-protocol/src/connect.rs
@@ -5,12 +5,13 @@ use crate::packets::handshake::{ClientboundHandshakePacket, ServerboundHandshake
use crate::packets::login::{ClientboundLoginPacket, ServerboundLoginPacket};
use crate::packets::status::{ClientboundStatusPacket, ServerboundStatusPacket};
use crate::packets::ProtocolPacket;
-use crate::read::read_packet;
+use crate::read::{read_packet, ReadPacketError};
use crate::write::write_packet;
use crate::ServerIpAddress;
use azalea_crypto::{Aes128CfbDec, Aes128CfbEnc};
use std::fmt::Debug;
use std::marker::PhantomData;
+use thiserror::Error;
use tokio::net::TcpStream;
pub struct Connection<R: ProtocolPacket, W: ProtocolPacket> {
@@ -28,7 +29,7 @@ where
R: ProtocolPacket + Debug,
W: ProtocolPacket + Debug,
{
- pub async fn read(&mut self) -> Result<R, String> {
+ pub async fn read(&mut self) -> Result<R, ReadPacketError> {
read_packet::<R, _>(
&mut self.stream,
self.compression_threshold,
@@ -38,30 +39,32 @@ where
}
/// Write a packet to the server
- pub async fn write(&mut self, packet: W) {
+ pub async fn write(&mut self, packet: W) -> std::io::Result<()> {
write_packet(
packet,
&mut self.stream,
self.compression_threshold,
&mut self.enc_cipher,
)
- .await;
+ .await
}
}
+#[derive(Error, Debug)]
+pub enum ConnectionError {
+ #[error("{0}")]
+ Io(#[from] std::io::Error),
+}
+
impl Connection<ClientboundHandshakePacket, ServerboundHandshakePacket> {
- pub async fn new(address: &ServerIpAddress) -> Result<Self, String> {
+ pub async fn new(address: &ServerIpAddress) -> Result<Self, ConnectionError> {
let ip = address.ip;
let port = address.port;
- let stream = TcpStream::connect(format!("{}:{}", ip, port))
- .await
- .map_err(|_| "Failed to connect to server")?;
+ let stream = TcpStream::connect(format!("{}:{}", ip, port)).await?;
// enable tcp_nodelay
- stream
- .set_nodelay(true)
- .expect("Error enabling tcp_nodelay");
+ stream.set_nodelay(true)?;
Ok(Connection {
stream,
diff --git a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs b/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
index f45946d5..622b9ec7 100755
--- a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
@@ -1,3 +1,4 @@
+use azalea_buf::BufReadError;
use azalea_buf::McBuf;
use azalea_buf::McBufVarReadable;
use azalea_buf::{McBufReadable, McBufWritable, Readable, Writable};
@@ -24,7 +25,7 @@ pub struct BrigadierNumber<T> {
max: Option<T>,
}
impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let flags = buf.read_byte()?;
let min = if flags & 0x01 != 0 {
Some(T::read_from(buf)?)
@@ -123,7 +124,7 @@ pub enum BrigadierParser {
}
impl McBufReadable for BrigadierParser {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let parser_type = u32::var_read_from(buf)?;
match parser_type {
@@ -190,14 +191,16 @@ impl McBufReadable for BrigadierParser {
45 => Ok(BrigadierParser::TemplateMirror),
46 => Ok(BrigadierParser::TemplateRotation),
47 => Ok(BrigadierParser::Uuid),
- _ => Err(format!("Unknown BrigadierParser type: {}", parser_type)),
+ _ => Err(BufReadError::UnexpectedEnumVariant {
+ id: parser_type as i32,
+ }),
}
}
}
// TODO: BrigadierNodeStub should have more stuff
impl McBufReadable for BrigadierNodeStub {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let flags = u8::read_from(buf)?;
if flags > 31 {
println!(
diff --git a/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs
index 8b52b8cf..d85f39cb 100644
--- a/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::{McBufReadable, McBufVarReadable, McBufWritable};
+use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufWritable};
use azalea_core::ParticleData;
use packet_macros::ClientboundGamePacket;
use std::io::{Read, Write};
@@ -20,7 +20,7 @@ pub struct ClientboundLevelParticlesPacket {
}
impl McBufReadable for ClientboundLevelParticlesPacket {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let particle_id = u32::var_read_from(buf)?;
let override_limiter = bool::read_from(buf)?;
let x = f64::read_from(buf)?;
diff --git a/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs
index 9a312276..5ab187ae 100755
--- a/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable, Readable};
use packet_macros::ClientboundGamePacket;
use std::io::{Read, Write};
@@ -20,7 +20,7 @@ pub struct PlayerAbilitiesFlags {
}
impl McBufReadable for PlayerAbilitiesFlags {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let byte = buf.read_byte()?;
Ok(PlayerAbilitiesFlags {
invulnerable: byte & 1 != 0,
diff --git a/azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs
index a2caae4b..7414e10c 100644
--- a/azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::{BitSet, McBuf, McBufReadable, McBufVarWritable};
+use azalea_buf::{BitSet, BufReadError, McBuf, McBufReadable, McBufVarWritable};
use azalea_buf::{McBufVarReadable, McBufWritable};
use azalea_chat::component::Component;
use azalea_crypto::{MessageSignature, SignedMessageHeader};
@@ -74,13 +74,15 @@ pub enum FilterMask {
}
impl McBufReadable for FilterMask {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let filter_mask = u32::var_read_from(buf)?;
match filter_mask {
0 => Ok(FilterMask::PassThrough),
1 => Ok(FilterMask::FullyFiltered),
2 => Ok(FilterMask::PartiallyFiltered(BitSet::read_from(buf)?)),
- _ => Err("Invalid filter mask".to_string()),
+ _ => Err(BufReadError::UnexpectedEnumVariant {
+ id: filter_mask as i32,
+ }),
}
}
}
diff --git a/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs
index 614a351e..d53774b7 100644
--- a/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_chat::component::Component;
use packet_macros::ClientboundGamePacket;
@@ -63,7 +63,7 @@ pub struct RemovePlayer {
}
impl McBufReadable for Action {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let id = buf.read_byte()?;
Ok(match id {
0 => Action::AddPlayer(Vec::<AddPlayer>::read_from(buf)?),
@@ -71,7 +71,7 @@ impl McBufReadable for Action {
2 => Action::UpdateLatency(Vec::<UpdateLatency>::read_from(buf)?),
3 => Action::UpdateDisplayName(Vec::<UpdateDisplayName>::read_from(buf)?),
4 => Action::RemovePlayer(Vec::<RemovePlayer>::read_from(buf)?),
- _ => panic!("Unknown player info action id: {}", id),
+ _ => return Err(BufReadError::UnexpectedEnumVariant { id: id.into() }),
})
}
}
diff --git a/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs
index 758e6bb0..d4c9dcb5 100644
--- a/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable, Readable};
use packet_macros::ClientboundGamePacket;
use std::io::{Read, Write};
@@ -28,7 +28,7 @@ pub struct RelativeArguments {
}
impl McBufReadable for RelativeArguments {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let byte = buf.read_byte()?;
Ok(RelativeArguments {
x: byte & 0b1 != 0,
diff --git a/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs b/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs
index e6a5bf7f..05e96f69 100644
--- a/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_core::ResourceLocation;
use packet_macros::ClientboundGamePacket;
@@ -41,7 +41,7 @@ impl McBufWritable for State {
}
}
impl McBufReadable for State {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let state = buf.read_varint()?;
Ok(match state {
0 => State::Init,
diff --git a/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs
index 0a83edf0..5dee398e 100644
--- a/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
use azalea_core::{ChunkSectionBlockPos, ChunkSectionPos};
use packet_macros::ClientboundGamePacket;
@@ -18,7 +18,7 @@ pub struct BlockStateWithPosition {
}
impl McBufReadable for BlockStateWithPosition {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let data = u64::var_read_from(buf)?;
let position_part = data & 4095;
let state = (data >> 12) as u32;
diff --git a/azalea-protocol/src/packets/game/clientbound_set_equipment_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_equipment_packet.rs
index 102e90e1..35f0d251 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_equipment_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_equipment_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_core::Slot;
use packet_macros::ClientboundGamePacket;
@@ -17,13 +17,17 @@ pub struct EquipmentSlots {
}
impl McBufReadable for EquipmentSlots {
- fn read_from(buf: &mut impl std::io::Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl std::io::Read) -> Result<Self, BufReadError> {
let mut slots = vec![];
loop {
let equipment_byte = u8::read_from(buf)?;
- let equipment_slot = EquipmentSlot::from_byte(equipment_byte & 127)
- .ok_or_else(|| format!("Invalid equipment slot byte {}", equipment_byte))?;
+ let equipment_slot =
+ EquipmentSlot::from_byte(equipment_byte & 127).ok_or_else(|| {
+ BufReadError::UnexpectedEnumVariant {
+ id: equipment_byte.into(),
+ }
+ })?;
let item = Slot::read_from(buf)?;
slots.push((equipment_slot, item));
if equipment_byte & 128 == 0 {
diff --git a/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs
index 396c0fa4..88cb15e9 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::{McBuf, McBufReadable, McBufWritable};
+use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
use azalea_chat::component::Component;
use azalea_core::{ResourceLocation, Slot};
use packet_macros::ClientboundGamePacket;
@@ -45,7 +45,7 @@ pub struct DisplayFlags {
}
impl McBufReadable for DisplayFlags {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let data = u32::read_from(buf)?;
Ok(DisplayFlags {
background: (data & 0b1) != 0,
diff --git a/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs
index b8785a66..6bb41a81 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_core::ResourceLocation;
use packet_macros::ClientboundGamePacket;
@@ -34,12 +34,12 @@ enum Operation {
}
impl McBufReadable for Operation {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
match buf.read_byte()? {
0 => Ok(Operation::Addition),
1 => Ok(Operation::MultiplyBase),
2 => Ok(Operation::MultiplyTotal),
- op => Err(format!("Unknown operation: {}", op)),
+ id => Err(BufReadError::UnexpectedEnumVariant { id: id.into() }),
}
}
}
diff --git a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
index 7a96629b..da1485d0 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
@@ -1,6 +1,6 @@
use std::io::{Read, Write};
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_core::{ResourceLocation, Slot};
use packet_macros::ClientboundGamePacket;
@@ -49,7 +49,7 @@ impl McBufWritable for ShapedRecipe {
}
}
impl McBufReadable for ShapedRecipe {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let width = buf.read_varint()?.try_into().unwrap();
let height = buf.read_varint()?.try_into().unwrap();
let group = buf.read_utf()?;
@@ -129,7 +129,7 @@ impl McBufWritable for Recipe {
}
impl McBufReadable for Recipe {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let recipe_type = ResourceLocation::read_from(buf)?;
let identifier = ResourceLocation::read_from(buf)?;
diff --git a/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs
index 6d567cfa..6f0fe778 100755
--- a/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_core::ResourceLocation;
use packet_macros::ClientboundGamePacket;
@@ -23,7 +23,7 @@ pub struct Tags {
pub struct TagMap(HashMap<ResourceLocation, Vec<Tags>>);
impl McBufReadable for TagMap {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let length = buf.read_varint()? as usize;
let mut data = HashMap::with_capacity(length);
for _ in 0..length {
@@ -51,7 +51,7 @@ impl McBufWritable for TagMap {
}
}
impl McBufReadable for Tags {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let name = ResourceLocation::read_from(buf)?;
let elements = buf.read_int_id_list()?;
Ok(Tags { name, elements })
diff --git a/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs b/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs
index 9d9ce35b..93421cc2 100755
--- a/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs
+++ b/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs
@@ -2,34 +2,11 @@ use std::io::{Read, Write};
use super::ClientboundLoginPacket;
use azalea_auth::game_profile::GameProfile;
-use azalea_buf::{McBufReadable, Readable, SerializableUuid, Writable};
+use azalea_buf::{BufReadError, McBuf, McBufReadable, Readable, SerializableUuid, Writable};
+use packet_macros::ClientboundLoginPacket;
use uuid::Uuid;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, McBuf, ClientboundLoginPacket)]
pub struct ClientboundGameProfilePacket {
pub game_profile: GameProfile,
}
-
-// TODO: add derives to GameProfile and have an impl McBufReadable/Writable for GameProfile
-impl ClientboundGameProfilePacket {
- pub fn get(self) -> ClientboundLoginPacket {
- ClientboundLoginPacket::ClientboundGameProfilePacket(self)
- }
-
- pub fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- for n in self.game_profile.uuid.to_int_array() {
- buf.write_int(n as i32).unwrap();
- }
- buf.write_utf(self.game_profile.name.as_str()).unwrap();
- Ok(())
- }
-
- pub fn read(buf: &mut impl Read) -> Result<ClientboundLoginPacket, String> {
- let uuid = Uuid::read_from(buf)?;
- let name = buf.read_utf_with_len(16)?;
- Ok(ClientboundGameProfilePacket {
- game_profile: GameProfile::new(uuid, name),
- }
- .get())
- }
-}
diff --git a/azalea-protocol/src/packets/login/clientbound_login_compression_packet.rs b/azalea-protocol/src/packets/login/clientbound_login_compression_packet.rs
index 39314041..26321f34 100755
--- a/azalea-protocol/src/packets/login/clientbound_login_compression_packet.rs
+++ b/azalea-protocol/src/packets/login/clientbound_login_compression_packet.rs
@@ -3,7 +3,7 @@ use std::{
io::{Read, Write},
};
-use azalea_buf::{Readable, Writable};
+use azalea_buf::{BufReadError, Readable, Writable};
use super::ClientboundLoginPacket;
@@ -22,7 +22,7 @@ impl ClientboundLoginCompressionPacket {
Ok(())
}
- pub fn read(buf: &mut impl Read) -> Result<ClientboundLoginPacket, String> {
+ pub fn read(buf: &mut impl Read) -> Result<ClientboundLoginPacket, BufReadError> {
let compression_threshold = buf.read_varint()?;
Ok(ClientboundLoginCompressionPacket {
diff --git a/azalea-protocol/src/packets/login/serverbound_key_packet.rs b/azalea-protocol/src/packets/login/serverbound_key_packet.rs
index 62dc6252..54f268e7 100644
--- a/azalea-protocol/src/packets/login/serverbound_key_packet.rs
+++ b/azalea-protocol/src/packets/login/serverbound_key_packet.rs
@@ -1,4 +1,4 @@
-use azalea_buf::McBuf;
+use azalea_buf::{BufReadError, McBuf};
use azalea_crypto::SaltSignaturePair;
use packet_macros::ServerboundLoginPacket;
use std::io::{Read, Write};
@@ -18,7 +18,7 @@ pub enum NonceOrSaltSignature {
}
impl McBufReadable for NonceOrSaltSignature {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let is_nonce = bool::read_from(buf)?;
if is_nonce {
Ok(NonceOrSaltSignature::Nonce(Vec::<u8>::read_from(buf)?))
diff --git a/azalea-protocol/src/packets/mod.rs b/azalea-protocol/src/packets/mod.rs
index 228d7c74..da1631a0 100644
--- a/azalea-protocol/src/packets/mod.rs
+++ b/azalea-protocol/src/packets/mod.rs
@@ -3,7 +3,8 @@ pub mod handshake;
pub mod login;
pub mod status;
-use azalea_buf::{McBufWritable, Readable, Writable};
+use crate::read::ReadPacketError;
+use azalea_buf::{BufReadError, McBufWritable, Readable, Writable};
use std::io::{Read, Write};
pub const PROTOCOL_VERSION: u32 = 760;
@@ -36,15 +37,15 @@ where
fn id(&self) -> u32;
/// Read a packet by its id, ConnectionProtocol, and flow
- fn read(id: u32, buf: &mut impl Read) -> Result<Self, String>;
+ fn read(id: u32, buf: &mut impl Read) -> Result<Self, ReadPacketError>;
fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error>;
}
impl azalea_buf::McBufReadable for ConnectionProtocol {
- fn read_from(buf: &mut impl Read) -> Result<Self, String> {
- ConnectionProtocol::from_i32(buf.read_varint()?)
- .ok_or_else(|| "Invalid intention".to_string())
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ let id = buf.read_varint()?;
+ ConnectionProtocol::from_i32(id).ok_or(BufReadError::UnexpectedEnumVariant { id })
}
}
diff --git a/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs b/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs
index 2e4116fa..8724816b 100755
--- a/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs
+++ b/azalea-protocol/src/packets/status/clientbound_status_response_packet.rs
@@ -1,5 +1,5 @@
use super::ClientboundStatusPacket;
-use azalea_buf::Readable;
+use azalea_buf::{BufReadError, Readable};
use azalea_chat::component::Component;
use serde::Deserialize;
use serde_json::Value;
@@ -42,14 +42,11 @@ impl ClientboundStatusResponsePacket {
Ok(())
}
- pub fn read(buf: &mut impl Read) -> Result<ClientboundStatusPacket, String> {
+ pub fn read(buf: &mut impl Read) -> Result<ClientboundStatusPacket, BufReadError> {
let status_string = buf.read_utf()?;
- let status_json: Value =
- serde_json::from_str(status_string.as_str()).expect("Server status isn't valid JSON");
+ let status_json: Value = serde_json::from_str(status_string.as_str())?;
- let packet = ClientboundStatusResponsePacket::deserialize(status_json)
- .map_err(|e| e.to_string())?
- .get();
+ let packet = ClientboundStatusResponsePacket::deserialize(status_json)?.get();
Ok(packet)
}
diff --git a/azalea-protocol/src/read.rs b/azalea-protocol/src/read.rs
index 6a56ccfb..077e1297 100755
--- a/azalea-protocol/src/read.rs
+++ b/azalea-protocol/src/read.rs
@@ -1,5 +1,6 @@
use crate::packets::ProtocolPacket;
-use azalea_buf::{read_varint_async, Readable};
+use azalea_buf::McBufVarReadable;
+use azalea_buf::{read_varint_async, BufReadError, Readable};
use azalea_crypto::Aes128CfbDec;
use flate2::read::ZlibDecoder;
use std::{
@@ -8,32 +9,67 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
+use thiserror::Error;
use tokio::io::{AsyncRead, AsyncReadExt};
-async fn frame_splitter<R: ?Sized>(mut stream: &mut R) -> Result<Vec<u8>, String>
+#[derive(Error, Debug)]
+pub enum ReadPacketError {
+ #[error("Error reading packet {packet_name} ({packet_id}): {source}")]
+ Parse {
+ packet_id: u32,
+ packet_name: String,
+ source: BufReadError,
+ },
+ #[error("Unknown packet id {id} in state {state_name}")]
+ UnknownPacketId { state_name: String, id: u32 },
+ #[error("Couldn't read packet id")]
+ ReadPacketId { source: BufReadError },
+ #[error("Couldn't decompress packet")]
+ Decompress {
+ #[from]
+ source: DecompressionError,
+ },
+ #[error("Frame splitter error")]
+ FrameSplitter {
+ #[from]
+ source: FrameSplitterError,
+ },
+ #[error("Leftover data after reading packet {packet_name}: {data:?}")]
+ LeftoverData { data: Vec<u8>, packet_name: String },
+}
+
+#[derive(Error, Debug)]
+pub enum FrameSplitterError {
+ #[error("Couldn't read VarInt length for packet. The previous packet may have been corrupted")]
+ LengthRead {
+ #[from]
+ source: BufReadError,
+ },
+ #[error("Io error")]
+ Io {
+ #[from]
+ source: std::io::Error,
+ },
+}
+
+async fn frame_splitter<R: ?Sized>(mut stream: &mut R) -> Result<Vec<u8>, FrameSplitterError>
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
// Packet Length
- let length_result = read_varint_async(&mut stream).await;
- match length_result {
- Ok(length) => {
- let mut buf = vec![0; length as usize];
+ let length = read_varint_async(&mut stream).await?;
- stream
- .read_exact(&mut buf)
- .await
- .map_err(|e| e.to_string())?;
+ let mut buf = vec![0; length as usize];
+ stream.read_exact(&mut buf).await?;
- Ok(buf)
- }
- Err(_) => Err("length wider than 21-bit".to_string()),
- }
+ Ok(buf)
}
-fn packet_decoder<P: ProtocolPacket>(stream: &mut impl Read) -> Result<P, String> {
+fn packet_decoder<P: ProtocolPacket>(stream: &mut impl Read) -> Result<P, ReadPacketError> {
// Packet ID
- let packet_id = stream.read_varint()?;
+ let packet_id = stream
+ .read_varint()
+ .map_err(|e| ReadPacketError::ReadPacketId { source: e })?;
P::read(packet_id.try_into().unwrap(), stream)
}
@@ -42,39 +78,57 @@ static VALIDATE_DECOMPRESSED: bool = true;
pub static MAXIMUM_UNCOMPRESSED_LENGTH: u32 = 2097152;
+#[derive(Error, Debug)]
+pub enum DecompressionError {
+ #[error("Couldn't read VarInt length for data")]
+ LengthReadError {
+ #[from]
+ source: BufReadError,
+ },
+ #[error("Io error")]
+ Io {
+ #[from]
+ source: std::io::Error,
+ },
+ #[error("Badly compressed packet - size of {size} is below server threshold of {threshold}")]
+ BelowCompressionThreshold { size: u32, threshold: u32 },
+ #[error(
+ "Badly compressed packet - size of {size} is larger than protocol maximum of {maximum}"
+ )]
+ AboveCompressionThreshold { size: u32, maximum: u32 },
+}
+
fn compression_decoder(
stream: &mut impl Read,
compression_threshold: u32,
-) -> Result<Vec<u8>, String> {
+) -> Result<Vec<u8>, DecompressionError> {
// Data Length
- let n: u32 = stream.read_varint()?.try_into().unwrap();
+ let n = u32::var_read_from(stream)?;
if n == 0 {
// no data size, no compression
let mut buf = vec![];
- stream.read_to_end(&mut buf).map_err(|e| e.to_string())?;
+ stream.read_to_end(&mut buf)?;
return Ok(buf);
}
if VALIDATE_DECOMPRESSED {
if n < compression_threshold {
- return Err(format!(
- "Badly compressed packet - size of {} is below server threshold of {}",
- n, compression_threshold
- ));
+ return Err(DecompressionError::BelowCompressionThreshold {
+ size: n,
+ threshold: compression_threshold,
+ });
}
if n > MAXIMUM_UNCOMPRESSED_LENGTH {
- return Err(format!(
- "Badly compressed packet - size of {} is larger than protocol maximum of {}",
- n, MAXIMUM_UNCOMPRESSED_LENGTH
- ));
+ return Err(DecompressionError::AboveCompressionThreshold {
+ size: n,
+ maximum: MAXIMUM_UNCOMPRESSED_LENGTH,
+ });
}
}
let mut decoded_buf = vec![];
let mut decoder = ZlibDecoder::new(stream);
- decoder
- .read_to_end(&mut decoded_buf)
- .map_err(|e| e.to_string())?;
+ decoder.read_to_end(&mut decoded_buf)?;
Ok(decoded_buf)
}
@@ -121,7 +175,7 @@ pub async fn read_packet<'a, P: ProtocolPacket, R>(
stream: &'a mut R,
compression_threshold: Option<u32>,
cipher: &mut Option<Aes128CfbDec>,
-) -> Result<P, String>
+) -> Result<P, ReadPacketError>
where
R: AsyncRead + std::marker::Unpin + std::marker::Send + std::marker::Sync,
{
@@ -149,5 +203,7 @@ where
let packet = packet_decoder(&mut buf.as_slice())?;
// println!("decoded packet ({}ms)", start_time.elapsed().as_millis());
+ if !buf.is_empty() {}
+
Ok(packet)
}
diff --git a/azalea-protocol/src/resolver.rs b/azalea-protocol/src/resolver.rs
index 24687a6e..e21362a5 100755
--- a/azalea-protocol/src/resolver.rs
+++ b/azalea-protocol/src/resolver.rs
@@ -1,16 +1,24 @@
-use std::net::IpAddr;
-
use crate::{ServerAddress, ServerIpAddress};
use async_recursion::async_recursion;
+use std::net::IpAddr;
+use thiserror::Error;
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
TokioAsyncResolver,
};
+#[derive(Error, Debug)]
+pub enum ResolverError {
+ #[error("No SRV record found")]
+ NoSrvRecord,
+ #[error("No IP found")]
+ NoIp,
+}
+
/// Resolve a Minecraft server address into an IP address and port.
/// If it's already an IP address, it's returned as-is.
#[async_recursion]
-pub async fn resolve_address(address: &ServerAddress) -> Result<ServerIpAddress, String> {
+pub async fn resolve_address(address: &ServerAddress) -> Result<ServerIpAddress, ResolverError> {
// If the address.host is already in the format of an ip address, return it.
if let Ok(ip) = address.host.parse::<IpAddr>() {
return Ok(ServerIpAddress {
@@ -33,20 +41,20 @@ pub async fn resolve_address(address: &ServerAddress) -> Result<ServerIpAddress,
let redirect_srv = redirect_result
.iter()
.next()
- .ok_or_else(|| "No SRV record found".to_string())?;
+ .ok_or(ResolverError::NoSrvRecord)?;
let redirect_address = ServerAddress {
host: redirect_srv.target().to_utf8(),
port: redirect_srv.port(),
};
- println!("redirecting to {:?}", redirect_address);
+ // println!("redirecting to {:?}", redirect_address);
return resolve_address(&redirect_address).await;
}
// there's no redirect, try to resolve this as an ip address
let lookup_ip_result = resolver.lookup_ip(address.host.clone()).await;
- let lookup_ip = lookup_ip_result.map_err(|_| "No IP found".to_string())?;
+ let lookup_ip = lookup_ip_result.map_err(|_| ResolverError::NoIp)?;
Ok(ServerIpAddress {
ip: lookup_ip.iter().next().unwrap(),
diff --git a/azalea-protocol/src/write.rs b/azalea-protocol/src/write.rs
index ae9a6829..30710f8b 100755
--- a/azalea-protocol/src/write.rs
+++ b/azalea-protocol/src/write.rs
@@ -3,49 +3,67 @@ use async_compression::tokio::bufread::ZlibEncoder;
use azalea_buf::Writable;
use azalea_crypto::Aes128CfbEnc;
use std::fmt::Debug;
+use thiserror::Error;
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
-fn frame_prepender(data: &mut Vec<u8>) -> Result<Vec<u8>, String> {
+fn frame_prepender(data: &mut Vec<u8>) -> Result<Vec<u8>, std::io::Error> {
let mut buf = Vec::new();
- buf.write_varint(data.len() as i32)
- .map_err(|e| e.to_string())?;
+ buf.write_varint(data.len() as i32)?;
buf.append(data);
Ok(buf)
}
-fn packet_encoder<P: ProtocolPacket + std::fmt::Debug>(packet: &P) -> Result<Vec<u8>, String> {
+#[derive(Error, Debug)]
+pub enum PacketEncodeError {
+ #[error("{0}")]
+ Io(#[from] std::io::Error),
+ #[error("Packet too big (is {actual} bytes, should be less than {maximum}): {packet_string}")]
+ TooBig {
+ actual: usize,
+ maximum: usize,
+ packet_string: String,
+ },
+}
+
+fn packet_encoder<P: ProtocolPacket + std::fmt::Debug>(
+ packet: &P,
+) -> Result<Vec<u8>, PacketEncodeError> {
let mut buf = Vec::new();
- buf.write_varint(packet.id() as i32)
- .map_err(|e| e.to_string())?;
- packet.write(&mut buf).map_err(|e| e.to_string())?;
+ buf.write_varint(packet.id() as i32)?;
+ packet.write(&mut buf)?;
if buf.len() > MAXIMUM_UNCOMPRESSED_LENGTH as usize {
- return Err(format!(
- "Packet too big (is {} bytes, should be less than {}): {:?}",
- buf.len(),
- MAXIMUM_UNCOMPRESSED_LENGTH,
- packet
- ));
+ return Err(PacketEncodeError::TooBig {
+ actual: buf.len(),
+ maximum: MAXIMUM_UNCOMPRESSED_LENGTH as usize,
+ packet_string: format!("{:?}", packet),
+ });
}
Ok(buf)
}
-async fn compression_encoder(data: &[u8], compression_threshold: u32) -> Result<Vec<u8>, String> {
+#[derive(Error, Debug)]
+pub enum PacketCompressError {
+ #[error("{0}")]
+ Io(#[from] std::io::Error),
+}
+
+async fn compression_encoder(
+ data: &[u8],
+ compression_threshold: u32,
+) -> Result<Vec<u8>, PacketCompressError> {
let n = data.len();
// if it's less than the compression threshold, don't compress
if n < compression_threshold as usize {
let mut buf = Vec::new();
- buf.write_varint(0).map_err(|e| e.to_string())?;
- buf.write_all(data).await.map_err(|e| e.to_string())?;
+ buf.write_varint(0)?;
+ buf.write_all(data).await?;
Ok(buf)
} else {
// otherwise, compress
let mut deflater = ZlibEncoder::new(data);
// write deflated data to buf
let mut buf = Vec::new();
- deflater
- .read_to_end(&mut buf)
- .await
- .map_err(|e| e.to_string())?;
+ deflater.read_to_end(&mut buf).await?;
Ok(buf)
}
}
@@ -55,7 +73,8 @@ pub async fn write_packet<P, W>(
stream: &mut W,
compression_threshold: Option<u32>,
cipher: &mut Option<Aes128CfbEnc>,
-) where
+) -> std::io::Result<()>
+where
P: ProtocolPacket + Debug,
W: AsyncWrite + Unpin + Send,
{
@@ -68,5 +87,5 @@ pub async fn write_packet<P, W>(
if let Some(cipher) = cipher {
azalea_crypto::encrypt_packet(cipher, &mut buf);
}
- stream.write_all(&buf).await.unwrap();
+ stream.write_all(&buf).await
}