faery-ring/src/server.rs

115 lines
2.4 KiB
Rust

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<Cursor<Cow<'b, [u8]>>> {
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,
)
}
}
}
}