use thiserror::Error;
const PASSWORD_MASK_ASTERISKS: usize = 5;
fn sanitize_connection_string(conn_str: &str) -> String {
if let Some(start) = conn_str.find("://") {
let protocol = &conn_str[..start];
let after_protocol = &conn_str[start + 3..];
if let Some(at_pos) = after_protocol.find('@') {
let user_part = &after_protocol[..at_pos];
let sanitized_user: String = user_part
.chars()
.take_while(|c| *c != ':')
.chain(std::iter::once('*'))
.chain(
std::iter::once(':')
.chain(std::iter::once('*'))
.take(PASSWORD_MASK_ASTERISKS),
)
.collect();
return format!(
"{}://{}@{}",
protocol,
sanitized_user,
&after_protocol[at_pos + 1..]
);
}
}
conn_str.to_string()
}
#[derive(Error, Debug)]
pub enum CacheError {
#[error("Serialization error: {0}. Please check the data format and ensure the serializer is compatible."
)]
Serialization(String),
#[error("Operation failed: {0}. Please retry or check your request.")]
Operation(String),
#[error("Connection error: {0}. Please check network connectivity and server availability.")]
Connection(String),
#[error("Key not found: {0}. The requested key does not exist in the cache.")]
NotFound(String),
#[error(
"Cache degraded: {0}. The cache is operating in degraded mode with limited functionality."
)]
Degraded(String),
#[error("L1 cache operation failed: {0}. This may indicate memory pressure or configuration issues."
)]
L1Error(String),
#[error("L2 cache operation failed: {0}. Please check Redis connection and server status.")]
L2Error(String),
#[error("Configuration error: {0}. Please review your configuration file and ensure all required settings are provided."
)]
ConfigError(String),
#[error("Configuration error: {0}. Please review your configuration file.")]
Configuration(String),
#[error("Operation not supported: {0}. This feature may not be available for the current cache type."
)]
NotSupported(String),
#[error("WAL (Write-Ahead Log) operation failed: {0}. Check disk space and file permissions.")]
WalError(String),
#[error("Database error: {0}. Please check database connectivity and query syntax.")]
DatabaseError(String),
#[cfg(feature = "l2-redis")]
#[error("Redis connection failed: {}. Please ensure Redis server is running and the connection string is correct.",
sanitize_connection_string(&0.to_string())
)]
RedisError(#[from] redis::RedisError),
#[cfg(not(feature = "l2-redis"))]
#[error("Redis connection failed: {0}. Please enable l2-redis feature and ensure Redis server is running."
)]
RedisError(String),
#[error("I/O error: {0}. Check file permissions and disk space.")]
IoError(std::io::Error),
#[error("Backend error: {0}. This may be a transient issue, please retry.")]
BackendError(String),
#[error("Operation timed out: {0}. Consider increasing the timeout value or check system performance."
)]
Timeout(String),
#[error("Shutdown error: {0}. Some resources may not have been properly released.")]
ShutdownError(String),
#[error("Key too long: {0}. Maximum key length is {1} bytes.")]
KeyTooLong(usize, usize),
#[error("Value too large: {0}. Maximum value size is {1} bytes.")]
ValueTooLarge(usize, usize),
#[error("Buffer full: {0}. The batch write buffer has reached capacity. Please retry later or increase buffer size."
)]
BufferFull(String),
#[error(
"Invalid input: {0}. The provided input does not meet the required format or constraints."
)]
InvalidInput(String),
#[error("Invalid key: {0}. The provided key does not meet the required format or contains forbidden characters.")]
InvalidKey(String),
}
pub type Result<T> = std::result::Result<T, CacheError>;
#[cfg(feature = "database")]
impl From<sea_orm::DbErr> for CacheError {
fn from(e: sea_orm::DbErr) -> Self {
CacheError::DatabaseError(e.to_string())
}
}
impl From<std::io::Error> for CacheError {
fn from(e: std::io::Error) -> Self {
CacheError::IoError(e)
}
}
impl CacheError {
pub fn is_not_found(&self) -> bool {
matches!(self, CacheError::NotFound(_))
}
pub fn is_connection_error(&self) -> bool {
matches!(
self,
CacheError::Connection(_) | CacheError::RedisError(_) | CacheError::L2Error(_)
)
}
pub fn is_degraded(&self) -> bool {
matches!(self, CacheError::Degraded(_))
}
}