use std::marker::PhantomData;
use std::sync::Arc;
use bytes::Bytes;
use foundation_errstacks::ErrorTrace;
use foundation_netio::shared::http::SimpleHeaders;
use crate::shared::codec::CodecFor;
use crate::shared::error::{ConnectError, ConnectResult};
use super::conn::{ConnReceiver, ConnSender};
pub trait FrameMiddleware: Send + Sync + 'static {
fn on_send(&self, frame: Bytes, headers: &SimpleHeaders) -> ConnectResult<Bytes> {
let _ = headers;
Ok(frame)
}
fn on_receive(&self, frame: Bytes, headers: &SimpleHeaders) -> ConnectResult<Bytes> {
let _ = headers;
Ok(frame)
}
}
pub trait TypedMiddleware<T>: Send + Sync + 'static {
fn on_send(&self, msg: &T) -> ConnectResult<()> {
let _ = msg;
Ok(())
}
fn on_receive(&self, msg: &mut T) -> ConnectResult<()> {
let _ = msg;
Ok(())
}
}
pub struct MessageSink<T> {
sender: Box<dyn ConnSender>,
codec: Arc<dyn CodecFor<T>>,
typed_mw: Vec<Arc<dyn TypedMiddleware<T>>>,
frame_mw: Vec<Arc<dyn FrameMiddleware>>,
_marker: PhantomData<fn(T)>,
}
impl<T: Send + 'static> MessageSink<T> {
#[must_use]
pub fn new(sender: Box<dyn ConnSender>, codec: Arc<dyn CodecFor<T>>) -> Self {
Self {
sender,
codec,
typed_mw: Vec::new(),
frame_mw: Vec::new(),
_marker: PhantomData,
}
}
#[must_use]
pub fn with_typed_middleware(mut self, mw: Arc<dyn TypedMiddleware<T>>) -> Self {
self.typed_mw.push(mw);
self
}
#[must_use]
pub fn with_frame_middleware(mut self, mw: Arc<dyn FrameMiddleware>) -> Self {
self.frame_mw.push(mw);
self
}
pub async fn set_headers(&mut self, headers: SimpleHeaders) -> ConnectResult<()> {
self.sender.send_headers(headers).await
}
pub async fn send(&mut self, msg: T) -> ConnectResult<()> {
for mw in &self.typed_mw {
mw.on_send(&msg)?;
}
let mut frame = self.codec.marshal(&msg)?;
let empty = SimpleHeaders::new();
for mw in &self.frame_mw {
frame = mw.on_send(frame, &empty)?;
}
self.sender.send(frame).await
}
pub async fn close(self, trailers: SimpleHeaders) -> ConnectResult<()> {
self.sender.close(None, trailers).await
}
pub async fn close_with_error(
self,
error: ErrorTrace<ConnectError>,
trailers: SimpleHeaders,
) -> ConnectResult<()> {
self.sender.close(Some(error), trailers).await
}
}
pub struct MessageSource<T> {
receiver: Box<dyn ConnReceiver>,
codec: Arc<dyn CodecFor<T>>,
headers: SimpleHeaders,
typed_mw: Vec<Arc<dyn TypedMiddleware<T>>>,
frame_mw: Vec<Arc<dyn FrameMiddleware>>,
_marker: PhantomData<fn() -> T>,
}
impl<T: Send + 'static> MessageSource<T> {
#[must_use]
pub fn new(
receiver: Box<dyn ConnReceiver>,
codec: Arc<dyn CodecFor<T>>,
headers: SimpleHeaders,
) -> Self {
Self {
receiver,
codec,
headers,
typed_mw: Vec::new(),
frame_mw: Vec::new(),
_marker: PhantomData,
}
}
#[must_use]
pub fn with_typed_middleware(mut self, mw: Arc<dyn TypedMiddleware<T>>) -> Self {
self.typed_mw.push(mw);
self
}
#[must_use]
pub fn with_frame_middleware(mut self, mw: Arc<dyn FrameMiddleware>) -> Self {
self.frame_mw.push(mw);
self
}
pub async fn receive(&mut self) -> ConnectResult<Option<T>> {
match self.receiver.receive().await? {
Some(mut frame) => {
for mw in &self.frame_mw {
frame = mw.on_receive(frame, &self.headers)?;
}
let mut msg = self.codec.unmarshal(frame)?;
for mw in &self.typed_mw {
mw.on_receive(&mut msg)?;
}
Ok(Some(msg))
}
None => Ok(None),
}
}
#[must_use]
pub fn headers(&self) -> &SimpleHeaders {
&self.headers
}
#[must_use]
pub fn trailers(&self) -> &SimpleHeaders {
self.receiver.trailers()
}
}