use rama::{Context, Layer, Service};
use tansu_sans_io::Frame;
use tokio::sync::{mpsc, oneshot};
use tokio_util::sync::CancellationToken;
use tracing::debug;
use crate::Error;
#[derive(Clone, Debug, Default)]
pub struct ChannelFrameLayer {
cancellation: CancellationToken,
}
impl ChannelFrameLayer {
pub fn new(cancellation: CancellationToken) -> Self {
Self { cancellation }
}
}
impl<S> Layer<S> for ChannelFrameLayer {
type Service = ChannelFrameService<S>;
fn layer(&self, inner: S) -> Self::Service {
Self::Service {
inner,
cancellation: self.cancellation.clone(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct ChannelFrameService<S> {
inner: S,
cancellation: CancellationToken,
}
pub type FrameReceiver = mpsc::Receiver<(Frame, oneshot::Sender<Frame>)>;
impl<S, State> Service<State, FrameReceiver> for ChannelFrameService<S>
where
S: Service<State, Frame, Response = Frame>,
State: Clone + Send + Sync + 'static,
S::Error: From<Error>,
{
type Response = ();
type Error = S::Error;
async fn serve(
&self,
ctx: Context<State>,
mut req: FrameReceiver,
) -> Result<Self::Response, Self::Error> {
loop {
tokio::select! {
Some((frame, tx)) = req.recv() => {
debug!(?frame, ?tx);
self.inner
.serve(ctx.clone(), frame)
.await
.and_then(|response| {
tx.send(response)
.map_err(|unsent| Error::UnableToSend(Box::new(unsent)))
.map_err(Into::into)
})?
}
cancelled = self.cancellation.cancelled() => {
debug!(?cancelled);
break;
}
}
}
Ok(())
}
}
pub type FrameSender = mpsc::Sender<(Frame, oneshot::Sender<Frame>)>;
#[derive(Clone, Debug)]
pub struct FrameChannelService {
tx: FrameSender,
}
impl FrameChannelService {
pub fn new(tx: FrameSender) -> Self {
Self { tx }
}
}
impl<State> Service<State, Frame> for FrameChannelService
where
State: Send + Sync + 'static,
{
type Response = Frame;
type Error = Error;
async fn serve(&self, _ctx: Context<State>, req: Frame) -> Result<Self::Response, Self::Error> {
let (resp_tx, resp_rx) = oneshot::channel();
self.tx
.send((req, resp_tx))
.await
.map_err(|send_error| Error::UnableToSend(Box::new(send_error.0.0)))?;
resp_rx.await.map_err(Error::OneshotRecv)
}
}
pub fn bounded_channel(buffer: usize) -> (FrameSender, FrameReceiver) {
mpsc::channel::<(Frame, oneshot::Sender<Frame>)>(buffer)
}