use std::{collections::HashMap, fmt::Display};
use axum::{
extract::{FromRequestParts, Query},
http::{request::Parts, StatusCode},
response::{IntoResponse, Response},
RequestPartsExt,
};
use pubky_common::crypto::PublicKey;
use crate::shared::parse_bool;
#[derive(Debug, Clone)]
pub struct PubkyHost(pub(crate) PublicKey);
impl PubkyHost {
pub fn public_key(&self) -> &PublicKey {
&self.0
}
}
impl Display for PubkyHost {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<S> FromRequestParts<S> for PubkyHost
where
S: Sync + Send,
{
type Rejection = Response;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
let pubky_host = parts
.extensions
.get::<PubkyHost>()
.cloned()
.ok_or((
StatusCode::INTERNAL_SERVER_ERROR,
"Can't extract PubkyHost. Is `PubkyHostLayer` enabled?",
))
.map_err(|e| e.into_response())?;
Ok(pubky_host)
}
}
#[derive(Debug, Clone)]
pub struct ListQueryParams {
pub limit: Option<u16>,
pub cursor: Option<String>,
pub shallow: bool,
pub reverse: bool,
}
impl ListQueryParams {
pub fn extract_cursor(params: &Query<HashMap<String, String>>) -> Option<String> {
let value = params.get("cursor")?;
if value.is_empty() {
return None;
}
let mut value = value.as_str();
if let Some(stripped_value) = value.strip_prefix("pubky://") {
value = stripped_value;
}
Some(value.to_string())
}
}
impl<S> FromRequestParts<S> for ListQueryParams
where
S: Send + Sync,
{
type Rejection = Response;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
let params: Query<HashMap<String, String>> =
parts.extract().await.map_err(IntoResponse::into_response)?;
let reverse = if let Some(reverse) = params.get("reverse") {
parse_bool(reverse).map_err(|e| *e)?
} else {
false
};
let shallow = if let Some(shallow) = params.get("shallow") {
parse_bool(shallow).map_err(|e| *e)?
} else {
false
};
let limit = params
.get("limit")
.and_then(|l| if l.is_empty() { None } else { Some(l) })
.and_then(|l| l.parse::<u16>().ok());
let cursor = Self::extract_cursor(¶ms);
Ok(ListQueryParams {
shallow,
limit,
cursor,
reverse,
})
}
}