Improve typing and errors, clean up

This commit is contained in:
Silas Brack 2026-03-07 15:24:05 +01:00
parent 07490efc28
commit ec408aff29
5 changed files with 205 additions and 22 deletions

View file

@ -1,11 +1,33 @@
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,
Db(rusqlite::Error),
VolumeError(String),
InsufficientVolumes { need: usize, have: usize },
PartialWrite,
}
impl From<rusqlite::Error> for AppError {
@ -22,17 +44,22 @@ impl std::fmt::Display for AppError {
match self {
AppError::NotFound => write!(f, "not found"),
AppError::Db(e) => write!(f, "database error: {e}"),
AppError::VolumeError(msg) => write!(f, "volume error: {msg}"),
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, msg) = match &self {
AppError::NotFound => (StatusCode::NOT_FOUND, self.to_string()),
_ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
let status = match &self {
AppError::NotFound => StatusCode::NOT_FOUND,
AppError::Db(_) => StatusCode::INTERNAL_SERVER_ERROR,
AppError::InsufficientVolumes { .. } => StatusCode::SERVICE_UNAVAILABLE,
AppError::PartialWrite => StatusCode::BAD_GATEWAY,
};
(status, msg).into_response()
(status, self.to_string()).into_response()
}
}