use std::fmt;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AntQuicError {
#[error("Transport error: {0}")]
Transport(#[from] crate::transport_error::Error),
#[error("Connection error: {0}")]
Connection(#[from] crate::connection::ConnectionError),
#[error("Discovery error: {0}")]
Discovery(#[from] crate::candidate_discovery::DiscoveryError),
#[error("NAT traversal error: {0}")]
NatTraversal(#[from] crate::nat_traversal_api::NatTraversalError),
#[error("Configuration error: {0}")]
Config(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Crypto error: {0}")]
Crypto(String),
#[error("PQC error: {0}")]
Pqc(#[from] crate::crypto::pqc::types::PqcError),
#[error("Operation timed out: {0}")]
Timeout(String),
#[error("Resource exhausted: {0}")]
ResourceExhausted(String),
#[error("Invalid parameter: {0}")]
InvalidParameter(String),
#[error("Internal error: {0}")]
Internal(String),
}
pub type Result<T> = std::result::Result<T, AntQuicError>;
pub mod utils {
use super::*;
use tracing::{error, warn, info, debug};
pub fn log_error<E: std::error::Error>(error: &E, context: &str) {
let error_msg = format!("{}: {}", context, error);
match error.downcast_ref::<AntQuicError>() {
Some(AntQuicError::Internal(_)) => error!("{}", error_msg),
Some(AntQuicError::Transport(_)) => warn!("{}", error_msg),
Some(AntQuicError::Connection(_)) => warn!("{}", error_msg),
Some(AntQuicError::Timeout(_)) => info!("{}", error_msg),
Some(AntQuicError::InvalidParameter(_)) => debug!("{}", error_msg),
_ => warn!("{}", error_msg),
}
}
pub fn to_user_message<E: std::error::Error>(error: &E) -> String {
match error.downcast_ref::<AntQuicError>() {
Some(AntQuicError::Transport(_)) => "Network connection error. Please check your internet connection.".to_string(),
Some(AntQuicError::Connection(_)) => "Failed to establish connection. The remote peer may be unreachable.".to_string(),
Some(AntQuicError::Discovery(_)) => "Failed to discover network configuration. Please check your network settings.".to_string(),
Some(AntQuicError::NatTraversal(_)) => "NAT traversal failed. This may be due to restrictive network policies.".to_string(),
Some(AntQuicError::Timeout(_)) => "Operation timed out. Please try again.".to_string(),
Some(AntQuicError::Config(_)) => "Configuration error. Please check your settings.".to_string(),
Some(AntQuicError::Io(_)) => "System I/O error. Please check file permissions and disk space.".to_string(),
Some(AntQuicError::Crypto(_)) => "Cryptographic operation failed. This may indicate a security issue.".to_string(),
Some(AntQuicError::Pqc(_)) => "Post-quantum cryptographic operation failed.".to_string(),
Some(AntQuicError::ResourceExhausted(_)) => "System resources exhausted. Please close some applications and try again.".to_string(),
Some(AntQuicError::InvalidParameter(_)) => "Invalid input parameters provided.".to_string(),
Some(AntQuicError::Internal(_)) => "An internal error occurred. Please report this issue.".to_string(),
_ => format!("An unexpected error occurred: {}", error),
}
}
pub fn is_recoverable<E: std::error::Error>(error: &E) -> bool {
match error.downcast_ref::<AntQuicError>() {
Some(AntQuicError::Timeout(_)) => true,
Some(AntQuicError::Connection(_)) => true,
Some(AntQuicError::Discovery(_)) => true,
Some(AntQuicError::NatTraversal(_)) => true,
Some(AntQuicError::Io(io_err)) => {
matches!(io_err.kind(), std::io::ErrorKind::TimedOut | std::io::ErrorKind::Interrupted)
}
_ => false,
}
}
pub fn get_retry_delay<E: std::error::Error>(error: &E) -> Option<std::time::Duration> {
match error.downcast_ref::<AntQuicError>() {
Some(AntQuicError::Timeout(_)) => Some(std::time::Duration::from_millis(100)),
Some(AntQuicError::Connection(_)) => Some(std::time::Duration::from_millis(500)),
Some(AntQuicError::Discovery(_)) => Some(std::time::Duration::from_secs(1)),
Some(AntQuicError::NatTraversal(_)) => Some(std::time::Duration::from_secs(2)),
Some(AntQuicError::Io(io_err)) => {
match io_err.kind() {
std::io::ErrorKind::TimedOut => Some(std::time::Duration::from_millis(100)),
std::io::ErrorKind::Interrupted => Some(std::time::Duration::from_millis(10)),
_ => None,
}
}
_ => None,
}
}
}
#[macro_export]
macro_rules! ensure {
($condition:expr, $error:expr) => {
if !($condition) {
return Err($error.into());
}
};
}
#[macro_export]
macro_rules! bail {
($error:expr) => {
return Err($error.into());
};
}
#[macro_export]
macro_rules! context {
($result:expr, $context:expr) => {
$result.map_err(|e| AntQuicError::Internal(format!("{}: {}", $context, e)))
};
}