use std::io::{self, Cursor, Read, Write};
use thiserror::Error;
use crate::ser::{Deserialize, SerializationError, Serialize};
use crate::varint::{VarInt, VarIntError};
#[cfg(feature = "async")]
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[derive(Debug, Error)]
pub enum PacketError {
#[error("VarInt error: {0}")]
VarInt(#[from] VarIntError),
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] SerializationError),
#[error("Invalid packet length: {0}")]
InvalidLength(i64),
}
pub trait PacketId {
fn packet_id(&self) -> i32;
}
#[derive(Debug, Clone)]
pub struct RawPacket {
pub data: Vec<u8>,
}
impl RawPacket {
pub fn new(data: Vec<u8>) -> Self {
RawPacket { data }
}
pub fn read_sync<R: Read>(reader: &mut R) -> Result<Self, PacketError> {
let len = VarInt::read_sync(reader)?;
if len.0 < 0 {
return Err(PacketError::InvalidLength(len.0 as i64));
}
let mut data = vec![0u8; len.0 as usize];
reader.read_exact(&mut data)?;
Ok(RawPacket { data })
}
pub fn write_sync<W: Write>(&self, writer: &mut W) -> Result<(), PacketError> {
VarInt(self.data.len() as i32).write_sync(writer)?;
writer.write_all(&self.data)?;
Ok(())
}
#[cfg(feature = "async")]
pub async fn read_async<R: AsyncReadExt + Unpin>(reader: &mut R) -> Result<Self, PacketError> {
let len = VarInt::read_async(reader).await?;
if len.0 < 0 {
return Err(PacketError::InvalidLength(len.0 as i64));
}
let mut data = vec![0u8; len.0 as usize];
reader.read_exact(&mut data).await?;
Ok(RawPacket { data })
}
#[cfg(feature = "async")]
pub async fn write_async<W: AsyncWriteExt + Unpin>(
&self,
writer: &mut W,
) -> Result<(), PacketError> {
VarInt(self.data.len() as i32).write_async(writer).await?;
writer.write_all(&self.data).await?;
Ok(())
}
pub fn as_uncompressed(&self) -> Result<UncompressedPacket, PacketError> {
let mut cursor = Cursor::new(&self.data);
let packet_id = VarInt::read_sync(&mut cursor)?;
let pos = cursor.position() as usize;
let payload = self.data[pos..].to_vec();
Ok(UncompressedPacket {
packet_id: packet_id.0,
payload,
})
}
#[cfg(feature = "compression")]
pub fn uncompress(&self, threshold: Option<i32>) -> Result<UncompressedPacket, PacketError> {
use crate::compression::decompress_zlib;
if threshold.is_none() {
return self.as_uncompressed();
}
let mut cursor = Cursor::new(&self.data);
let data_length = VarInt::read_sync(&mut cursor)?;
let compressed_start = cursor.position() as usize;
if data_length.0 == 0 {
let packet_id = VarInt::read_sync(&mut cursor)?;
let pos = cursor.position() as usize;
let payload = self.data[pos..].to_vec();
return Ok(UncompressedPacket {
packet_id: packet_id.0,
payload,
});
}
let compressed_data = &self.data[compressed_start..];
let uncompressed = decompress_zlib(compressed_data)?;
let mut inner = Cursor::new(&uncompressed);
let packet_id = VarInt::read_sync(&mut inner)?;
let pos = inner.position() as usize;
let payload = uncompressed[pos..].to_vec();
Ok(UncompressedPacket {
packet_id: packet_id.0,
payload,
})
}
#[cfg(not(feature = "compression"))]
pub fn uncompress(&self, _threshold: Option<i32>) -> Result<UncompressedPacket, PacketError> {
self.as_uncompressed()
}
}
#[derive(Debug, Clone)]
pub struct UncompressedPacket {
pub packet_id: i32,
pub payload: Vec<u8>,
}
impl UncompressedPacket {
pub fn new(packet_id: i32, payload: Vec<u8>) -> Self {
UncompressedPacket { packet_id, payload }
}
pub fn deserialize_payload<T: Deserialize>(&self) -> Result<T, PacketError> {
let mut cursor = Cursor::new(&self.payload);
Ok(T::deserialize(&mut cursor)?)
}
pub fn to_raw_packet(&self) -> Result<RawPacket, PacketError> {
let mut buf = Vec::new();
VarInt(self.packet_id).write_sync(&mut buf)?;
std::io::Write::write_all(&mut buf, &self.payload)?;
Ok(RawPacket { data: buf })
}
#[cfg(feature = "compression")]
pub fn to_raw_packet_compressed(
&self,
threshold: Option<i32>,
) -> Result<RawPacket, PacketError> {
use crate::compression::compress_zlib;
let Some(t) = threshold else {
return self.to_raw_packet();
};
let mut inner = Vec::new();
VarInt(self.packet_id).write_sync(&mut inner)?;
inner.extend_from_slice(&self.payload);
let mut frame = Vec::new();
if inner.len() >= t as usize {
let compressed = compress_zlib(&inner)?;
VarInt(inner.len() as i32).write_sync(&mut frame)?;
frame.extend_from_slice(&compressed);
} else {
VarInt(0).write_sync(&mut frame)?;
frame.extend_from_slice(&inner);
}
Ok(RawPacket { data: frame })
}
#[cfg(not(feature = "compression"))]
pub fn to_raw_packet_compressed(
&self,
_threshold: Option<i32>,
) -> Result<RawPacket, PacketError> {
self.to_raw_packet()
}
pub fn from_packet<P: PacketId + Serialize>(packet: &P) -> Result<Self, PacketError> {
let mut payload = Vec::new();
packet.serialize(&mut payload)?;
Ok(UncompressedPacket {
packet_id: packet.packet_id(),
payload,
})
}
pub fn write_sync<W: Write>(&self, writer: &mut W) -> Result<(), PacketError> {
self.to_raw_packet()?.write_sync(writer)
}
#[cfg(feature = "async")]
pub async fn write_async<W: AsyncWriteExt + Unpin>(
&self,
writer: &mut W,
) -> Result<(), PacketError> {
self.to_raw_packet()?.write_async(writer).await
}
}