hyper_static_server/
exporter.rs

1
2
3
4
5use ::std::{
6		
7		io,
8		sync,
9		time,
10		
11		collections::HashSet,
12		
13		io::Write as _,
14		
15	};
16
17
18use ::cpio::newc as cpio;
19
20
21use crate::{
22		
23		StaticRouteDebug,
24		
25	};
26
27
28use crate::hss::{
29		
30		BodyExt as _,
31		ResponseExt as _,
32		
33		ResultExtWrap as _,
34		
35		fail_with_format,
36		
37	};
38
39
40use crate::hss;
41
42
43
44
45pub fn export_routes_debug (_routes : impl Into<hss::Routes>, _output : impl io::Write) -> hss::ServerResult {
46	
47	let mut _output = _output;
48	
49	let mut _consumer = |_route : &hss::Route, _content_type : hss::ContentType, _content_buffer : Vec<u8>| {
50			
51			if let Some (_debug) = _route.extensions.get::<StaticRouteDebug> () {
52				write! (_output, "**  {} -> {:?}\n", _route.path, _debug) .or_wrap (0x99260590) ?;
53			} else {
54				write! (_output, "**  {}\n", _route.path) .or_wrap (0xb7ff2169) ?;
55			}
56			
57			write! (_output, ">>  {} bytes of type `{}`;\n", _content_buffer.len (), _content_type.to_str ()) .or_wrap (0xaea1edf5) ?;
58			
59			Ok (())
60		};
61	
62	return export_routes_all (_routes, &mut _consumer);
63}
64
65
66
67
68pub fn export_routes_dump (_routes : impl Into<hss::Routes>, _route_path : &str, _output : impl io::Write) -> hss::ServerResult {
69	
70	let mut _output = _output;
71	
72	let mut _consumer = |_route : &hss::Route, _content_type : hss::ContentType, _content_buffer : Vec<u8>| {
73			_output.write_all (&_content_buffer) .or_wrap (0x2a238b7f)
74		};
75	
76	return export_routes_one (_routes, _route_path, &mut _consumer);
77}
78
79
80
81
82pub fn export_routes_cpio (_routes : impl Into<hss::Routes>, _output : impl io::Write) -> hss::ServerResult {
83	
84	let mut _output = _output;
85	
86	let _timestamp = time::SystemTime::now () .duration_since (time::UNIX_EPOCH) .or_wrap (0x9c419037) ?;
87	let _timestamp : u32 = _timestamp.as_secs () .try_into () .or_wrap (0x451e1667) ?;
88	
89	let mut _paths_seen = HashSet::new ();
90	let mut _folders = HashSet::new ();
91	
92	let mut _consumer = |_route : &hss::Route, _content_type : hss::ContentType, _content_buffer : Vec<u8>| {
93			
94			let _path = export_routes_cpio_path (_route, _content_type) ?;
95			let _content_size : u32 = _content_buffer.len () .try_into () .or_wrap (0xc3c8d6c2) ?;
96			
97			if _paths_seen.contains (&_path) {
98				eprintln! ("[ww] [94617879]  duplicate path encountered `{}`;  ignoring!", _path);
99			}
100			_paths_seen.insert (_path.clone ());
101			
102			{
103				let mut _folder = String::new ();
104				for _path_component in _path.split ('/') {
105					if ! _folder.is_empty () {
106						_folder.push ('/');
107					}
108					_folder.push_str (_path_component);
109					if _folder.len () == _path.len () {
110						break;
111					}
112					if _folders.contains (&_folder) {
113						continue;
114					}
115					if _paths_seen.contains (&_folder) {
116						eprintln! ("[ww] [fa649895]  duplicate path encountered `{}`;  ignoring!", _folder);
117					}
118					_folders.insert (_folder.clone ());
119					_paths_seen.insert (_folder.clone ());
120					cpio::Builder::new (&_folder)
121							.mode (0o755 | 0o040000)
122							.mtime (_timestamp)
123							.write (&mut _output, 0)
124							.finish () .or_wrap (0x0bfd8f69) ?
125						;
126				}
127			}
128			
129			let _cpio_entry = cpio::Builder::new (&_path)
130					.mode (0o644 | 0o100000)
131					.mtime (_timestamp)
132				;
133			let mut _cpio_entry = _cpio_entry.write (&mut _output, _content_size);
134			_cpio_entry.write_all (&_content_buffer) .or_wrap (0x29b49136) ?;
135			_cpio_entry.finish () .or_wrap (0x76be56bc) ?;
136			
137			Ok (())
138		};
139	
140	export_routes_all (_routes, &mut _consumer) ?;
141	
142	cpio::trailer (&mut _output) .or_wrap (0x4975bcae) ?;
143	
144	return Ok (());
145}
146
147
148
149
150fn export_routes_cpio_path (_route : &hss::Route, _content_type : hss::ContentType) -> hss::ServerResult<String> {
151	
152	if ! _route.path.starts_with ("/") || _route.path.is_empty () {
153		fail_with_format! (0xea316ecf, "failed resolving path for `{}` (missing `/` prefix)!", _route.path);
154	}
155	let mut _route_path = _route.path[1..].to_owned ();
156	
157	if _route_path.ends_with ("/") || _route_path.is_empty () {
158		match _content_type {
159			hss::ContentType::Text =>
160				_route_path.push_str ("index.txt"),
161			hss::ContentType::Html =>
162				_route_path.push_str ("index.html"),
163			hss::ContentType::Xml =>
164				_route_path.push_str ("index.xml"),
165			hss::ContentType::Json =>
166				_route_path.push_str ("index.json"),
167			_ =>
168				_route_path.push_str ("index.data"),
169		}
170	}
171	
172	let _extensions : &[&str] = match _content_type {
173		hss::ContentType::Text =>
174			&[".txt", ".text", ".md"],
175		hss::ContentType::Html =>
176			&[".html", ".htm", ".xhtml"],
177		hss::ContentType::Xml =>
178			&[".xml", ".xhtml"],
179		hss::ContentType::Json =>
180			&[".json"],
181		_ =>
182			&[],
183	};
184	
185	if ! _extensions.is_empty () {
186		let mut _has_extension = false;
187		for _extension in _extensions {
188			if _route_path.ends_with (_extension) {
189				_has_extension = true;
190				break;
191			}
192		}
193		if ! _has_extension {
194			_route_path.push_str (_extensions[0]);
195		}
196	}
197	
198	return Ok (_route_path);
199}
200
201
202
203
204pub fn export_routes_all <Consumer> (_routes : impl Into<hss::Routes>, _consumer : Consumer) -> hss::ServerResult
205	where
206		Consumer : FnMut (&hss::Route, hss::ContentType, Vec<u8>) -> hss::ServerResult,
207{
208	let _routes = _routes.into ();
209	let _runtime = hss::runtime_current_thread () ?;
210	
211	let mut _consumer = _consumer;
212	for _route in _routes.routes () {
213		export_route_resolve (&_routes, &_route.path, &mut _consumer, &_runtime) ?;
214	}
215	
216	return Ok (());
217}
218
219
220
221
222pub fn export_routes_one <Consumer> (_routes : impl Into<hss::Routes>, _route_path : &str, _consumer : Consumer) -> hss::ServerResult
223	where
224		Consumer : FnMut (&hss::Route, hss::ContentType, Vec<u8>) -> hss::ServerResult,
225{
226	let _routes = _routes.into ();
227	let _runtime = hss::runtime_current_thread () ?;
228	
229	export_route_resolve (&_routes, _route_path, _consumer, &_runtime) ?;
230	
231	return Ok (());
232}
233
234
235
236
237pub fn export_route_resolve <Consumer> (_routes : &hss::Routes, _route_path : &str, _consumer : Consumer, _runtime : &hss::Runtime) -> hss::ServerResult
238	where
239		Consumer : FnOnce (&hss::Route, hss::ContentType, Vec<u8>) -> hss::ServerResult,
240{
241	let _route_matched = match _routes.resolve (_route_path) {
242		Ok (Some (_route_matched)) =>
243			_route_matched,
244		Ok (None) =>
245			fail_with_format! (0xa712904b, "failed resolving route for `{}` (resolution failed)!", _route_path),
246		Err (_error) =>
247			fail_with_format! (0xea0e6963, "failed resolving route for `{}` (resolution failed)!  //  {}", _route_path, _error),
248	};
249	
250	return export_route_matched (_route_matched, _consumer, _runtime);
251}
252
253
254
255
256pub fn export_route_matched <Consumer> (_route_matched : hss::RouteMatched, _consumer : Consumer, _runtime : &hss::Runtime) -> hss::ServerResult
257	where
258		Consumer : FnOnce (&hss::Route, hss::ContentType, Vec<u8>) -> hss::ServerResult,
259{
260	let _route = _route_matched.route.clone ();
261	
262	let (_content_type, _content_buffer) = export_route_matched_0 (_route_matched, &_runtime) ?;
263	
264	_consumer (&_route, _content_type, _content_buffer) ?;
265	
266	return Ok (());
267}
268
269
270
271
272pub fn export_route_matched_0 (_route_matched : hss::RouteMatched, _runtime : &hss::Runtime) -> hss::ServerResult<(hss::ContentType, Vec<u8>)> {
273	
274	let _route = sync::Arc::clone (&_route_matched.route);
275	
276	let _request = hss::Request::get (_route.path.clone ()) .body (hss::Body::default ()) .or_wrap (0x5fbdc50e) ?;
277	
278	let _future = _route.handle (_request, _route_matched);
279	
280	let _response = match _runtime.block_on (_future) {
281		Ok (_response) =>
282			_response,
283		Err (_error) =>
284			fail_with_format! (0x349294f0, "failed generating response for `{}` (handling failed)!  //  {}", _route.path, _error),
285	};
286	
287	let _status = _response.status ();
288	let _content_type = _response.content_type_or_unknown ();
289	
290	let _body = match _status {
291		hss::consts::OK =>
292			_response.into_body (),
293		_ =>
294			fail_with_format! (0xbb5e6327, "failed generating response for `{}` (status {})!", _route.path, _status),
295	};
296	
297	let _buffer = match export_body (_body, _runtime) {
298		Ok (_buffer) =>
299			_buffer,
300		Err (_error) =>
301			fail_with_format! (0x622b887a, "failed generating response for `{}` (streaming failed)!  //  {}", _route.path, _error),
302	};
303	
304	return Ok ((_content_type, _buffer));
305}
306
307
308
309
310fn export_body (_body : hss::BodyDynBox, _runtime : &hss::Runtime) -> hss::ServerResult<Vec<u8>> {
311	
312	let mut _body = _body;
313	return _body.consume_to_vec (Some (_runtime));
314}
315