wstomp 0.2.0

A STOMP-over-WebSocket client library for Rust, built on top of awc and async-stomp
Documentation
use async_stomp::{FromServer, Message, ToServer};
use awc::{
    error::{WsClientError, WsProtocolError},
    ws::CloseReason,
};
use tokio::sync::mpsc::error::SendError;

#[derive(Debug)]
pub enum WStompConnectError {
    WsClientError(WsClientError),
    ConnectMessageFailed(Box<SendError<Message<ToServer>>>),
    ReconnectionLimit,
}

/// Custom enum combine events in WebSocket and STOMP
#[derive(Debug)]
pub enum WStompEvent {
    /// Regular message from STOMP protocol
    Message(Message<FromServer>),
    /// WebSocket or STOMP error combined
    Error(WStompError),
}

impl From<WStompError> for WStompEvent {
    fn from(err: WStompError) -> Self {
        Self::Error(err)
    }
}

/// Custom error type to combine WebSocket and STOMP errors.
#[derive(Debug)]
pub enum WStompError {
    /// Error during receiving websocket frames (from awc)
    WsReceive(WsProtocolError),
    /// Error during sending websocket frames (from awc)
    WsSend(WsProtocolError),
    /// Error while decoding (receiving) STOMP message (from async-stomp)
    StompDecoding(anyhow::Error),
    /// Error while encoding (sending) STOMP message (from async-stomp)
    StompEncoding(anyhow::Error),
    /// Incomplete STOMP frame received through WebSocket
    ///
    /// This is a warning that WebSocket protocol finished receiving data, but STOMP protocol
    /// doesn't recognize it as a full STOMP message. Should not happen, can be ignored in most cases.
    IncompleteStompFrame,
    /// Websocket closed connection (with reason)
    WebsocketClosed(Option<CloseReason>),
    /// Can't send ping, probably network problems
    PingFailed(anyhow::Error),
    /// Haven't received pong from last ping
    PingTimeout,
}

impl std::fmt::Display for WStompConnectError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::WsClientError(WsClientError::InvalidResponseStatus(status)) => write!(
                f,
                "WebSocket connection error: server rejected upgrade with HTTP {}",
                status
            ),
            Self::WsClientError(err) => write!(f, "WebSocket connection error: {}", err),
            Self::ConnectMessageFailed(msg) => write!(f, "WebSocket receive error: {}", msg),
            Self::ReconnectionLimit => write!(f, "Reconnection retry limit reached"),
        }
    }
}

impl std::error::Error for WStompConnectError {}

impl std::fmt::Display for WStompError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::WsReceive(err) => write!(f, "WebSocket receive error: {}", err),
            Self::WsSend(err) => write!(f, "WebSocket send error: {}", err),
            Self::StompDecoding(err) => write!(f, "STOMP decoding error: {}", err),
            Self::StompEncoding(err) => write!(f, "STOMP encoding error: {}", err),
            Self::IncompleteStompFrame => {
                write!(f, "STOMP decoding warning: Dropped incomplete frame")
            }
            Self::WebsocketClosed(reason) => write!(
                f,
                "Websocket closed {}",
                reason
                    .as_ref()
                    .map(|r| r.description.clone().unwrap_or_default())
                    .unwrap_or_default()
            ),
            Self::PingFailed(err) => write!(f, "Websocket ping failed: {err}"),
            Self::PingTimeout => write!(f, "Websocket ping timeout"),
        }
    }
}

impl std::error::Error for WStompError {}