Skip to content

Commit

Permalink
Move korangar_packets handler to separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
vE5li committed May 2, 2024
1 parent 2102d98 commit 7234e36
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 218 deletions.
3 changes: 2 additions & 1 deletion korangar/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ mod packet_recorder {

use korangar_debug::profiling::RingBuffer;
use korangar_interface::elements::WeakElementCell;
use ragnarok_packets::{IncomingPacket, OutgoingPacket, PacketCallback, PacketHeader, UnknownPacket};
use ragnarok_packets::handler::{PacketCallback, UnknownPacket};
use ragnarok_packets::{IncomingPacket, OutgoingPacket, PacketHeader};

use crate::interface::application::InterfaceSettings;
use crate::interface::elements::PacketEntry;
Expand Down
1 change: 1 addition & 0 deletions korangar_networking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use event::{
NoNetworkEvents,
};
use ragnarok_bytes::{ByteStream, FromBytes};
use ragnarok_packets::handler::{DuplicateHandlerError, HandlerResult, NoPacketCallback, PacketCallback, PacketHandler};
use ragnarok_packets::*;
use server::{ServerConnectCommand, ServerConnection};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
Expand Down
244 changes: 244 additions & 0 deletions ragnarok_packets/src/handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
use std::collections::HashMap;

use derive_new::new;
use ragnarok_bytes::{ByteStream, ConversionError, ConversionResult, FromBytes};

use crate::{IncomingPacket, OutgoingPacket, PacketHeader};

/// Helper struct for working with unknown incoming packets.
#[derive(Clone, new)]
pub struct UnknownPacket {
pub bytes: Vec<u8>,
}

impl IncomingPacket for UnknownPacket {
const HEADER: PacketHeader = PacketHeader(0);
const IS_PING: bool = false;

fn payload_from_bytes<Meta>(byte_stream: &mut ByteStream<Meta>) -> ConversionResult<Self> {
let _ = byte_stream;
unimplemented!()
}

#[cfg(feature = "packet-to-prototype-element")]
fn to_prototype_element<App: korangar_interface::application::Application>(
&self,
) -> Box<dyn korangar_interface::elements::PrototypeElement<App> + Send> {
Box::new(self.clone())
}
}

#[cfg(feature = "interface")]
impl<App: korangar_interface::application::Application> korangar_interface::elements::PrototypeElement<App> for UnknownPacket {
fn to_element(&self, display: String) -> korangar_interface::elements::ElementCell<App> {
use korangar_interface::elements::{ElementWrap, Expandable};

let mut byte_stream = ByteStream::<()>::without_metadata(&self.bytes);

let elements = match self.bytes.len() >= 2 {
true => {
let signature = PacketHeader::from_bytes(&mut byte_stream).unwrap();
let header = format!("0x{:0>4x}", signature.0);
let data = &self.bytes[byte_stream.get_offset()..];

vec![header.to_element("header".to_owned()), data.to_element("data".to_owned())]
}
false => {
vec![self.bytes.to_element("data".to_owned())]
}
};

Expandable::new(display, elements, false).wrap()
}
}

/// Possible results of [`PacketHandler::process_one`].
pub enum HandlerResult<Output> {
/// Packet was successfully processed and produced some output.
Ok(Output),
/// No packet handler was registered for the incoming packet.
UnhandledPacket,
/// Packet was most likely cut-off.
PacketCutOff,
/// An error occurred inside the packet handler.
InternalError(Box<ConversionError>),
}

/// Error when trying to register two separate handlers for the same packet.
#[derive(Debug, Clone)]
pub struct DuplicateHandlerError {
/// Header of the packet.
pub packet_header: PacketHeader,
}

/// Trait for monitoring the incoming and outgoing packets.
pub trait PacketCallback: Clone + Send + 'static {
/// Called by the [`PacketHandler`] when a packet is received.
fn incoming_packet<Packet>(&self, packet: &Packet)
where
Packet: IncomingPacket;

/// Called by the [`NetworkingSystem`](super::NetworkingSystem) when a
/// packet is sent.
fn outgoing_packet<Packet>(&self, packet: &Packet)
where
Packet: OutgoingPacket;

/// Called by the [`PacketHandler`] when a packet arrives that doesn't have
/// a handler registered.
fn unknown_packet(&self, packet: &UnknownPacket);

/// Called by the [`PacketHandler`] when a packet handler returned an error.
fn failed_packet(&self, header: PacketHeader, error: Box<ConversionError>);
}

#[derive(Debug, Default, Clone)]
pub struct NoPacketCallback;

impl PacketCallback for NoPacketCallback {
fn incoming_packet<Packet>(&self, _packet: &Packet)
where
Packet: IncomingPacket,
{
}

fn outgoing_packet<Packet>(&self, _packet: &Packet)
where
Packet: OutgoingPacket,
{
}

fn unknown_packet(&self, _packet: &UnknownPacket) {}

fn failed_packet(&self, _header: PacketHeader, _error: Box<ConversionError>) {}
}

pub type HandlerFunction<Output, Meta> = Box<dyn Fn(&mut ByteStream<Meta>) -> ConversionResult<Output>>;

/// A struct to help with reading packets from from a [`ByteStream`] and
/// converting them to some common event type.
///
/// It allows passing a packet callback to monitor incoming packets.
pub struct PacketHandler<Output, Meta, Callback>
where
Meta: 'static,
{
handlers: HashMap<PacketHeader, HandlerFunction<Output, Meta>>,
packet_callback: Callback,
}

impl<Output, Meta, Callback> Default for PacketHandler<Output, Meta, Callback>
where
Meta: 'static,
Callback: Default,
{
fn default() -> Self {
Self {
handlers: Default::default(),
packet_callback: Default::default(),
}
}
}

impl<Output, Meta, Callback> PacketHandler<Output, Meta, Callback>
where
Meta: Default + 'static,
Output: Default,
Callback: PacketCallback,
{
/// Create a new packet handler with a callback.
pub fn with_callback(packet_callback: Callback) -> Self {
Self {
handlers: Default::default(),
packet_callback,
}
}

/// Register a new packet handler.
pub fn register<Packet, Return>(&mut self, handler: impl Fn(Packet) -> Return + 'static) -> Result<(), DuplicateHandlerError>
where
Packet: IncomingPacket,
Return: Into<Output>,
{
let packet_callback = self.packet_callback.clone();
let old_handler = self.handlers.insert(
Packet::HEADER,
Box::new(move |byte_stream| {
let packet = Packet::payload_from_bytes(byte_stream)?;

packet_callback.incoming_packet(&packet);

Ok(handler(packet).into())
}),
);

match old_handler.is_some() {
true => Err(DuplicateHandlerError {
packet_header: Packet::HEADER,
}),
false => Ok(()),
}
}

/// Register a noop packet handler.
pub fn register_noop<Packet>(&mut self) -> Result<(), DuplicateHandlerError>
where
Packet: IncomingPacket,
{
let packet_callback = self.packet_callback.clone();
let old_handler = self.handlers.insert(
Packet::HEADER,
Box::new(move |byte_stream| {
let packet = Packet::payload_from_bytes(byte_stream)?;

packet_callback.incoming_packet(&packet);

Ok(Output::default())
}),
);

match old_handler.is_some() {
true => Err(DuplicateHandlerError {
packet_header: Packet::HEADER,
}),
false => Ok(()),
}
}

/// Take a single packet from the byte stream.
pub fn process_one(&mut self, byte_stream: &mut ByteStream<Meta>) -> HandlerResult<Output> {
let save_point = byte_stream.create_save_point();

let Ok(header) = PacketHeader::from_bytes(byte_stream) else {
// Packet is cut-off at the header.
byte_stream.restore_save_point(save_point);
return HandlerResult::PacketCutOff;
};

let Some(handler) = self.handlers.get(&header) else {
byte_stream.restore_save_point(save_point);

self.packet_callback.unknown_packet(&UnknownPacket {
bytes: byte_stream.remaining_bytes(),
});

return HandlerResult::UnhandledPacket;
};

match handler(byte_stream) {
Ok(output) => HandlerResult::Ok(output),
// Cut-off packet (probably).
Err(error) if error.is_byte_stream_too_short() => {
byte_stream.restore_save_point(save_point);
HandlerResult::PacketCutOff
}
Err(error) => {
byte_stream.restore_save_point(save_point);

self.packet_callback.failed_packet(header, error.clone());

HandlerResult::InternalError(error)
}
}
}
}
Loading

0 comments on commit 7234e36

Please sign in to comment.