use axum::extract::State;
use axum::http::{StatusCode, Uri};
use axum::response::{IntoResponse, Response};
use did_hosting_common::server::mnemonic::validate_mnemonic;
use tracing::debug;
use crate::error::AppError;
use crate::server::AppState;
use crate::watcher_ops::{self, WatcherRecord};
async fn serve_content(
state: &AppState,
mnemonic: &str,
key: &str,
content_type: &str,
) -> Result<Response, AppError> {
if let Some(record) = state
.dids_ks
.get::<WatcherRecord>(watcher_ops::did_key(mnemonic))
.await?
&& record.disabled
{
return Err(AppError::NotFound(format!("content not found: {mnemonic}")));
}
let content = state
.dids_ks
.get_raw(key)
.await?
.ok_or_else(|| AppError::NotFound(format!("content not found: {mnemonic}")))?;
debug!(mnemonic = %mnemonic, size = content.len(), content_type, "content resolved");
let cache_control = state.config.server.resolve_cache.header_value();
Ok((
StatusCode::OK,
[
("content-type", content_type),
("cache-control", cache_control.as_str()),
],
content,
)
.into_response())
}
pub async fn serve_root_did_log(State(state): State<AppState>) -> Result<Response, AppError> {
serve_content(
&state,
".well-known",
"content:.well-known:log",
"application/jsonl+json",
)
.await
}
pub async fn serve_root_witness(State(state): State<AppState>) -> Result<Response, AppError> {
serve_content(
&state,
".well-known",
"content:.well-known:witness",
"application/json",
)
.await
}
pub async fn serve_public(State(state): State<AppState>, uri: Uri) -> Response {
let path = uri.path().trim_start_matches('/');
if let Some(mnemonic) = path.strip_suffix("/did.jsonl")
&& !mnemonic.is_empty()
{
if let Err(e) = validate_mnemonic(mnemonic) {
return e.into_response();
}
let key = format!("content:{mnemonic}:log");
return match serve_content(&state, mnemonic, &key, "application/jsonl+json").await {
Ok(resp) => resp,
Err(e) => e.into_response(),
};
}
if let Some(mnemonic) = path.strip_suffix("/did-witness.json")
&& !mnemonic.is_empty()
{
if let Err(e) = validate_mnemonic(mnemonic) {
return e.into_response();
}
let key = format!("content:{mnemonic}:witness");
return match serve_content(&state, mnemonic, &key, "application/json").await {
Ok(resp) => resp,
Err(e) => e.into_response(),
};
}
StatusCode::NOT_FOUND.into_response()
}