use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub enum S3Error {
AccessDenied(String),
BucketNotFound(String),
ObjectNotFound(String),
NetworkError(String),
InvalidCredentials(String),
BucketAlreadyExists(String),
BucketNotEmpty(String),
Other(String),
}
impl fmt::Display for S3Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
S3Error::AccessDenied(msg) => write!(f, "Access denied: {}", msg),
S3Error::BucketNotFound(msg) => write!(f, "Bucket not found: {}", msg),
S3Error::ObjectNotFound(msg) => write!(f, "Object not found: {}", msg),
S3Error::NetworkError(msg) => write!(f, "Network error: {}", msg),
S3Error::InvalidCredentials(msg) => write!(f, "Invalid minio: {}", msg),
S3Error::BucketAlreadyExists(msg) => write!(f, "Bucket already exists: {}", msg),
S3Error::BucketNotEmpty(msg) => write!(f, "Bucket not empty: {}", msg),
S3Error::Other(msg) => write!(f, "{}", msg),
}
}
}
impl S3Error {
pub fn from_message(msg: impl Into<String>) -> Self {
let msg = msg.into();
let msg_lower = msg.to_lowercase();
if msg_lower.contains("access denied") || msg_lower.contains("accessdenied") {
S3Error::AccessDenied(msg)
} else if msg_lower.contains("no such bucket") || msg_lower.contains("nosuchbucket") {
S3Error::BucketNotFound(msg)
} else if msg_lower.contains("no such key") || msg_lower.contains("nosuchkey") {
S3Error::ObjectNotFound(msg)
} else if msg_lower.contains("network") || msg_lower.contains("connection") || msg_lower.contains("timeout") {
S3Error::NetworkError(msg)
} else if msg_lower.contains("credential") || msg_lower.contains("signature") || msg_lower.contains("unauthorized") {
S3Error::InvalidCredentials(msg)
} else if msg_lower.contains("bucket already exists") || msg_lower.contains("bucketalreadyexists") || msg_lower.contains("bucketalreadyownedby") {
S3Error::BucketAlreadyExists(msg)
} else if msg_lower.contains("bucket not empty") || msg_lower.contains("bucketnotempty") {
S3Error::BucketNotEmpty(msg)
} else {
S3Error::Other(msg)
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum LocalError {
NotFound(String),
PermissionDenied(String),
DirectoryNotEmpty(String),
IoError(String),
Other(String),
}
impl fmt::Display for LocalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LocalError::NotFound(msg) => write!(f, "Not found: {}", msg),
LocalError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
LocalError::DirectoryNotEmpty(msg) => write!(f, "Directory not empty: {}", msg),
LocalError::IoError(msg) => write!(f, "IO error: {}", msg),
LocalError::Other(msg) => write!(f, "{}", msg),
}
}
}
impl LocalError {
pub fn from_message(msg: impl Into<String>) -> Self {
let msg = msg.into();
let msg_lower = msg.to_lowercase();
if msg_lower.contains("not found") || msg_lower.contains("no such file") {
LocalError::NotFound(msg)
} else if msg_lower.contains("permission denied") || msg_lower.contains("access denied") {
LocalError::PermissionDenied(msg)
} else if msg_lower.contains("not empty") || msg_lower.contains("directory not empty") {
LocalError::DirectoryNotEmpty(msg)
} else if msg_lower.contains("io error") {
LocalError::IoError(msg)
} else {
LocalError::Other(msg)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_s3_error_from_message_access_denied() {
let err = S3Error::from_message("Access Denied: you don't have permission");
assert!(matches!(err, S3Error::AccessDenied(_)));
}
#[test]
fn test_s3_error_from_message_bucket_not_found() {
let err = S3Error::from_message("NoSuchBucket: bucket does not exist");
assert!(matches!(err, S3Error::BucketNotFound(_)));
}
#[test]
fn test_s3_error_from_message_other() {
let err = S3Error::from_message("Some random error");
assert!(matches!(err, S3Error::Other(_)));
}
#[test]
fn test_local_error_from_message_not_found() {
let err = LocalError::from_message("No such file or directory");
assert!(matches!(err, LocalError::NotFound(_)));
}
#[test]
fn test_local_error_from_message_permission_denied() {
let err = LocalError::from_message("Permission denied: cannot access file");
assert!(matches!(err, LocalError::PermissionDenied(_)));
}
#[test]
fn test_s3_error_display() {
let err = S3Error::AccessDenied("test bucket".into());
assert_eq!(format!("{}", err), "Access denied: test bucket");
}
#[test]
fn test_local_error_display() {
let err = LocalError::NotFound("/path/to/file".into());
assert_eq!(format!("{}", err), "Not found: /path/to/file");
}
}