unb-runtime 2.0.0

unb session runtime: transport codec, session/writer engine, Wire handle, cancellation
Documentation
use unb_core::Envelope;

use crate::BodyStream;
use bytes::Bytes;
use futures_util::stream::{SplitSink, SplitStream};
use futures_util::{SinkExt, StreamExt};
use tokio::sync::mpsc;
use unb_transport::BoxTransport;

use crate::error::WsError;

pub type SessionStreams = Option<std::sync::Arc<unb_transport::ConnectionStreams>>;

pub enum Pipe {
    Local {
        rx: mpsc::Receiver<Envelope>,
        tx: mpsc::Sender<Envelope>,
        initiator: bool,
    },
    Piped {
        pipe: BoxTransport,
        initiator: bool,
    },
    PipedWithStreams {
        pipe: BoxTransport,
        initiator: bool,
        streams: SessionStreams,
    },
}

impl Pipe {
    pub fn piped_with_streams(
        pipe: BoxTransport,
        initiator: bool,
        streams: std::sync::Arc<unb_transport::ConnectionStreams>,
    ) -> Pipe {
        Pipe::PipedWithStreams {
            pipe,
            initiator,
            streams: Some(streams),
        }
    }

    pub(crate) fn initiator(&self) -> bool {
        match self {
            Pipe::Local { initiator, .. }
            | Pipe::Piped { initiator, .. }
            | Pipe::PipedWithStreams { initiator, .. } => *initiator,
        }
    }

    pub(crate) fn streams(&self) -> SessionStreams {
        match self {
            Pipe::Local { .. } | Pipe::Piped { .. } => None,
            Pipe::PipedWithStreams { streams, .. } => streams.clone(),
        }
    }

    pub(crate) fn split(self) -> (PipeReader, PipeWriter) {
        match self {
            Pipe::Local { rx, tx, .. } => (PipeReader::Local(rx), PipeWriter::Local(tx)),
            Pipe::Piped { pipe, .. } | Pipe::PipedWithStreams { pipe, .. } => {
                let (sink, stream) = pipe.split();
                (PipeReader::Piped(stream), PipeWriter::Piped(sink))
            }
        }
    }
}

pub(crate) enum PipeReader {
    Local(mpsc::Receiver<Envelope>),
    Piped(SplitStream<BoxTransport>),
}

pub(crate) enum PipeWriter {
    Local(mpsc::Sender<Envelope>),
    Piped(SplitSink<BoxTransport, Bytes>),
}

impl PipeReader {
    pub(crate) async fn recv(&mut self) -> Result<Option<(Envelope, Option<BodyStream>)>, WsError> {
        match self {
            PipeReader::Local(rx) => Ok(rx.recv().await.map(|envelope| (envelope, None))),
            PipeReader::Piped(stream) => match stream.next().await {
                None => Ok(None),
                Some(Ok(frame)) => Ok(Some((Envelope::decode(frame)?, None))),
                Some(Err(error)) => Err(error.into()),
            },
        }
    }
}

impl PipeWriter {
    pub(crate) async fn feed(&mut self, envelope: Envelope) -> Result<(), WsError> {
        match self {
            PipeWriter::Local(tx) => tx.send(envelope).await.map_err(|_| WsError::Gone),
            PipeWriter::Piped(sink) => Ok(sink.feed(envelope.encode()).await?),
        }
    }

    pub(crate) async fn flush(&mut self) -> Result<(), WsError> {
        match self {
            PipeWriter::Local(_) => Ok(()),
            PipeWriter::Piped(sink) => Ok(sink.flush().await?),
        }
    }

    pub(crate) async fn close(&mut self) -> Result<(), WsError> {
        match self {
            PipeWriter::Local(_) => Ok(()),
            PipeWriter::Piped(sink) => Ok(sink.close().await?),
        }
    }
}