use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use futures::Stream;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use tokio_tungstenite::tungstenite::Message;
use url::Url;
use crate::socket_loop::{
TerminalError, TxChannelPayload, poll_recv_raw, recv_raw, send_close, send_confirmed,
send_unconfirmed,
};
use crate::{Codec, ConnectOptions, ConnectionHandler, Error, NoopHandler, Socketeer};
pub struct SocketeerTx<C: Codec> {
pub(crate) sender: mpsc::Sender<TxChannelPayload>,
pub(crate) codec: C,
pub(crate) terminal_error: TerminalError,
}
impl<C: Codec + Clone> Clone for SocketeerTx<C> {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
codec: self.codec.clone(),
terminal_error: Arc::clone(&self.terminal_error),
}
}
}
impl<C: Codec> std::fmt::Debug for SocketeerTx<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SocketeerTx").finish_non_exhaustive()
}
}
impl<C: Codec> SocketeerTx<C> {
pub async fn send(&self, message: C::Tx) -> Result<(), Error> {
let encoded = self.codec.encode(&message)?;
self.send_raw(encoded).await
}
pub async fn send_raw(&self, message: Message) -> Result<(), Error> {
send_confirmed(&self.sender, &self.terminal_error, message).await
}
pub async fn send_unconfirmed(&self, message: C::Tx) -> Result<(), Error> {
let encoded = self.codec.encode(&message)?;
self.send_raw_unconfirmed(encoded).await
}
pub async fn send_raw_unconfirmed(&self, message: Message) -> Result<(), Error> {
send_unconfirmed(&self.sender, &self.terminal_error, message).await
}
pub async fn close(&self) -> Result<(), Error> {
send_close(&self.sender).await
}
}
pub struct SocketeerRx<C: Codec, Handler = NoopHandler, const CHANNEL_SIZE: usize = 256>
where
Handler: ConnectionHandler<C>,
{
pub(crate) receiver: mpsc::Receiver<Message>,
pub(crate) codec: C,
pub(crate) terminal_error: TerminalError,
pub(crate) socket_handle: JoinHandle<()>,
pub(crate) url: Url,
pub(crate) options: ConnectOptions,
pub(crate) handler: Handler,
}
impl<C: Codec, Handler, const CHANNEL_SIZE: usize> std::fmt::Debug
for SocketeerRx<C, Handler, CHANNEL_SIZE>
where
Handler: ConnectionHandler<C>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SocketeerRx")
.field("url", &self.url)
.finish_non_exhaustive()
}
}
impl<C: Codec, Handler, const CHANNEL_SIZE: usize> SocketeerRx<C, Handler, CHANNEL_SIZE>
where
Handler: ConnectionHandler<C>,
{
pub async fn next_message(&mut self) -> Result<C::Rx, Error> {
let message = recv_raw(&mut self.receiver, &self.terminal_error).await?;
self.codec.decode(&message)
}
pub async fn next_raw_message(&mut self) -> Result<Message, Error> {
recv_raw(&mut self.receiver, &self.terminal_error).await
}
#[allow(clippy::result_large_err)]
pub fn reunite(
self,
tx: SocketeerTx<C>,
) -> Result<Socketeer<C, Handler, CHANNEL_SIZE>, ReuniteError<C, Handler, CHANNEL_SIZE>> {
if Arc::ptr_eq(&self.terminal_error, &tx.terminal_error) {
Ok(Socketeer::from_parts(
self.url,
self.options,
self.codec,
self.handler,
self.receiver,
tx.sender,
self.socket_handle,
self.terminal_error,
))
} else {
Err(ReuniteError { tx, rx: self })
}
}
}
pub struct ReuniteError<C: Codec, Handler = NoopHandler, const CHANNEL_SIZE: usize = 256>
where
Handler: ConnectionHandler<C>,
{
pub tx: SocketeerTx<C>,
pub rx: SocketeerRx<C, Handler, CHANNEL_SIZE>,
}
impl<C: Codec, Handler, const CHANNEL_SIZE: usize> std::fmt::Debug
for ReuniteError<C, Handler, CHANNEL_SIZE>
where
Handler: ConnectionHandler<C>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReuniteError").finish_non_exhaustive()
}
}
impl<C: Codec, Handler, const CHANNEL_SIZE: usize> std::fmt::Display
for ReuniteError<C, Handler, CHANNEL_SIZE>
where
Handler: ConnectionHandler<C>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("tried to reunite a SocketeerTx and SocketeerRx from different connections")
}
}
impl<C: Codec, Handler, const CHANNEL_SIZE: usize> std::error::Error
for ReuniteError<C, Handler, CHANNEL_SIZE>
where
Handler: ConnectionHandler<C>,
{
}
impl<C: Codec + Unpin, Handler, const CHANNEL_SIZE: usize> Stream
for SocketeerRx<C, Handler, CHANNEL_SIZE>
where
Handler: ConnectionHandler<C> + Unpin,
{
type Item = Result<C::Rx, Error>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
poll_recv_raw(&mut this.receiver, &this.terminal_error, cx)
.map(|frame| frame.map(|result| result.and_then(|message| this.codec.decode(&message))))
}
}