use axum::{body::Body, http::Request};
use std::sync::Arc;
use tower::{Layer, Service};
use crate::HumusQuerySettings;
use crate::language::LanguageManifest;
use crate::language::UnicodeLanguageIdentifier;
use crate::middleware::format_extraction::extract_format_from_request_accept_header;
use crate::middleware::format_extraction::extract_format_from_request_uri;
use crate::middleware::format_extraction::extract_format_from_request_user_agent_header;
use crate::middleware::language_extraction::language_from_accept_language_header;
use crate::middleware::language_extraction::language_from_cookie;
use crate::templating::FormatChooser;
use crate::templating::HumusFormatIdentifier;
use crate::templating::TemplatesManifest;
#[derive(Debug, Clone)]
pub struct TemplateSettingsLayer {
templates_manifest: Arc<TemplatesManifest>,
language_manifest: Arc<LanguageManifest>,
format_chooser: Arc<FormatChooser>,
}
impl TemplateSettingsLayer {
pub fn new(
templates_manifest: TemplatesManifest,
language_manifest: LanguageManifest,
format_chooser: FormatChooser,
) -> Self {
Self {
templates_manifest: Arc::new(templates_manifest),
language_manifest: Arc::new(language_manifest),
format_chooser: Arc::new(format_chooser),
}
}
}
impl<S> Layer<S> for TemplateSettingsLayer {
type Service = TemplateSettingsService<S>;
fn layer(&self, inner: S) -> Self::Service {
TemplateSettingsService {
templates_manifest: self.templates_manifest.clone(),
language_manifest: self.language_manifest.clone(),
format_chooser: self.format_chooser.clone(),
service: inner,
}
}
}
#[derive(Debug, Clone)]
pub struct TemplateSettingsService<S> {
templates_manifest: Arc<TemplatesManifest>,
format_chooser: Arc<FormatChooser>,
language_manifest: Arc<LanguageManifest>,
service: S,
}
impl<S> Service<Request<Body>> for TemplateSettingsService<S>
where
S: Service<Request<Body>>,
{
type Response = S::Response;
type Error = S::Error;
type Future = S::Future;
fn poll_ready(
&mut self,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
let mut best_language: Option<UnicodeLanguageIdentifier> = None;
if let Some(language) = language_from_cookie(&req, &self.language_manifest) {
best_language = Some(language);
} else if let Some(language) =
language_from_accept_language_header(&req, &self.language_manifest)
{
best_language = Some(language);
}
let format_id = if let Some(id) = extract_format_from_request_uri(&req) {
id
} else if let Some(id) =
extract_format_from_request_accept_header(&req, &self.format_chooser)
{
id
} else if let Some(id) =
extract_format_from_request_user_agent_header(&req, &self.format_chooser)
{
id
} else {
self.templates_manifest.default_format
};
req.extensions_mut().insert(TemplateSetting {
language: best_language,
format: format_id,
});
self.service.call(req)
}
}
#[derive(Debug, Clone)]
pub struct TemplateSetting {
pub language: Option<UnicodeLanguageIdentifier>,
pub format: HumusFormatIdentifier,
}
impl HumusQuerySettings for TemplateSetting {
fn get_format(&self) -> HumusFormatIdentifier {
self.format
}
fn get_preferred_language(&self) -> Option<UnicodeLanguageIdentifier> {
self.language.clone()
}
}