hyper_static_server/
runtime_sitemaps.rs

1
2
3use crate::hss;
4
5
6#[ allow (unused_imports) ]
7use ::std::{
8		
9		str::FromStr as _,
10		
11	};
12
13
14#[ allow (unused_imports) ]
15use crate::hss::{
16		
17		ResponseExt as _,
18		
19		ResultExtWrap as _,
20		ResultExtPanic as _,
21		
22	};
23
24
25use crate::runtime::{
26		
27		StaticResource,
28		
29	};
30
31
32
33pub enum SitemapFormat {
34	#[ cfg (feature = "runtime-sitemaps-xml") ]
35	Xml,
36	Text,
37}
38
39
40pub enum SitemapFrequency {
41	Always,
42	Hourly,
43	Daily,
44	Weekly,
45	Monthly,
46	Yearly,
47	Never,
48}
49
50
51pub struct SitemapPriority (f32);
52
53
54
55
56impl SitemapFormat {
57	
58	pub fn from_str (_string : &str) -> hss::ServerResult<Self> {
59		match _string {
60			#[ cfg (feature = "runtime-sitemaps-xml") ]
61			"xml" => Ok (Self::Xml),
62			"text" => Ok (Self::Text),
63			_ => hss::fail_with_code! (0xdf9d3bb7),
64		}
65	}
66	
67	pub fn from_str_must (_string : &str) -> Self {
68		Self::from_str (_string) .or_panic (0x685370b7)
69	}
70}
71
72
73
74
75impl SitemapFrequency {
76	
77	pub fn from_str (_string : &str) -> hss::ServerResult<Option<Self>> {
78		match _string {
79			"default" => Ok (None),
80			"always" => Ok (Some (Self::Always)),
81			"hourly" => Ok (Some (Self::Hourly)),
82			"daily" => Ok (Some (Self::Daily)),
83			"weekly" => Ok (Some (Self::Weekly)),
84			"monthly" => Ok (Some (Self::Monthly)),
85			"yearly" => Ok (Some (Self::Yearly)),
86			"never" => Ok (Some (Self::Never)),
87			_ => hss::fail_with_code! (0xb2001a05),
88		}
89	}
90	
91	pub fn from_str_must (_string : &str) -> Option<Self> {
92		Self::from_str (_string) .or_panic (0x256f6fc2)
93	}
94}
95
96
97impl SitemapPriority {
98	
99	pub fn to_f32 (&self) -> f32 {
100		self.0
101	}
102	
103	pub fn from_str (_string : &str) -> hss::ServerResult<Option<Self>> {
104		match _string {
105			"default" =>
106				Ok (None),
107			_ =>
108				Self::from_f32 (f32::from_str (_string) .or_wrap (0x1dd1e4e7) ?)
109		}
110	}
111	
112	pub fn from_f32 (_value : f32) -> hss::ServerResult<Option<Self>> {
113		if _value < 0.0 {
114			hss::fail_with_code! (0x55b5a84b);
115		}
116		if _value > 1.0 {
117			hss::fail_with_code! (0xa233806b);
118		}
119		Ok (Some (Self (_value)))
120	}
121	
122	pub fn from_str_must (_string : &str) -> Option<Self> {
123		Self::from_str (_string) .or_panic (0xfe4be058)
124	}
125	
126	pub fn from_f32_must (_value : f32) -> Option<Self> {
127		Self::from_f32 (_value) .or_panic (0x004c83da)
128	}
129}
130
131
132
133
134pub struct RouteSitemapEntry {
135	pub included : Option<bool>,
136	pub frequency : Option<SitemapFrequency>,
137	pub priority : Option<SitemapPriority>,
138}
139
140
141impl RouteSitemapEntry {
142	
143	pub fn new () -> Self {
144		Self {
145				included : None,
146				frequency : None,
147				priority : None,
148			}
149	}
150}
151
152
153
154
155pub struct RoutesSitemapResource {
156	prefix : String,
157	format : SitemapFormat,
158	routes : Option<hss::Routes>,
159}
160
161
162impl RoutesSitemapResource {
163	
164	pub fn new (_prefix : String, _format : SitemapFormat, _extensions : Option<&hss::Extensions>) -> hss::ServerResult<Self> {
165		Self::new_with_routes (_prefix, _format, None, _extensions)
166	}
167	
168	#[ cfg (feature = "runtime-sitemaps-xml") ]
169	pub fn new_xml (_prefix : String, _extensions : Option<&hss::Extensions>) -> hss::ServerResult<Self> {
170		Self::new (_prefix, SitemapFormat::Xml, _extensions)
171	}
172	
173	pub fn new_text (_prefix : String, _extensions : Option<&hss::Extensions>) -> hss::ServerResult<Self> {
174		Self::new (_prefix, SitemapFormat::Text, _extensions)
175	}
176	
177	pub fn new_with_routes (_prefix : String, _format : SitemapFormat, _routes : Option<hss::Routes>, _extensions : Option<&hss::Extensions>) -> hss::ServerResult<Self> {
178		let _self = Self {
179				prefix : _prefix,
180				format : _format,
181				routes : _routes,
182			};
183		Ok (_self)
184	}
185	
186	pub fn into_handler (self) -> impl hss::Handler {
187		hss::HandlerSimpleSyncWrapper::new (self)
188	}
189}
190
191
192impl StaticResource for RoutesSitemapResource {
193	
194	fn content_type (&self) -> hss::ContentType {
195		match self.format {
196			#[ cfg (feature = "runtime-sitemaps-xml") ]
197			SitemapFormat::Xml =>
198				hss::ContentType::Xml,
199			SitemapFormat::Text =>
200				hss::ContentType::Text,
201		}
202	}
203	
204	fn description (&self) -> &'static str {
205		match self.format {
206			#[ cfg (feature = "runtime-sitemaps-xml") ]
207			SitemapFormat::Xml =>
208				"sitemap (xml)",
209			SitemapFormat::Text =>
210				"sitemap (text)",
211		}
212	}
213	
214	fn into_handler_dyn (self) -> hss::HandlerDynArc {
215		let _handler = self.into_handler ();
216		let _handler = hss::HandlerDynArc::new (_handler);
217		_handler
218	}
219}
220
221
222impl hss::HandlerSimpleSync for RoutesSitemapResource {
223	
224	fn handle (&self, _request : &hss::Request<hss::Body>, _response : &mut hss::Response<hss::Body>) -> hss::ServerResult {
225		
226		let _routes = if let Some (_routes) = &self.routes {
227			_routes.clone ()
228		} else if let Some (_route_matched) = _request.extensions () .get::<hss::RouteMatched> () {
229			_route_matched.routes.clone ()
230		} else if let Some (_routes) = _request.extensions () .get::<hss::Routes> () {
231			_routes.clone ()
232		} else {
233			hss::fail_with_code! (0xee535008);
234		};
235		
236		let mut _sitemap_routes = Vec::new ();
237		let mut _url_buffer = String::with_capacity (128);
238		for _route in _routes.routes () {
239			if let Some (_entry) = _route.extensions.get::<RouteSitemapEntry> () {
240				if _entry.included.unwrap_or (true) {
241					_url_buffer.clear ();
242					_url_buffer.push_str (self.prefix.trim_end_matches ("/"));
243					_url_buffer.push_str ("/");
244					_url_buffer.push_str (_route.path.trim_start_matches ("/"));
245					let _url = ::url::Url::from_str (&_url_buffer) .or_wrap (0x270667a5) ?;
246					_sitemap_routes.push ((_url, _entry));
247				}
248			}
249		}
250		drop (_url_buffer);
251		
252		let (_body, _content_type) = match self.format {
253			
254			#[ cfg (feature = "runtime-sitemaps-xml") ]
255			SitemapFormat::Xml => {
256				let mut _entries = Vec::with_capacity (_sitemap_routes.len ());
257				for (_route_url, _route_entry) in _sitemap_routes {
258					let mut _builder = ::sitewriter::UrlEntryBuilder::default ();
259					_builder.loc (_route_url);
260					if let Some (_frequency) = _route_entry.frequency.as_ref () {
261						let _frequency = match _frequency {
262							SitemapFrequency::Always => ::sitewriter::ChangeFreq::Always,
263							SitemapFrequency::Hourly => ::sitewriter::ChangeFreq::Hourly,
264							SitemapFrequency::Daily => ::sitewriter::ChangeFreq::Daily,
265							SitemapFrequency::Weekly => ::sitewriter::ChangeFreq::Weekly,
266							SitemapFrequency::Monthly => ::sitewriter::ChangeFreq::Monthly,
267							SitemapFrequency::Yearly => ::sitewriter::ChangeFreq::Yearly,
268							SitemapFrequency::Never => ::sitewriter::ChangeFreq::Never,
269						};
270						_builder.changefreq (_frequency);
271					}
272					if let Some (_priority) = _route_entry.priority.as_ref () {
273						_builder.priority (_priority.to_f32 ());
274					}
275					let _entry = _builder.build () .or_wrap (0x155cdb8f) ?;
276					_entries.push (_entry);
277				}
278				let _buffer = ::sitewriter::generate_str (&_entries);
279				(_buffer, hss::ContentType::Xml)
280			}
281			
282			SitemapFormat::Text => {
283				let mut _buffer = String::with_capacity (16 * 1024);
284				for (_route_url, _route_entry) in _sitemap_routes {
285					_buffer.push_str (_route_url.as_str ());
286					_buffer.push_str ("\n");
287				}
288				(_buffer, hss::ContentType::Text)
289			}
290		};
291		
292		_response.set_status_200 ();
293		_response.set_content_type (_content_type);
294		_response.set_body (_body);
295		
296		Ok (())
297	}
298}
299