#![allow(non_snake_case)]
#[cfg(feature = "pyo3")]
use pyo3::types::PyTracebackMethods;
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum RiError {
Io(String),
Serde(String),
Config(String),
Hook(String),
Prometheus(String),
ServiceMesh(String),
InvalidState(String),
InvalidInput(String),
SecurityViolation(String),
DeviceNotFound { device_id: String },
DeviceAllocationFailed { device_id: String, reason: String },
AllocationNotFound { allocation_id: String },
ModuleNotFound { module_name: String },
ModuleInitFailed { module_name: String, reason: String },
ModuleStartFailed { module_name: String, reason: String },
ModuleShutdownFailed { module_name: String, reason: String },
CircularDependency { modules: Vec<String> },
MissingDependency { module_name: String, dependency: String },
Other(String),
ExternalError(String),
PoolError(String),
DeviceError(String),
RedisError(String),
HttpClientError(String),
TomlError(String),
YamlError(String),
Queue(String),
FrameError(String),
Database(String),
}
pub type RiResult<T> = Result<T, RiError>;
impl std::fmt::Display for RiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RiError::Io(err) => write!(f, "IO error: {err}"),
RiError::Serde(err) => write!(f, "Serialization error: {err}"),
RiError::Config(msg) => write!(f, "Configuration error: {msg}"),
RiError::Hook(msg) => write!(f, "Hook error: {msg}"),
RiError::Prometheus(err) => write!(f, "Prometheus error: {err}"),
RiError::ServiceMesh(err) => write!(f, "Service mesh error: {err}"),
RiError::InvalidState(msg) => write!(f, "Invalid state: {msg}"),
RiError::InvalidInput(msg) => write!(f, "Invalid input: {msg}"),
RiError::SecurityViolation(msg) => write!(f, "Security violation: {msg}"),
RiError::DeviceNotFound { device_id } => write!(f, "Device not found: {device_id}"),
RiError::DeviceAllocationFailed { device_id, reason } => {
write!(f, "Device allocation failed for {device_id}: {reason}")
}
RiError::AllocationNotFound { allocation_id } => {
write!(f, "Allocation not found: {allocation_id}")
}
RiError::ModuleNotFound { module_name } => {
write!(f, "Module not found: {module_name}")
}
RiError::ModuleInitFailed { module_name, reason } => {
write!(f, "Module initialization failed for {module_name}: {reason}")
}
RiError::ModuleStartFailed { module_name, reason } => {
write!(f, "Module start failed for {module_name}: {reason}")
}
RiError::ModuleShutdownFailed { module_name, reason } => {
write!(f, "Module shutdown failed for {module_name}: {reason}")
}
RiError::CircularDependency { modules } => {
write!(f, "Circular dependency detected: {}", modules.join(" -> "))
}
RiError::MissingDependency { module_name, dependency } => {
write!(f, "Module {module_name} depends on missing module: {dependency}")
}
RiError::Other(msg) => write!(f, "{msg}"),
RiError::ExternalError(msg) => write!(f, "External error: {msg}"),
RiError::PoolError(msg) => write!(f, "Pool error: {msg}"),
RiError::DeviceError(msg) => write!(f, "Device error: {msg}"),
RiError::RedisError(msg) => write!(f, "Redis error: {msg}"),
RiError::HttpClientError(msg) => write!(f, "HTTP client error: {msg}"),
RiError::TomlError(msg) => write!(f, "TOML error: {msg}"),
RiError::YamlError(msg) => write!(f, "YAML error: {msg}"),
RiError::Queue(msg) => write!(f, "Queue error: {msg}"),
RiError::FrameError(msg) => write!(f, "Frame error: {msg}"),
RiError::Database(msg) => write!(f, "Database error: {msg}"),
}
}
}
impl std::error::Error for RiError {}
impl From<std::io::Error> for RiError {
fn from(error: std::io::Error) -> Self {
RiError::Io(format!("I/O operation failed: {}", error))
}
}
pub struct RiErrorFormatter<'a> {
error: &'a RiError,
}
impl<'a> RiErrorFormatter<'a> {
pub fn new(error: &'a RiError) -> Self {
Self { error }
}
pub fn format(&self) -> String {
let base_message = self.error.to_string();
let suggestion = self.get_suggestion();
match suggestion {
Some(s) => format!("{}\n💡 Suggestion: {}", base_message, s),
None => base_message,
}
}
fn get_suggestion(&self) -> Option<&'static str> {
match self.error {
RiError::Io(_) => Some("Check file permissions and disk space"),
RiError::Serde(_) => Some("Verify data format matches expected schema"),
RiError::Config(_) => Some("Review configuration file syntax and required fields"),
RiError::Hook(_) => Some("Check hook implementation for errors and ensure proper registration"),
RiError::Prometheus(_) => Some("Verify Prometheus server is running and metrics endpoint is accessible"),
RiError::ServiceMesh(_) => Some("Check service mesh configuration and network connectivity"),
RiError::InvalidState(_) => Some("Ensure module is in correct state before performing operation"),
RiError::InvalidInput(_) => Some("Validate input data against expected format and constraints"),
RiError::SecurityViolation(_) => Some("Review security policies and access permissions"),
RiError::DeviceNotFound { .. } => Some("Verify device ID exists and is properly registered"),
RiError::DeviceAllocationFailed { .. } => Some("Check device availability and allocation constraints"),
RiError::AllocationNotFound { .. } => Some("Verify allocation ID is correct and hasn't expired"),
RiError::ModuleNotFound { .. } => Some("Ensure module is registered and feature flag is enabled"),
RiError::ModuleInitFailed { .. } => Some("Check module dependencies and initialization parameters"),
RiError::ModuleStartFailed { .. } => Some("Review module start sequence and resource availability"),
RiError::ModuleShutdownFailed { .. } => Some("Ensure no active connections before shutdown"),
RiError::CircularDependency { .. } => Some("Restructure module dependencies to eliminate cycles"),
RiError::MissingDependency { .. } => Some("Add required module to application configuration"),
RiError::Other(_) => None,
RiError::ExternalError(_) => Some("Check external service status and credentials"),
RiError::PoolError(_) => Some("Verify connection pool configuration and database availability"),
RiError::DeviceError(_) => Some("Check device connection and configuration"),
RiError::RedisError(_) => Some("Verify Redis server is running and connection parameters are correct"),
RiError::HttpClientError(_) => Some("Check network connectivity and target server availability"),
RiError::TomlError(_) => Some("Validate TOML syntax and required sections"),
RiError::YamlError(_) => Some("Validate YAML syntax and indentation"),
RiError::Queue(_) => Some("Check message queue service status and queue configuration"),
RiError::FrameError(_) => Some("Check frame format and protocol compatibility"),
RiError::Database(_) => Some("Verify database connection and query syntax"),
}
}
}
#[inline]
pub fn format_error(error: &RiError) -> String {
RiErrorFormatter::new(error).format()
}
#[inline]
pub fn log_error(error: &RiError) {
log::error!("{}", format_error(error));
}
impl From<serde_json::Error> for RiError {
fn from(error: serde_json::Error) -> Self {
RiError::Serde(error.to_string())
}
}
#[cfg(feature = "observability")]
impl From<prometheus::Error> for RiError {
fn from(error: prometheus::Error) -> Self {
RiError::Prometheus(error.to_string())
}
}
#[cfg(feature = "redis")]
impl From<redis::RedisError> for RiError {
fn from(error: redis::RedisError) -> Self {
RiError::RedisError(error.to_string())
}
}
#[cfg(feature = "http_client")]
impl From<reqwest::Error> for RiError {
fn from(error: reqwest::Error) -> Self {
RiError::HttpClientError(error.to_string())
}
}
impl From<toml::de::Error> for RiError {
fn from(error: toml::de::Error) -> Self {
RiError::TomlError(error.to_string())
}
}
impl From<toml::ser::Error> for RiError {
fn from(error: toml::ser::Error) -> Self {
RiError::TomlError(error.to_string())
}
}
impl From<serde_yaml::Error> for RiError {
fn from(error: serde_yaml::Error) -> Self {
RiError::YamlError(error.to_string())
}
}
#[cfg(feature = "rabbitmq")]
impl From<lapin::Error> for RiError {
fn from(error: lapin::Error) -> Self {
RiError::Other(format!("RabbitMQ error: {error}"))
}
}
#[cfg(all(feature = "kafka", not(windows)))]
impl From<rdkafka::error::KafkaError> for RiError {
fn from(error: rdkafka::error::KafkaError) -> Self {
RiError::Queue(format!("Kafka error: {}", error))
}
}
#[cfg(all(feature = "kafka", windows))]
impl From<rdkafka::error::KafkaError> for RiError {
fn from(error: rdkafka::error::KafkaError) -> Self {
RiError::Queue(format!("Kafka error: {}", error))
}
}
impl From<tokio::time::error::Elapsed> for RiError {
fn from(error: tokio::time::error::Elapsed) -> Self {
RiError::Io(format!("Operation timed out: {}", error))
}
}
impl From<std::str::Utf8Error> for RiError {
fn from(error: std::str::Utf8Error) -> Self {
RiError::Serde(format!("UTF-8 conversion error: {}", error))
}
}
impl From<tokio::sync::TryLockError> for RiError {
fn from(error: tokio::sync::TryLockError) -> Self {
RiError::InvalidState(format!("Lock acquisition failed: {}", error))
}
}
impl From<super::lock::RiLockError> for RiError {
fn from(error: super::lock::RiLockError) -> Self {
RiError::InvalidState(format!("Lock error: {}", error))
}
}
#[cfg(feature = "pyo3")]
impl std::convert::From<RiError> for pyo3::PyErr {
fn from(error: RiError) -> Self {
pyo3::exceptions::PyRuntimeError::new_err(error.to_string())
}
}
#[cfg(feature = "pyo3")]
impl std::convert::From<pyo3::PyErr> for RiError {
fn from(error: pyo3::PyErr) -> Self {
let error_info = pyo3::Python::attach(|py| {
let traceback = error.traceback(py)
.and_then(|tb| tb.format().ok())
.unwrap_or_default();
let error_type = error.get_type(py).to_string();
let error_value = error.value(py).to_string();
format!("{}: {}\n{}", error_type, error_value, traceback)
});
RiError::Other(format!("Python error: {}", error_info))
}
}
#[cfg(feature = "pyo3")]
#[pyo3::prelude::pymethods]
impl RiError {
pub fn __str__(&self) -> String {
self.to_string()
}
pub fn __repr__(&self) -> String {
format!("{:?}", self)
}
#[staticmethod]
pub fn from_str(message: &str) -> Self {
RiError::Other(message.to_string())
}
#[staticmethod]
pub fn io(message: &str) -> Self {
RiError::Io(message.to_string())
}
#[staticmethod]
pub fn serde(message: &str) -> Self {
RiError::Serde(message.to_string())
}
#[staticmethod]
pub fn config(message: &str) -> Self {
RiError::Config(message.to_string())
}
#[staticmethod]
pub fn hook(message: &str) -> Self {
RiError::Hook(message.to_string())
}
pub fn is_io(&self) -> bool {
matches!(self, RiError::Io(_))
}
pub fn is_serde(&self) -> bool {
matches!(self, RiError::Serde(_))
}
pub fn is_config(&self) -> bool {
matches!(self, RiError::Config(_))
}
pub fn is_hook(&self) -> bool {
matches!(self, RiError::Hook(_))
}
pub fn is_prometheus(&self) -> bool {
matches!(self, RiError::Prometheus(_))
}
pub fn is_service_mesh(&self) -> bool {
matches!(self, RiError::ServiceMesh(_))
}
pub fn is_invalid_state(&self) -> bool {
matches!(self, RiError::InvalidState(_))
}
pub fn is_invalid_input(&self) -> bool {
matches!(self, RiError::InvalidInput(_))
}
pub fn is_security_violation(&self) -> bool {
matches!(self, RiError::SecurityViolation(_))
}
pub fn is_device_not_found(&self) -> bool {
matches!(self, RiError::DeviceNotFound { .. })
}
pub fn is_device_allocation_failed(&self) -> bool {
matches!(self, RiError::DeviceAllocationFailed { .. })
}
pub fn is_allocation_not_found(&self) -> bool {
matches!(self, RiError::AllocationNotFound { .. })
}
pub fn is_module_not_found(&self) -> bool {
matches!(self, RiError::ModuleNotFound { .. })
}
pub fn is_module_init_failed(&self) -> bool {
matches!(self, RiError::ModuleInitFailed { .. })
}
pub fn is_module_start_failed(&self) -> bool {
matches!(self, RiError::ModuleStartFailed { .. })
}
pub fn is_module_shutdown_failed(&self) -> bool {
matches!(self, RiError::ModuleShutdownFailed { .. })
}
pub fn is_circular_dependency(&self) -> bool {
matches!(self, RiError::CircularDependency { .. })
}
pub fn is_missing_dependency(&self) -> bool {
matches!(self, RiError::MissingDependency { .. })
}
pub fn is_other(&self) -> bool {
matches!(self, RiError::Other(_))
}
pub fn is_external_error(&self) -> bool {
matches!(self, RiError::ExternalError(_))
}
pub fn is_pool_error(&self) -> bool {
matches!(self, RiError::PoolError(_))
}
pub fn is_device_error(&self) -> bool {
matches!(self, RiError::DeviceError(_))
}
pub fn is_redis_error(&self) -> bool {
matches!(self, RiError::RedisError(_))
}
pub fn is_http_client_error(&self) -> bool {
matches!(self, RiError::HttpClientError(_))
}
pub fn is_toml_error(&self) -> bool {
matches!(self, RiError::TomlError(_))
}
pub fn is_yaml_error(&self) -> bool {
matches!(self, RiError::YamlError(_))
}
pub fn is_queue(&self) -> bool {
matches!(self, RiError::Queue(_))
}
}