chipzen-bot 0.3.0

Build, test, and deploy poker bots for the Chipzen AI competition platform
Documentation
use thiserror::Error;

/// Top-level error type for SDK operations. Variants describe the
/// failure surface in terms users care about (connect failed, server
/// dropped us mid-handshake, peer sent something unparseable) rather
/// than transport internals.
///
/// Large variants (`Transport`, `Json`) are boxed so `Result<T, Error>`
/// stays small on the success path. The boxing is invisible to callers
/// thanks to the `From` impls below.
#[derive(Debug, Error)]
pub enum Error {
    #[error("WebSocket transport error: {0}")]
    Transport(Box<tokio_tungstenite::tungstenite::Error>),

    #[error("connection closed before {context}")]
    ConnectionClosed { context: &'static str },

    #[error("invalid URL: {0}")]
    InvalidUrl(#[from] url::ParseError),

    #[error("malformed protocol message: {0}")]
    Protocol(String),

    #[error("JSON serialization failed: {0}")]
    Json(Box<serde_json::Error>),

    #[error("retry budget exhausted ({attempts} attempts) — last error: {last_error}")]
    RetriesExhausted { attempts: u32, last_error: String },

    /// Raised when `bot.decide()` panics and `safe_mode` is off.
    ///
    /// Distinguished from transport/connection errors so the caller treats it
    /// as terminal (a deterministic bot bug, not a transient disconnect) and
    /// does NOT reconnect-retry it. See chipzen-ai/chipzen-sdk#52.
    #[error("bot decision error (safe_mode off): {0}")]
    BotDecision(String),

    /// Raised when a server-supplied gateway URL is cross-origin relative to
    /// the lobby, or downgrades `wss` to `ws`. Refused so the bot token is
    /// never sent to a different host or in cleartext.
    #[error("untrusted gateway URL: {0}")]
    UntrustedGateway(String),
}

impl From<tokio_tungstenite::tungstenite::Error> for Error {
    fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
        Error::Transport(Box::new(err))
    }
}

impl From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Self {
        Error::Json(Box::new(err))
    }
}