use std::borrow::Cow; use std::io::Cursor; use std::ops::Deref; use std::sync::Arc; use tiny_http::Header; use tiny_http::Request; use tiny_http::Response; use tiny_http::Server; use tiny_http::StatusCode; pub fn go(domains: &[&str]) { let server = Server::http("0.0.0.0:3243").unwrap(); let server = Arc::new(server); for req in server.incoming_requests() { let route = Route::parse_request(&req); let resp = route.render(domains); if let Err(e) = req.respond(resp) { eprintln!("WARN: {}", e); } } } pub enum Route<'a> { Next(&'a str), Prev(&'a str), NotFound, } pub enum RuntimeStatic { JsonIndex, } impl<'a> Route<'a> { pub fn parse_request(r: &'a Request) -> Self { let segments: Vec<_> = r.url() .split('/') .filter(|s| !s.is_empty()) .collect(); // TODO automatically detect a fallback url from the request's Referer header let referrer_domain = segments.get(1).map(|s| *s).unwrap_or("missing_referrer_domain"); match segments.get(0).map(Deref::deref) { Some("next") => { Route::Next(referrer_domain) }, Some("prev") => { Route::Prev(referrer_domain) }, _ => Route::NotFound, } } pub fn render<'b>(&self, domains: &[&'b str]) -> Response>> { match self { Self::Next(this_domain) | Self::Prev(this_domain) => { let offset: isize = if let Self::Next(_) = self { 1 } else { -1 }; let destination = domains.iter() .position(|d| this_domain.starts_with(d)) .map(|i| (i as isize + offset).rem_euclid(domains.len() as isize)) .map(|i| domains[i as usize]); if let Some(url) = destination { let destination = format!( "https://{}", url ); Response::new( StatusCode(303), vec![ Header::from_bytes( b"Location".to_owned(), destination.as_bytes(), ).unwrap(), ], Cursor::new(Cow::Borrowed(b"")), Some(0), None, ) } else { let bytes = format!( "Misconfigured server. Website {} not found in webring.", this_domain, ); let blen = bytes.len(); Response::new( StatusCode(400), Vec::new(), Cursor::new(Cow::Owned(bytes.into_bytes())), Some(blen), None, ) } }, Self::NotFound => { Response::new( StatusCode(404), Vec::new(), Cursor::new(Cow::Borrowed(b"Page not found")), Some(14), None, ) } } } }