use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum SdkError {
#[error("Configuration error: {0}")]
Config(String),
#[error("Connection error: {0}")]
Connection(String),
#[error("Authentication failed: {0}")]
Auth(String),
#[error("Protocol error: {0}")]
Protocol(String),
#[error("Transaction error: {0}")]
Transaction(String),
#[error("Timeout after {0:?}")]
Timeout(Duration),
#[error("All protocols failed to connect")]
AllProtocolsFailed,
#[error("Rate limited: {0}")]
RateLimited(String),
#[error("Not connected to server")]
NotConnected,
#[error("Stream closed")]
StreamClosed,
#[error("Insufficient token balance")]
InsufficientTokens,
#[error("Internal error: {0}")]
Internal(String),
}
impl SdkError {
pub fn config(msg: impl Into<String>) -> Self {
SdkError::Config(msg.into())
}
pub fn connection(msg: impl Into<String>) -> Self {
SdkError::Connection(msg.into())
}
pub fn auth(msg: impl Into<String>) -> Self {
SdkError::Auth(msg.into())
}
pub fn protocol(msg: impl Into<String>) -> Self {
SdkError::Protocol(msg.into())
}
pub fn transaction(msg: impl Into<String>) -> Self {
SdkError::Transaction(msg.into())
}
}
impl From<reqwest::Error> for SdkError {
fn from(e: reqwest::Error) -> Self {
if e.is_timeout() {
SdkError::Timeout(Duration::from_secs(30))
} else if e.is_connect() {
SdkError::Connection(e.to_string())
} else {
SdkError::Protocol(e.to_string())
}
}
}
impl From<serde_json::Error> for SdkError {
fn from(e: serde_json::Error) -> Self {
SdkError::Protocol(format!("JSON error: {}", e))
}
}
impl From<tokio_tungstenite::tungstenite::Error> for SdkError {
fn from(e: tokio_tungstenite::tungstenite::Error) -> Self {
SdkError::Connection(format!("WebSocket error: {}", e))
}
}
impl From<std::io::Error> for SdkError {
fn from(e: std::io::Error) -> Self {
SdkError::Connection(format!("IO error: {}", e))
}
}
pub type Result<T> = std::result::Result<T, SdkError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = SdkError::Config("missing api_key".to_string());
assert_eq!(err.to_string(), "Configuration error: missing api_key");
let err = SdkError::Timeout(Duration::from_secs(5));
assert_eq!(err.to_string(), "Timeout after 5s");
}
#[test]
fn test_error_constructors() {
let err = SdkError::config("test");
assert!(matches!(err, SdkError::Config(_)));
let err = SdkError::auth("invalid key");
assert!(matches!(err, SdkError::Auth(_)));
}
}