diff options
Diffstat (limited to 'src/error/mod.rs')
| -rw-r--r-- | src/error/mod.rs | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/error/mod.rs b/src/error/mod.rs new file mode 100644 index 0000000..606e344 --- /dev/null +++ b/src/error/mod.rs @@ -0,0 +1,79 @@ +use std::{error, fmt, io}; + +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; + +pub mod chain; +pub mod failed; + +// I'm making an effort to avoid `anyhow` here, as that crate is _enormously_ +// complex (though very usable). We don't need to be overly careful about +// allocations on errors in this app, so this is fine for most "general +// failure" cases. +type BoxedError = Box<dyn error::Error + Send + Sync>; + +// Returns a 500 Internal Server Error to the client. Meant to be used via the +// `?` operator; _does not_ return the originating error to the client. +#[derive(Debug)] +pub struct Internal(Id, BoxedError); + +impl<E> From<E> for Internal +where + E: Into<BoxedError>, +{ + fn from(error: E) -> Self { + let id = Id::generate(); + Self(id, error.into()) + } +} + +impl fmt::Display for Internal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(id, _) = self; + writeln!(f, "internal server error")?; + writeln!(f, "error id: {id}")?; + Ok(()) + } +} + +impl IntoResponse for Internal { + fn into_response(self) -> Response { + let Self(id, error) = &self; + chain::format_with_id(&mut io::stderr().lock(), id, error.as_ref()) + .expect("write to stderr"); + (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response() + } +} + +pub type Id = crate::id::Id<InternalError>; + +#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct InternalError; + +impl crate::id::Prefix for InternalError { + fn prefix(&self) -> &'static str { + "E" + } +} + +pub struct Unauthorized; + +impl IntoResponse for Unauthorized { + fn into_response(self) -> Response { + (StatusCode::UNAUTHORIZED, "unauthorized").into_response() + } +} + +pub struct NotFound<E>(pub E); + +impl<E> IntoResponse for NotFound<E> +where + E: std::error::Error, +{ + fn into_response(self) -> Response { + let Self(response) = self; + (StatusCode::NOT_FOUND, response.to_string()).into_response() + } +} |
