use bytes::Bytes;
use http::{HeaderValue, Response, StatusCode};
use serde_json::json;
#[derive(Clone, Debug, thiserror::Error)]
#[error("{error}: {detail}")]
pub struct AAuthError {
pub status: StatusCode,
pub error: String,
pub detail: String,
pub headers: Vec<(&'static str, String)>,
}
impl AAuthError {
pub fn new(status: StatusCode, error: impl Into<String>, detail: impl Into<String>) -> Self {
Self {
status,
error: error.into(),
detail: detail.into(),
headers: Vec::new(),
}
}
pub(crate) fn invalid_request(detail: impl Into<String>) -> Self {
Self::new(StatusCode::BAD_REQUEST, "invalid_request", detail)
}
pub(crate) fn forbidden(detail: impl Into<String>) -> Self {
Self::new(StatusCode::FORBIDDEN, "invalid_request", detail)
}
pub(crate) fn mission_terminated(detail: impl Into<String>) -> Self {
Self::new(StatusCode::FORBIDDEN, "mission_terminated", detail)
}
pub(crate) fn mission_not_found() -> Self {
Self::new(
StatusCode::NOT_FOUND,
"mission_not_found",
"no such mission",
)
}
pub(crate) fn signature(code: &str, detail: impl Into<String>) -> Self {
let mut error = Self::new(StatusCode::UNAUTHORIZED, code, detail);
error
.headers
.push(("signature-error", format!("error={code}")));
error
}
pub fn into_response(self) -> Response<Bytes> {
let mut response = problem(self.status, &self.error, Some(&self.detail));
for (name, value) in self.headers {
if let Ok(value) = HeaderValue::from_str(&value) {
response.headers_mut().insert(name, value);
}
}
response
}
}
impl From<crate::store::StoreError> for AAuthError {
fn from(error: crate::store::StoreError) -> Self {
Self::new(
StatusCode::SERVICE_UNAVAILABLE,
"temporarily_unavailable",
error.to_string(),
)
}
}
pub fn problem(status: StatusCode, error: &str, detail: Option<&str>) -> Response<Bytes> {
let mut body = json!({ "error": error });
if let Some(detail) = detail.filter(|d| !d.is_empty()) {
body["detail"] = json!(detail);
}
let mut response = Response::new(Bytes::from(body.to_string()));
*response.status_mut() = status;
response.headers_mut().insert(
"content-type",
HeaderValue::from_static("application/problem+json"),
);
response
}