use std::sync::Arc;
use crate::{
codec::EofError,
push::{FrameLike, PushHandle},
};
#[derive(Default)]
pub struct ConnectionContext;
pub trait WireframeProtocol: Send + Sync + 'static {
type Frame: FrameLike;
type ProtocolError;
fn on_connection_setup(&self, _handle: PushHandle<Self::Frame>, _ctx: &mut ConnectionContext) {}
fn before_send(&self, _frame: &mut Self::Frame, _ctx: &mut ConnectionContext) {}
fn on_command_end(&self, _ctx: &mut ConnectionContext) {}
fn handle_error(&self, _error: Self::ProtocolError, _ctx: &mut ConnectionContext) {}
fn stream_end_frame(&self, _ctx: &mut ConnectionContext) -> Option<Self::Frame> { None }
fn on_eof(&self, _error: &EofError, _partial_data: &[u8], _ctx: &mut ConnectionContext) {}
}
type BeforeSendHook<F> = Box<dyn FnMut(&mut F, &mut ConnectionContext) + Send + 'static>;
type OnConnectionSetupHook<F> =
Box<dyn FnOnce(PushHandle<F>, &mut ConnectionContext) + Send + 'static>;
type OnCommandEndHook = Box<dyn FnMut(&mut ConnectionContext) + Send + 'static>;
type HandleErrorHook<E> = Box<dyn FnMut(E, &mut ConnectionContext) + Send + 'static>;
type StreamEndHook<F> = Box<dyn FnMut(&mut ConnectionContext) -> Option<F> + Send + 'static>;
type OnEofHook = Box<dyn FnMut(&EofError, &[u8], &mut ConnectionContext) + Send + 'static>;
pub struct ProtocolHooks<F, E> {
pub on_connection_setup: Option<OnConnectionSetupHook<F>>,
pub before_send: Option<BeforeSendHook<F>>,
pub on_command_end: Option<OnCommandEndHook>,
pub handle_error: Option<HandleErrorHook<E>>,
pub stream_end: Option<StreamEndHook<F>>,
pub on_eof: Option<OnEofHook>,
}
impl<F, E> Default for ProtocolHooks<F, E> {
fn default() -> Self {
Self {
on_connection_setup: None,
before_send: None,
on_command_end: None,
handle_error: None,
stream_end: None,
on_eof: None,
}
}
}
impl<F, E> ProtocolHooks<F, E> {
pub fn on_connection_setup(&mut self, handle: PushHandle<F>, ctx: &mut ConnectionContext) {
if let Some(hook) = self.on_connection_setup.take() {
hook(handle, ctx);
}
}
pub fn before_send(&mut self, frame: &mut F, ctx: &mut ConnectionContext) {
if let Some(hook) = &mut self.before_send {
hook(frame, ctx);
}
}
pub fn on_command_end(&mut self, ctx: &mut ConnectionContext) {
if let Some(hook) = &mut self.on_command_end {
hook(ctx);
}
}
pub fn handle_error(&mut self, error: E, ctx: &mut ConnectionContext) {
if let Some(hook) = &mut self.handle_error {
hook(error, ctx);
}
}
pub fn stream_end_frame(&mut self, ctx: &mut ConnectionContext) -> Option<F> {
self.stream_end.as_mut().and_then(|hook| hook(ctx))
}
pub fn on_eof(&mut self, error: &EofError, partial_data: &[u8], ctx: &mut ConnectionContext) {
if let Some(hook) = &mut self.on_eof {
hook(error, partial_data, ctx);
}
}
pub fn from_protocol<P>(protocol: &Arc<P>) -> Self
where
P: WireframeProtocol<Frame = F, ProtocolError = E> + ?Sized,
{
let protocol_before = Arc::clone(protocol);
let before = Box::new(move |frame: &mut F, ctx: &mut ConnectionContext| {
protocol_before.before_send(frame, ctx);
}) as BeforeSendHook<F>;
let protocol_end = Arc::clone(protocol);
let end = Box::new(move |ctx: &mut ConnectionContext| {
protocol_end.on_command_end(ctx);
}) as OnCommandEndHook;
let protocol_setup = Arc::clone(protocol);
let setup = Box::new(move |handle: PushHandle<F>, ctx: &mut ConnectionContext| {
protocol_setup.on_connection_setup(handle, ctx);
}) as OnConnectionSetupHook<F>;
let protocol_error = Arc::clone(protocol);
let err = Box::new(move |e: P::ProtocolError, ctx: &mut ConnectionContext| {
protocol_error.handle_error(e, ctx);
}) as HandleErrorHook<P::ProtocolError>;
let protocol_stream_end = Arc::clone(protocol);
let stream_end =
Box::new(move |ctx: &mut ConnectionContext| protocol_stream_end.stream_end_frame(ctx))
as StreamEndHook<F>;
let protocol_eof = Arc::clone(protocol);
let on_eof = Box::new(
move |error: &EofError, partial_data: &[u8], ctx: &mut ConnectionContext| {
protocol_eof.on_eof(error, partial_data, ctx);
},
) as OnEofHook;
Self {
on_connection_setup: Some(setup),
before_send: Some(before),
on_command_end: Some(end),
handle_error: Some(err),
stream_end: Some(stream_end),
on_eof: Some(on_eof),
}
}
}