From bb41e396aca01fee9f81785681fac0a79d0fd9d8 Mon Sep 17 00:00:00 2001 From: zirkonya Date: Thu, 27 Aug 2026 09:45:12 +0200 Subject: split event and enhance context --- src/codec.rs | 4 +-- src/codec/decode.rs | 41 ++++++++++----------- src/codec/encode.rs | 33 ++++++++--------- src/context.rs | 8 +++++ src/event.rs | 88 +++++++++++++++++----------------------------- src/event/connection.rs | 13 +++++++ src/event/disconnect.rs | 25 +++++++++++++ src/event/handler.rs | 67 +++++++++++++++++++++++++++++++++++ src/event/listener.rs | 47 +++++++++++++++++++++++++ src/event/received.rs | 7 ++++ src/event/sent.rs | 7 ++++ src/types/prefix/count.rs | 19 +++++----- src/types/prefix/length.rs | 19 +++++----- 13 files changed, 267 insertions(+), 111 deletions(-) create mode 100644 src/event/connection.rs create mode 100644 src/event/disconnect.rs create mode 100644 src/event/received.rs create mode 100644 src/event/sent.rs diff --git a/src/codec.rs b/src/codec.rs index 778001f..6680699 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -4,5 +4,5 @@ pub mod decode; pub mod encode; pub mod error; -pub trait Codec: Encode + Decode {} -impl Codec for T where T: Encode + Decode {} +pub trait Codec: Encode + Decode {} +impl Codec for T where T: Encode + Decode {} diff --git a/src/codec/decode.rs b/src/codec/decode.rs index fa4ae95..39253a2 100644 --- a/src/codec/decode.rs +++ b/src/codec/decode.rs @@ -1,13 +1,14 @@ //! Decoding: reading protocol values from a byte stream. +use crate::context::Context; use std::{io::Read, sync::Arc}; use crate::{DEFAULT_BUFFER_LEN, codec::error::Result}; macro_rules! impl_decode { ($type: ty) => { - impl Decode for $type { + impl Decode for $type { // decode number using big endian - fn decode(reader: &mut dyn Read, _: &mut Ctx) -> Result + fn decode(reader: &mut dyn Read, _: &Context) -> Result where Self: Sized, { @@ -21,14 +22,14 @@ macro_rules! impl_decode { } /// Read a value from a byte stream -pub trait Decode { - fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> Result +pub trait Decode { + fn decode(reader: &mut dyn Read, ctx: &Context) -> Result where Self: Sized; } -impl Decode for bool { - fn decode(reader: &mut dyn Read, _: &mut Ctx) -> Result +impl Decode for bool { + fn decode(reader: &mut dyn Read, _: &Context) -> Result where Self: Sized, { @@ -38,8 +39,8 @@ impl Decode for bool { } } -impl> Decode for Option { - fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> Result +impl> Decode for Option { + fn decode(reader: &mut dyn Read, ctx: &Context) -> Result where Self: Sized, { @@ -52,8 +53,8 @@ impl> Decode for Option { } } -impl> Decode for Vec { - fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> Result +impl> Decode for Vec { + fn decode(reader: &mut dyn Read, ctx: &Context) -> Result where Self: Sized, { @@ -66,8 +67,8 @@ impl> Decode for Vec { } } -impl Decode for String { - fn decode(reader: &mut dyn Read, _: &mut Ctx) -> Result +impl Decode for String { + fn decode(reader: &mut dyn Read, _: &Context) -> Result where Self: Sized, { @@ -77,16 +78,16 @@ impl Decode for String { } } -impl Decode for Arc<[u8]> { - fn decode(reader: &mut dyn Read, _: &mut Ctx) -> Result { +impl Decode for Arc<[u8]> { + fn decode(reader: &mut dyn Read, _: &Context) -> Result { let mut buf = Vec::with_capacity(DEFAULT_BUFFER_LEN); reader.read_to_end(&mut buf)?; Ok(Arc::<[u8]>::from(buf.into_boxed_slice())) } } -impl Decode for [u8; S] { - fn decode(reader: &mut dyn Read, _: &mut Ctx) -> Result +impl Decode for [u8; S] { + fn decode(reader: &mut dyn Read, _: &Context) -> Result where Self: Sized, { @@ -110,8 +111,8 @@ impl_decode!(i64); impl_decode!(i128); impl_decode!(isize); -impl Decode for f64 { - fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> Result +impl Decode for f64 { + fn decode(reader: &mut dyn Read, ctx: &Context) -> Result where Self: Sized, { @@ -121,8 +122,8 @@ impl Decode for f64 { } } -impl Decode for f32 { - fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> Result +impl Decode for f32 { + fn decode(reader: &mut dyn Read, ctx: &Context) -> Result where Self: Sized, { diff --git a/src/codec/encode.rs b/src/codec/encode.rs index c8d1c7b..b9ac961 100644 --- a/src/codec/encode.rs +++ b/src/codec/encode.rs @@ -1,12 +1,13 @@ //! Encoding: writing protocol values into a byte stream. use crate::codec::error::Error; +use crate::context::Context; use std::{io::Write, sync::Arc}; macro_rules! impl_encode { ($t: ty) => { - impl Encode for $t { + impl Encode for $t { /// write number using big endian - fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let size = buffer.write(&self.to_be_bytes())?; Ok(size) } @@ -15,20 +16,20 @@ macro_rules! impl_encode { } /// Write a value into a byte stream -pub trait Encode { - fn encode(&self, buffer: &mut dyn Write, ctx: &mut Ctx) -> Result; +pub trait Encode { + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result; } -impl Encode for bool { - fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { +impl Encode for bool { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let size = buffer.write(&[*self as u8])?; Ok(size) } } -impl> Encode for Option { +impl> Encode for Option { /// Encode `T` if Some(T) or do nothing if None - fn encode(&self, buffer: &mut dyn Write, ctx: &mut Ctx) -> Result { + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { match self { Some(val) => { let size = val.encode(buffer, ctx)?; @@ -39,11 +40,11 @@ impl> Encode for Option { } } -impl> Encode for Vec { +impl> Encode for Vec { /// Encode each element of vector /// use `CountPrefix` to prefix the vector with number of elements /// use `LenPrefix` to prefix the vector with encoded byte size - fn encode(&self, buffer: &mut dyn Write, ctx: &mut Ctx) -> Result { + fn encode(&self, buffer: &mut dyn Write, ctx: &Context) -> Result { let mut size = 0; for item in self { size += item.encode(buffer, ctx)?; @@ -52,30 +53,30 @@ impl> Encode for Vec { } } -impl Encode for String { +impl Encode for String { /// Encode the string using utf8 /// use `CountPrefix` to prefix the string with char length /// use `LenPrefix` to prefix the string with utf8 bytes length - fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let utf8 = self.as_bytes(); buffer.write_all(utf8)?; Ok(utf8.len()) } } -impl Encode for Arc<[u8]> { +impl Encode for Arc<[u8]> { /// write raw slice into the buffer /// use `LenPrefix` to prefix with byte length - fn encode(&self, buffer: &mut dyn Write, _: &mut Ctx) -> Result { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let len = buffer.write(self)?; Ok(len) } } -impl Encode for [u8; S] { +impl Encode for [u8; S] { /// write raw slice into the buffer /// use `LenPrefix` to prefix with byte length - fn encode(&self, buffer: &mut dyn Write, _ctx: &mut Ctx) -> Result { + fn encode(&self, buffer: &mut dyn Write, _: &Context) -> Result { let len = buffer.write(self)?; Ok(len) } diff --git a/src/context.rs b/src/context.rs index 8b13789..bcc0b6d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1 +1,9 @@ +pub struct Context { + pub data: Data, +} +impl Context { + pub fn new(data: Data) -> Self { + Self { data } + } +} \ No newline at end of file diff --git a/src/event.rs b/src/event.rs index bbba586..95d5a12 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,94 +1,72 @@ -use std::{io, net::SocketAddr, time::Instant}; +use std::{cell::Cell, time::Instant}; -use getset::{Getters, Setters}; +use getset::Getters; + +use crate::event::{ + connection::ConnectionEvent, disconnect::DisconnectEvent, received::PacketReceivedEvent, + sent::PacketSentEvent, +}; pub mod handler; pub mod listener; -pub enum EventKind +pub mod connection; +pub mod disconnect; +pub mod received; +pub mod sent; + +pub enum EventKind where Uid: PartialEq, { - Connection(ConnectionEvent), + Connection(ConnectionEvent), PacketReceived(PacketReceivedEvent), PacketSent(PacketSentEvent), Disconnect(DisconnectEvent), } -// TODO : identification -// TODO : reason type #[derive(Getters)] -pub struct ConnectionEvent +pub struct Event where Uid: PartialEq, { #[getset(get = "pub")] - peer_addr: SocketAddr, - #[getset(get = "pub")] - local_addr: SocketAddr, - #[getset(get = "pub")] - connection_id: Uid, -} -#[derive(Getters)] -pub struct PacketReceivedEvent { - #[getset(get = "pub")] - packet: Packet, -} -#[derive(Getters)] -pub struct PacketSentEvent { - #[getset(get = "pub")] - packet: Packet, -} - -// TODO : better error type for protocol violation -pub type ProtocolViolation = String; - -pub enum DisconnectReason { - Normal, - Error(io::Error), - ProtocolError(ProtocolViolation), - Timeout, - ServerShutdown, -} + instant: Instant, -#[derive(Getters)] -pub struct DisconnectEvent -where - Uid: PartialEq, -{ #[getset(get = "pub")] connection_id: Uid, + canceled: Cell, #[getset(get = "pub")] - reason: DisconnectReason, + kind: EventKind, } -#[derive(Getters, Setters)] -pub struct Event +impl Event where Uid: PartialEq, { - #[getset(get = "pub")] - instant: Instant, - #[getset(get = "pub", set = "pub")] - canceled: bool, - #[getset(get = "pub")] - kind: EventKind, -} - -impl Event { - pub fn new(kind: EventKind) -> Self { + pub fn new(connection_id: Uid, kind: EventKind) -> Self { Self { + connection_id, instant: Instant::now(), - canceled: false, + canceled: Cell::new(true), kind, } } - pub fn differed(when: Instant, kind: EventKind) -> Self { + pub fn differed(connection_id: Uid, when: Instant, kind: EventKind) -> Self { Self { + connection_id, instant: when, - canceled: false, + canceled: Cell::new(true), kind, } } + + pub fn canceled(&self) -> bool { + self.canceled.get() + } + + pub fn cancel(&self) { + self.canceled.set(true); + } } diff --git a/src/event/connection.rs b/src/event/connection.rs new file mode 100644 index 0000000..99813fd --- /dev/null +++ b/src/event/connection.rs @@ -0,0 +1,13 @@ +use std::net::SocketAddr; + +use getset::Getters; + +// TODO : identification +// TODO : reason type +#[derive(Getters)] +pub struct ConnectionEvent { + #[getset(get = "pub")] + peer_addr: SocketAddr, + #[getset(get = "pub")] + local_addr: SocketAddr, +} diff --git a/src/event/disconnect.rs b/src/event/disconnect.rs new file mode 100644 index 0000000..6511027 --- /dev/null +++ b/src/event/disconnect.rs @@ -0,0 +1,25 @@ +use std::io; + +use getset::Getters; + +// TODO : better error type for protocol violation +pub type ProtocolViolation = String; + +pub enum DisconnectReason { + Normal, + Error(io::Error), + ProtocolError(ProtocolViolation), + Timeout, + ServerShutdown, +} + +#[derive(Getters)] +pub struct DisconnectEvent +where + Uid: PartialEq, +{ + #[getset(get = "pub")] + connection_id: Uid, + #[getset(get = "pub")] + reason: DisconnectReason, +} diff --git a/src/event/handler.rs b/src/event/handler.rs index 7d8b5b5..3f9827e 100644 --- a/src/event/handler.rs +++ b/src/event/handler.rs @@ -1,2 +1,69 @@ // TODO : dispatch event through all listener // TODO : maybe compile listener into one ? + +use crate::{ + context::Context, + event::{ + Event, + listener::{Listener, ListenerResult}, + }, +}; + +pub struct EventHandler +where + Uid: PartialEq, +{ + listeners: Vec>>, +} + +impl EventHandler +where + Uid: PartialEq + Clone, +{ + pub fn register + 'static>(&mut self, listener: L) { + self.listeners.push(Box::new(listener)); + } + + pub fn dispatch(&self, event: &Event, ctx: &Context) { + match event.kind() { + super::EventKind::Connection(connection_event) => { + for listener in &self.listeners { + if matches!( + listener.on_connection(connection_event, ctx), + ListenerResult::Cancel | ListenerResult::Disconnect + ) { + event.cancel(); + break; + } + } + } + super::EventKind::PacketReceived(packet_received_event) => { + for listener in &self.listeners { + if matches!( + listener.on_packet_received(packet_received_event, ctx), + ListenerResult::Cancel | ListenerResult::Disconnect + ) { + event.cancel(); + break; + } + } + } + super::EventKind::PacketSent(packet_sent_event) => { + for listener in &self.listeners { + if matches!( + listener.on_packet_sent(packet_sent_event, ctx), + ListenerResult::Cancel | ListenerResult::Disconnect + ) { + event.cancel(); + break; + } + } + } + super::EventKind::Disconnect(disconnect_event) => { + for listener in &self.listeners { + listener.on_disconnect(disconnect_event, ctx); + } + } + } + } +} diff --git a/src/event/listener.rs b/src/event/listener.rs index 178dda8..81f4b57 100644 --- a/src/event/listener.rs +++ b/src/event/listener.rs @@ -1 +1,48 @@ +use crate::{ + context::Context, + event::{ConnectionEvent, DisconnectEvent, PacketReceivedEvent, PacketSentEvent}, +}; + // TODO : Listener ; interface to perform action when event occured +// TODO async trait for async runtime + +pub enum ListenerResult { + Continue, + /// Cancel the event + /// `ConectionEvent` => same as `ListenerResult::Disconnect` + /// `PacketReceived` => the received packet is drop + /// `PacketSent` => the packet isn't send + /// `Disconnect` => non sense + Cancel, + /// Force disconnect the connection + Disconnect, +} + +pub trait Listener +where + Uid: PartialEq, +{ + fn on_connection(&self, event: &ConnectionEvent, ctx: &Context) -> ListenerResult { + let _ = (event, ctx); + ListenerResult::Continue + } + fn on_packet_received( + &self, + event: &PacketReceivedEvent, + ctx: &Context, + ) -> ListenerResult { + let _ = (event, ctx); + ListenerResult::Continue + } + fn on_packet_sent( + &self, + event: &PacketSentEvent, + ctx: &Context, + ) -> ListenerResult { + let _ = (event, ctx); + ListenerResult::Continue + } + fn on_disconnect(&self, event: &DisconnectEvent, ctx: &Context) { + let _ = (event, ctx); + } +} diff --git a/src/event/received.rs b/src/event/received.rs new file mode 100644 index 0000000..0ef6d0e --- /dev/null +++ b/src/event/received.rs @@ -0,0 +1,7 @@ +use getset::Getters; + +#[derive(Getters)] +pub struct PacketReceivedEvent { + #[getset(get = "pub")] + packet: Packet, +} diff --git a/src/event/sent.rs b/src/event/sent.rs new file mode 100644 index 0000000..5278842 --- /dev/null +++ b/src/event/sent.rs @@ -0,0 +1,7 @@ +use getset::Getters; + +#[derive(Getters)] +pub struct PacketSentEvent { + #[getset(get = "pub")] + packet: Packet, +} diff --git a/src/types/prefix/count.rs b/src/types/prefix/count.rs index 0896167..e00c18c 100644 --- a/src/types/prefix/count.rs +++ b/src/types/prefix/count.rs @@ -4,6 +4,7 @@ use getset::Getters; use crate::{ codec::{Codec, decode::Decode, encode::Encode}, + context::Context, types::size::Size, }; @@ -59,16 +60,16 @@ where } } -impl Encode for CountPrefix +impl Encode for CountPrefix where - I: Codec, - L: Codec + Size + TryFrom, + I: Codec, + L: Codec + Size + TryFrom, D: IntoIterator + Clone, { fn encode( &self, buffer: &mut dyn std::io::prelude::Write, - ctx: &mut Ctx, + ctx: &Context, ) -> Result where Self: Sized, @@ -85,13 +86,13 @@ where } } -impl Decode for CountPrefix +impl Decode for CountPrefix where - I: Codec, - L: Codec + Size, + I: Codec, + L: Codec + Size, D: IntoIterator + FromIterator, { - fn decode(reader: &mut dyn Read, ctx: &mut Ctx) -> crate::codec::error::Result + fn decode(reader: &mut dyn Read, ctx: &Context) -> crate::codec::error::Result where Self: Sized, { @@ -106,4 +107,4 @@ where _len: PhantomData, }) } -} +} \ No newline at end of file diff --git a/src/types/prefix/length.rs b/src/types/prefix/length.rs index 3bb150a..750aa23 100644 --- a/src/types/prefix/length.rs +++ b/src/types/prefix/length.rs @@ -5,6 +5,7 @@ use getset::Getters; use crate::{ DEFAULT_BUFFER_LEN, codec::{self, Codec, decode::Decode, encode::Encode}, + context::Context, types::size::Size, }; @@ -48,12 +49,12 @@ impl AsMut for LenPrefixed { } } -impl Encode for LenPrefixed +impl Encode for LenPrefixed where - L: Codec + Size, - D: Codec, + L: Codec + Size, + D: Codec, { - fn encode(&self, writer: &mut dyn Write, ctx: &mut Ctx) -> Result { + fn encode(&self, writer: &mut dyn Write, ctx: &Context) -> Result { let mut buf = Vec::with_capacity(DEFAULT_BUFFER_LEN); self.data.encode(&mut buf, ctx)?; let len = L::from_size(buf.len()); @@ -63,14 +64,14 @@ where } } -impl Decode for LenPrefixed +impl Decode for LenPrefixed where - L: Codec + Size, - D: Codec, + L: Codec + Size, + D: Codec, { fn decode( reader: &mut dyn std::io::prelude::Read, - ctx: &mut Ctx, + ctx: &Context, ) -> crate::codec::error::Result where Self: Sized, @@ -84,4 +85,4 @@ where _len: PhantomData, }) } -} +} \ No newline at end of file -- cgit v1.2.3