use lz4_flex::{compress_prepend_size, decompress_size_prepended};
use std::io::{self, Cursor, Read};
#[derive(Debug, Clone)]
pub struct Packet {
pub id: u64,
pub ack: bool,
pub compressed: bool,
pub data: String,
}
impl Packet {
pub fn new(id: u64, data: String, compressed: bool) -> Self {
Self {
id,
ack: false,
compressed,
data,
}
}
pub fn serialize(&self) -> Vec<u8> {
let mut payload = format!("{}|{}|{}", self.id, self.ack as u8, self.data).into_bytes();
if self.compressed {
payload = compress_prepend_size(&payload);
}
let len = (payload.len() as u32).to_be_bytes();
[len.as_slice(), &payload].concat()
}
pub fn deserialize(stream: &mut Cursor<Vec<u8>>, compressed: bool) -> io::Result<Option<Self>> {
let mut len_buf = [0u8; 4];
if stream.read_exact(&mut len_buf).is_err() {
return Ok(None);
}
let len = u32::from_be_bytes(len_buf) as usize;
let mut payload = vec![0u8; len];
if stream.read_exact(&mut payload).is_err() {
return Ok(None);
}
let data = if compressed {
decompress_size_prepended(&payload).map_err(|_| io::ErrorKind::InvalidData)?
} else {
payload
};
let text = String::from_utf8_lossy(&data);
let mut parts = text.splitn(3, '|');
let id = parts.next().unwrap_or("0").parse().unwrap_or(0);
let ack = parts.next().unwrap_or("0") == "1";
let data = parts.next().unwrap_or("").to_string();
Ok(Some(Packet {
id,
ack,
compressed,
data,
}))
}
}