70 lines
2.4 KiB
Rust
70 lines
2.4 KiB
Rust
use axum::http::StatusCode;
|
|
use axum::response::{IntoResponse, Response};
|
|
|
|
/// Errors from individual volume HTTP requests — used for logging, not HTTP responses.
|
|
#[derive(Debug)]
|
|
pub enum VolumeError {
|
|
Request { url: String, source: reqwest::Error },
|
|
BadStatus { url: String, status: reqwest::StatusCode },
|
|
}
|
|
|
|
impl std::fmt::Display for VolumeError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
VolumeError::Request { url, source } => {
|
|
write!(f, "volume request to {url} failed: {source}")
|
|
}
|
|
VolumeError::BadStatus { url, status } => {
|
|
write!(f, "volume {url} returned status {status}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Application-level errors that map to HTTP responses.
|
|
#[derive(Debug)]
|
|
pub enum AppError {
|
|
NotFound,
|
|
CorruptRecord { key: String },
|
|
Db(rusqlite::Error),
|
|
InsufficientVolumes { need: usize, have: usize },
|
|
PartialWrite,
|
|
}
|
|
|
|
impl From<rusqlite::Error> for AppError {
|
|
fn from(e: rusqlite::Error) -> Self {
|
|
match e {
|
|
rusqlite::Error::QueryReturnedNoRows => AppError::NotFound,
|
|
other => AppError::Db(other),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for AppError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
AppError::NotFound => write!(f, "not found"),
|
|
AppError::CorruptRecord { key } => {
|
|
write!(f, "corrupt record for key {key}: no volumes")
|
|
}
|
|
AppError::Db(e) => write!(f, "database error: {e}"),
|
|
AppError::InsufficientVolumes { need, have } => {
|
|
write!(f, "need {need} volumes but only {have} available")
|
|
}
|
|
AppError::PartialWrite => write!(f, "not all volume writes succeeded"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl IntoResponse for AppError {
|
|
fn into_response(self) -> Response {
|
|
let status = match &self {
|
|
AppError::NotFound => StatusCode::NOT_FOUND,
|
|
AppError::CorruptRecord { .. } => StatusCode::INTERNAL_SERVER_ERROR,
|
|
AppError::Db(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
|
AppError::InsufficientVolumes { .. } => StatusCode::SERVICE_UNAVAILABLE,
|
|
AppError::PartialWrite => StatusCode::BAD_GATEWAY,
|
|
};
|
|
(status, self.to_string()).into_response()
|
|
}
|
|
}
|