credence_lib/configuration/
credence.rs1use super::{
2 super::{middleware::*, util::*},
3 caching::*,
4 encoding::*,
5 error::*,
6 files::*,
7 port::*,
8 render::*,
9 requests::*,
10 urls::*,
11};
12
13use {
14 compris::{annotate::*, normal::*, parse::*, resolve::*, *},
15 kutil::{
16 cli::depict::*,
17 http::{
18 cache::{Cache, CommonCacheKey},
19 tower::caching::*,
20 *,
21 },
22 std::immutable::*,
23 },
24 std::{collections::*, io, path::*},
25};
26
27#[derive(Clone, Debug, Depict, Resolve)]
33pub struct CredenceConfiguration {
34 #[resolve]
36 #[depict(skip)]
37 pub definitions: Option<Variant<WithoutAnnotations>>,
38
39 #[resolve]
41 #[depict(as(depict))]
42 pub files: FilesConfiguration,
43
44 #[resolve]
46 #[depict(iter(kv), key_style(number), as(depict))]
47 pub ports: BTreeMap<u16, Port>,
48
49 #[resolve]
51 #[depict(as(depict))]
52 pub requests: RequestsConfiguration,
53
54 #[resolve]
56 #[depict(as(depict))]
57 pub urls: UrlsConfiguration,
58
59 #[resolve]
61 #[depict(as(depict))]
62 pub render: RenderConfiguration,
63
64 #[resolve]
66 #[depict(as(depict))]
67 pub caching: CachingConfiguration,
68
69 #[resolve]
71 #[depict(as(depict))]
72 pub encoding: EncodingConfiguration,
73}
74
75impl CredenceConfiguration {
76 pub fn read<ReadT>(reader: &mut ReadT, source: ByteString) -> Result<Self, ConfigurationError>
78 where
79 ReadT: io::Read,
80 {
81 let variant = with_annotations!(
82 Parser::new(Format::YAML)
83 .with_source(source)
84 .with_try_unsigned_integers(true)
85 .parse_reader(reader)
86 .map_err(io::Error::other)?
87 );
88
89 let mut errors = ResolveErrors::default();
90 let configuration = variant.resolve_with_errors(&mut errors).map_err(io::Error::other)?;
91 if errors.is_empty() { Ok(configuration.ok_or(ConfigurationError::None)?) } else { Err(errors.into()) }
92 }
93
94 pub fn validate<PathT>(&mut self, base_path: PathT) -> Result<(), ConfigurationError>
96 where
97 PathT: AsRef<Path>,
98 {
99 for port in &mut self.ports.values_mut() {
100 port.validate(&base_path)?;
101 }
102
103 self.files.validate(base_path)
104 }
105
106 pub fn caching_layer<RequestBodyT, CacheT>(
108 &self,
109 cache: CacheT,
110 ) -> CachingLayer<RequestBodyT, CacheT, CommonCacheKey>
111 where
112 CacheT: Cache<CommonCacheKey>,
113 {
114 let skip_media_types = self.encoding.skip_media_types();
116
117 CachingLayer::default()
118 .cache(cache.clone())
119 .cacheable_by_default(self.caching.default)
120 .cache_key(|context| {
121 if let Some(socket) = context.request.extensions().get::<Socket>() {
122 context.cache_key.host = Some(socket.host.clone());
123 }
124 })
125 .min_cacheable_body_size(self.caching.min_body_size.inner.into())
126 .max_cacheable_body_size(self.caching.max_body_size.inner.into())
127 .min_encodable_body_size(self.encoding.min_body_size.inner.into())
128 .encodable_by_default(self.encoding.default)
129 .encodable_by_response(move |context| match context.headers.content_type() {
130 Some(content_type) => !skip_media_types.contains(&content_type),
131 None => true,
132 })
133 }
134
135 pub fn hide(&self, uri_path: &str) -> bool {
137 if uri_path_has_hidden_segment(uri_path) {
138 return true;
139 }
140
141 for hide in &self.urls.hide {
142 if hide.inner.is_match(uri_path) {
143 return true;
144 }
145 }
146
147 self.render.is_rendered_page(uri_path).is_some()
148 }
149
150 pub fn rendered_page_uri_path(&self, uri_path: &str) -> io::Result<Option<String>> {
154 let asset_path = self.files.asset(uri_path);
155 if let Some(base_file_name) = asset_path.file_name()
156 && let Some(parent) = asset_path.parent()
157 && parent.is_dir()
158 {
159 let base_file_name = base_file_name.to_string_lossy().into_owned() + &self.render.midfix;
160 for file_path in parent.read_dir()? {
161 let file_path = file_path?.path();
162 if let Some(file_name) = file_path.file_name() {
163 let file_name = file_name.to_string_lossy();
164 if file_name.starts_with(&base_file_name) {
165 let extension = &file_name[base_file_name.len()..];
166 return Ok(Some(String::from(uri_path) + &self.render.midfix + extension));
167 }
168 }
169 }
170 }
171
172 Ok(None)
173 }
174}
175
176impl Default for CredenceConfiguration {
177 fn default() -> Self {
178 let mut port = Port::default();
179 port.name = "http".into();
180
181 Self {
182 files: Default::default(),
183 ports: BTreeMap::from([(8000, port)]),
184 requests: Default::default(),
185 caching: Default::default(),
186 encoding: Default::default(),
187 render: Default::default(),
188 urls: Default::default(),
189 definitions: None,
190 }
191 }
192}