use async_trait::async_trait;
use axum::{extract::FromRequestParts, http::request::Parts};
pub const TENANT_ID_HEADER: &str = "X-Tenant-ID";
pub const ACT_AS_TENANT_HEADER: &str = "X-Act-As-Tenant";
fn header_value(parts: &Parts, name: &str) -> Option<String> {
parts
.headers
.get(name)
.and_then(|v: &axum::http::HeaderValue| v.to_str().ok())
.map(|s: &str| s.trim().to_string())
.filter(|s: &String| !s.is_empty())
}
#[derive(Clone, Debug)]
pub struct TenantId(pub Option<String>);
#[async_trait]
impl<S> FromRequestParts<S> for TenantId
where
S: Send + Sync,
{
type Rejection = std::convert::Infallible;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
Ok(TenantId(header_value(parts, TENANT_ID_HEADER)))
}
}
#[derive(Clone, Debug)]
pub struct ActAsTenant(pub Option<String>);
#[async_trait]
impl<S> FromRequestParts<S> for ActAsTenant
where
S: Send + Sync,
{
type Rejection = std::convert::Infallible;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
Ok(ActAsTenant(header_value(parts, ACT_AS_TENANT_HEADER)))
}
}