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?),
}
}
}