lib_humus/middleware/
template_settings.rs1use axum::{body::Body, http::Request};
6use std::sync::Arc;
7use tower::{Layer, Service};
8
9use crate::HumusQuerySettings;
10use crate::language::LanguageManifest;
11use crate::language::UnicodeLanguageIdentifier;
12
13use crate::middleware::format_extraction::extract_format_from_request_accept_header;
14use crate::middleware::format_extraction::extract_format_from_request_uri;
15use crate::middleware::format_extraction::extract_format_from_request_user_agent_header;
16use crate::middleware::language_extraction::language_from_accept_language_header;
17use crate::middleware::language_extraction::language_from_cookie;
18use crate::templating::FormatChooser;
19use crate::templating::HumusFormatIdentifier;
20use crate::templating::TemplatesManifest;
21
22#[derive(Debug, Clone)]
28pub struct TemplateSettingsLayer {
29 templates_manifest: Arc<TemplatesManifest>,
30 language_manifest: Arc<LanguageManifest>,
31 format_chooser: Arc<FormatChooser>,
32}
33
34impl TemplateSettingsLayer {
35 pub fn new(
37 templates_manifest: TemplatesManifest,
38 language_manifest: LanguageManifest,
39 format_chooser: FormatChooser,
40 ) -> Self {
41 Self {
42 templates_manifest: Arc::new(templates_manifest),
43 language_manifest: Arc::new(language_manifest),
44 format_chooser: Arc::new(format_chooser),
45 }
46 }
47}
48
49impl<S> Layer<S> for TemplateSettingsLayer {
50 type Service = TemplateSettingsService<S>;
51
52 fn layer(&self, inner: S) -> Self::Service {
53 TemplateSettingsService {
54 templates_manifest: self.templates_manifest.clone(),
55 language_manifest: self.language_manifest.clone(),
56 format_chooser: self.format_chooser.clone(),
57 service: inner,
58 }
59 }
60}
61
62#[derive(Debug, Clone)]
74pub struct TemplateSettingsService<S> {
75 templates_manifest: Arc<TemplatesManifest>,
76 format_chooser: Arc<FormatChooser>,
77 language_manifest: Arc<LanguageManifest>,
78 service: S,
79}
80
81impl<S> Service<Request<Body>> for TemplateSettingsService<S>
82where
83 S: Service<Request<Body>>,
84{
85 type Response = S::Response;
86 type Error = S::Error;
87 type Future = S::Future;
88
89 fn poll_ready(
90 &mut self,
91 cx: &mut std::task::Context<'_>,
92 ) -> std::task::Poll<Result<(), Self::Error>> {
93 self.service.poll_ready(cx)
94 }
95
96 fn call(&mut self, mut req: Request<Body>) -> Self::Future {
97 let mut best_language: Option<UnicodeLanguageIdentifier> = None;
98
99 if let Some(language) = language_from_cookie(&req, &self.language_manifest) {
100 best_language = Some(language);
101 } else if let Some(language) =
102 language_from_accept_language_header(&req, &self.language_manifest)
103 {
104 best_language = Some(language);
105 }
106
107 let format_id = if let Some(id) = extract_format_from_request_uri(&req) {
108 id
109 } else if let Some(id) =
110 extract_format_from_request_accept_header(&req, &self.format_chooser)
111 {
112 id
113 } else if let Some(id) =
114 extract_format_from_request_user_agent_header(&req, &self.format_chooser)
115 {
116 id
117 } else {
118 self.templates_manifest.default_format
119 };
120
121 req.extensions_mut().insert(TemplateSetting {
123 language: best_language,
124 format: format_id,
125 });
126
127 self.service.call(req)
128 }
129}
130
131#[derive(Debug, Clone)]
146pub struct TemplateSetting {
147 pub language: Option<UnicodeLanguageIdentifier>,
150
151 pub format: HumusFormatIdentifier,
153}
154
155impl HumusQuerySettings for TemplateSetting {
156 fn get_format(&self) -> HumusFormatIdentifier {
157 self.format
158 }
159
160 fn get_preferred_language(&self) -> Option<UnicodeLanguageIdentifier> {
161 self.language.clone()
162 }
163}