use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use ferro_blob_store::BlobStoreError;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum MavenError {
#[error("invalid Maven layout path: {0}")]
InvalidPath(String),
#[error("POM coordinate mismatch: {0}")]
CoordinateMismatch(String),
#[error("invalid POM: {0}")]
InvalidPom(String),
#[error("invalid maven-metadata.xml: {0}")]
InvalidMetadata(String),
#[error("not found: {0}")]
NotFound(String),
#[error("checksum mismatch: {0}")]
ChecksumMismatch(String),
#[error(transparent)]
Storage(#[from] BlobStoreError),
}
impl MavenError {
#[must_use]
pub fn status(&self) -> StatusCode {
match self {
Self::InvalidPath(_)
| Self::InvalidPom(_)
| Self::InvalidMetadata(_)
| Self::CoordinateMismatch(_)
| Self::ChecksumMismatch(_) => StatusCode::BAD_REQUEST,
Self::NotFound(_) => StatusCode::NOT_FOUND,
Self::Storage(err) => storage_status(err),
}
}
}
fn storage_status(err: &BlobStoreError) -> StatusCode {
match err {
BlobStoreError::NotFound(_) => StatusCode::NOT_FOUND,
BlobStoreError::DigestMismatch { .. } | BlobStoreError::InvalidDigest(_) => {
StatusCode::BAD_REQUEST
}
BlobStoreError::Io(_) => StatusCode::INTERNAL_SERVER_ERROR,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
}
impl IntoResponse for MavenError {
fn into_response(self) -> Response {
let status = self.status();
let body = self.to_string();
(status, body).into_response()
}
}
#[cfg(test)]
mod tests {
use super::MavenError;
use axum::http::StatusCode;
#[test]
fn invalid_path_maps_to_400() {
let err = MavenError::InvalidPath("no artifactId segment".into());
assert_eq!(err.status(), StatusCode::BAD_REQUEST);
}
#[test]
fn not_found_maps_to_404() {
let err = MavenError::NotFound("foo.jar".into());
assert_eq!(err.status(), StatusCode::NOT_FOUND);
}
}