- add: packet-service to handle game client packets - fix: health check for database-service - fix: health check for auth-service
104 lines
3.2 KiB
Rust
104 lines
3.2 KiB
Rust
use bincode::{Encode, Decode};
|
|
use std::error::Error;
|
|
use tokio::io::AsyncWriteExt;
|
|
use tokio::net::TcpStream;
|
|
use tracing::{debug, error};
|
|
use crate::packet_type::PacketType;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Packet {
|
|
pub packet_size: u16,
|
|
pub packet_type: PacketType,
|
|
pub packet_crc: u16,
|
|
pub payload: Vec<u8>,
|
|
}
|
|
|
|
pub trait PacketPayload: Encode + Decode {
|
|
fn encode(&self) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
|
|
let config = bincode::config::standard()
|
|
.with_fixed_int_encoding();
|
|
Ok(bincode::encode_to_vec(self, config)?)
|
|
}
|
|
|
|
fn decode(data: &[u8]) -> Result<Self, Box<dyn std::error::Error + Send + Sync>>
|
|
where
|
|
Self: Sized,
|
|
{
|
|
let config = bincode::config::standard()
|
|
.with_fixed_int_encoding();
|
|
Ok(bincode::decode_from_slice(data, config)?.0)
|
|
}
|
|
}
|
|
|
|
impl Packet {
|
|
pub fn new<T: PacketPayload>(packet_type: PacketType, payload: &T) -> Result<Self, Box<dyn Error + Send + Sync>> {
|
|
let encoded_payload = <T as PacketPayload>::encode(payload)?;
|
|
let packet_size = (6 + encoded_payload.len()) as u16;
|
|
// let packet_crc = crc::crc16::checksum_x25(&encoded_payload);
|
|
let packet_crc = 0;
|
|
|
|
Ok(Self {
|
|
packet_size,
|
|
packet_type,
|
|
packet_crc,
|
|
payload: encoded_payload,
|
|
})
|
|
}
|
|
|
|
pub fn from_raw(data: &[u8]) -> Result<Self, Box<dyn Error + Send + Sync>> {
|
|
if data.len() < 6 {
|
|
return Err("Invalid packet: Too short".into());
|
|
}
|
|
|
|
// Extract packet fields
|
|
let packet_size = u16::from_le_bytes(data[0..2].try_into()?);
|
|
let raw_packet_type = u16::from_le_bytes(data[2..4].try_into()?);
|
|
let packet_crc = u16::from_le_bytes(data[4..6].try_into()?);
|
|
|
|
// Validate the size
|
|
if packet_size as usize != data.len() {
|
|
error!("Invalid packet: Size mismatch, expected: {}, actual: {}", packet_size, data.len());
|
|
return Err("Invalid packet: Size mismatch".into());
|
|
}
|
|
|
|
debug!("size: {:#X}, raw_type: {:#X}, crc: {:#X}", packet_size, raw_packet_type, packet_crc);
|
|
|
|
// Convert raw packet type into `PacketType` enum
|
|
let packet_type = PacketType::try_from(raw_packet_type)?;
|
|
|
|
// Extract the payload
|
|
let payload = data[6..].to_vec();
|
|
|
|
Ok(Self {
|
|
packet_size,
|
|
packet_type,
|
|
packet_crc,
|
|
payload,
|
|
})
|
|
}
|
|
|
|
/// Serialize the `Packet` back to raw bytes
|
|
pub fn to_raw(&self) -> Vec<u8> {
|
|
let mut raw = Vec::with_capacity(self.packet_size as usize);
|
|
|
|
// Serialize fields
|
|
raw.extend(&self.packet_size.to_le_bytes());
|
|
raw.extend(&(self.packet_type as u16).to_le_bytes());
|
|
raw.extend(&self.packet_crc.to_le_bytes());
|
|
raw.extend(&self.payload);
|
|
|
|
raw
|
|
}
|
|
|
|
pub fn parse<T: PacketPayload>(&self) -> Result<T, Box<dyn Error + Send + Sync>> {
|
|
<T as PacketPayload>::decode(&self.payload)
|
|
}
|
|
}
|
|
|
|
pub async fn send_packet(stream: &mut TcpStream, packet: &Packet) -> Result<(), std::io::Error> {
|
|
let data = packet.to_raw();
|
|
debug!("Sending data: {:?}", data);
|
|
stream.write_all(&data).await?;
|
|
Ok(())
|
|
}
|