use crate::client::Refusal;
use crate::door::http::Response;
use crate::serve::storage::Failure;
use serde::Serialize;
use serde_json::{json, value::RawValue};
#[derive(Serialize)]
pub(super) struct Receipted<'a> {
pub(super) code: &'a str,
pub(super) message: &'a str,
pub(super) path: Option<&'a str>,
pub(super) receipt: &'a RawValue,
}
pub(super) fn refused_by_store(refused: &Refusal) -> Response {
let status = store_status(&refused.code);
let response = refused.verified.as_ref().map_or_else(
|| {
Response::json(
status,
&json!({"code": refused.code, "message": refused.message, "path": refused.path}),
)
},
|receipt| {
with_receipt(
status,
&Receipted {
code: &refused.code,
message: &refused.message,
path: refused.path.as_deref(),
receipt: receipt.raw(),
},
)
},
);
retry_after(response, status)
}
fn store_status(code: &str) -> u16 {
match code {
"busy"
| "busy_max_clients"
| "storage_unavailable"
| "writer_unavailable"
| "lys_could_not_be_asked"
| "lys_keys_pending"
| "busy_pending_signins" => 503,
"permission_refused" | "held_for_approval" | "origin_refused" => 403,
code if code.ends_with("_access_refused") => 403,
"branch_missing"
| "branch_unknown"
| "collection_missing"
| "document_missing"
| "store_unknown"
| "route_unknown"
| "version_missing"
| "file_unknown"
| "relation_missing"
| "counts_branch_missing" => 404,
_ => 400,
}
}
fn retry_after(response: Response, status: u16) -> Response {
if status == 503 {
response.with("Retry-After", "1")
} else {
response
}
}
pub(super) fn with_receipt(status: u16, body: &Receipted<'_>) -> Response {
serde_json::to_vec(body).map_or_else(
|error| {
let message = format!(
"the store answered {}: {}; its receipt could not be written: {error}",
body.code, body.message
);
Response::json(
502,
&json!({"code": "receipt_output_failed", "message": message}),
)
},
|bytes| Response::new(status, "application/json", bytes),
)
}
pub(in crate::door) fn refusal(failure: Failure) -> Response {
let Failure { code, message, .. } = failure;
let status = match code.as_str() {
"session_unknown" | "session_expired" | "sign_in_state_unknown" => 401,
"origin_refused" => 403,
"route_unknown" | "store_unknown" => 404,
"method_refused" => 405,
_ => store_status(&code),
};
retry_after(
Response::json(status, &json!({"code": code, "message": message})),
status,
)
}