mutiny-core 0.4.39

The core SDK for the mutiny node
Documentation
use async_trait::async_trait;
use futures::{SinkExt, StreamExt};

#[cfg(target_arch = "wasm32")]
use std::sync::Arc;

#[cfg(target_arch = "wasm32")]
use futures::lock::Mutex;

#[async_trait(?Send)]
pub trait SimpleWebSocket {
    async fn new(url: String) -> Result<Self, Box<dyn std::error::Error>>
    where
        Self: Sized;
    async fn send(&mut self, msg: String) -> Result<(), Box<dyn std::error::Error>>;
    async fn recv(&mut self) -> Result<String, Box<dyn std::error::Error>>;
}

#[cfg(target_arch = "wasm32")]
pub struct WebSocketImpl {
    write: crate::networking::proxy::WsSplit,
    read: crate::networking::proxy::ReadSplit,
}

#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
impl SimpleWebSocket for WebSocketImpl {
    async fn new(url: String) -> Result<Self, Box<dyn std::error::Error>> {
        let ws = gloo_net::websocket::futures::WebSocket::open(&url)?;
        let (write, read) = ws.split();
        Ok(Self {
            write: Arc::new(Mutex::new(write)),
            read: Arc::new(Mutex::new(read)),
        })
    }

    async fn send(&mut self, msg: String) -> Result<(), Box<dyn std::error::Error>> {
        Ok(self
            .write
            .lock()
            .await
            .send(gloo_net::websocket::Message::Text(msg))
            .await?)
    }

    async fn recv(&mut self) -> Result<String, Box<dyn std::error::Error>> {
        Ok(if let Some(msg) = self.read.lock().await.next().await {
            match msg? {
                gloo_net::websocket::Message::Text(text) => text,
                _ => return Err("received non-text message".into()),
            }
        } else {
            return Err("failed to receive message".into());
        })
    }
}

#[cfg(not(target_arch = "wasm32"))]
pub struct WebSocketImpl {
    ws: tokio_tungstenite::WebSocketStream<
        tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
    >,
}

#[async_trait(?Send)]
#[cfg(not(target_arch = "wasm32"))]
impl SimpleWebSocket for WebSocketImpl {
    async fn new(url: String) -> Result<Self, Box<dyn std::error::Error>> {
        let (ws_stream, _response) = tokio_tungstenite::connect_async(url)
            .await
            .map_err(Box::new)?;
        Ok(Self { ws: ws_stream })
    }

    async fn send(&mut self, msg: String) -> Result<(), Box<dyn std::error::Error>> {
        Ok(self
            .ws
            .send(tokio_tungstenite::tungstenite::Message::Text(msg))
            .await?)
    }

    async fn recv(&mut self) -> Result<String, Box<dyn std::error::Error>> {
        match self.ws.next().await {
            Some(Ok(tokio_tungstenite::tungstenite::Message::Text(msg))) => Ok(msg),
            Some(Ok(_)) => Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                "received non-text message",
            ))),
            Some(Err(e)) => Err(Box::new(e)),
            None => Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                "failed to receive message",
            ))),
        }
    }
}