hyper_static_server/
runtime_sitemaps.rs1
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