use thiserror::Error;
pub type Result<T> = std::result::Result<T, CompatError>;
#[derive(Debug, Error)]
pub enum CompatError {
#[error("user not found: {0}")]
UserNotFound(String),
#[error("username already exists: {0}")]
UsernameExists(String),
#[error("invalid username: {0}")]
InvalidUsername(String),
#[error("token not found")]
TokenNotFound,
#[error("invalid token format")]
InvalidTokenFormat,
#[error("token expired")]
TokenExpired,
#[error("invalid token")]
InvalidToken,
#[error("insufficient scope: requires {0:?}")]
InsufficientScope(crate::token::TokenScope),
#[error("SSH key not found")]
SshKeyNotFound,
#[error("invalid SSH key format: {0}")]
InvalidSshKey(String),
#[error("SSH key already exists with fingerprint: {0}")]
SshKeyExists(String),
#[error("release not found: {0}")]
ReleaseNotFound(String),
#[error("release already exists for tag: {0}")]
ReleaseExists(String),
#[error("asset not found: {0}")]
AssetNotFound(String),
#[error("asset already exists: {0}")]
AssetExists(String),
#[error("path not found: {0}")]
PathNotFound(String),
#[error("invalid ref: {0}")]
InvalidRef(String),
#[error("archive generation failed: {0}")]
ArchiveFailed(String),
#[error("rate limit exceeded, resets at {0}")]
RateLimitExceeded(u64),
#[error("storage error: {0}")]
Storage(String),
#[error("crypto error: {0}")]
Crypto(String),
}
impl CompatError {
pub fn status_code(&self) -> u16 {
match self {
Self::UserNotFound(_) => 404,
Self::UsernameExists(_) => 409,
Self::InvalidUsername(_) => 422,
Self::TokenNotFound => 401,
Self::InvalidTokenFormat => 401,
Self::TokenExpired => 401,
Self::InvalidToken => 401,
Self::InsufficientScope(_) => 403,
Self::SshKeyNotFound => 404,
Self::InvalidSshKey(_) => 422,
Self::SshKeyExists(_) => 409,
Self::ReleaseNotFound(_) => 404,
Self::ReleaseExists(_) => 409,
Self::AssetNotFound(_) => 404,
Self::AssetExists(_) => 409,
Self::PathNotFound(_) => 404,
Self::InvalidRef(_) => 422,
Self::ArchiveFailed(_) => 500,
Self::RateLimitExceeded(_) => 429,
Self::Storage(_) => 500,
Self::Crypto(_) => 500,
}
}
pub fn github_message(&self) -> &str {
match self {
Self::UserNotFound(_) => "Not Found",
Self::UsernameExists(_) => "Validation Failed",
Self::InvalidUsername(_) => "Validation Failed",
Self::TokenNotFound => "Bad credentials",
Self::InvalidTokenFormat => "Bad credentials",
Self::TokenExpired => "Bad credentials",
Self::InvalidToken => "Bad credentials",
Self::InsufficientScope(_) => "Forbidden",
Self::SshKeyNotFound => "Not Found",
Self::InvalidSshKey(_) => "Validation Failed",
Self::SshKeyExists(_) => "Validation Failed",
Self::ReleaseNotFound(_) => "Not Found",
Self::ReleaseExists(_) => "Validation Failed",
Self::AssetNotFound(_) => "Not Found",
Self::AssetExists(_) => "Validation Failed",
Self::PathNotFound(_) => "Not Found",
Self::InvalidRef(_) => "Validation Failed",
Self::ArchiveFailed(_) => "Server Error",
Self::RateLimitExceeded(_) => "API rate limit exceeded",
Self::Storage(_) => "Server Error",
Self::Crypto(_) => "Server Error",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_status_codes() {
assert_eq!(CompatError::UserNotFound("test".into()).status_code(), 404);
assert_eq!(CompatError::TokenNotFound.status_code(), 401);
assert_eq!(CompatError::RateLimitExceeded(0).status_code(), 429);
}
}