From 558c4078fd6b5c10bfbcac826774335904807e39 Mon Sep 17 00:00:00 2001 From: Vika Date: Sat, 28 May 2022 21:05:19 +0300 Subject: feat: group endpoints under `.kittybox` Actually got the idea from https://xeiaso.net/, who groups xer website's endpoints under the `.within` folder. --- kittybox-rs/src/frontend/onboarding.js | 2 +- kittybox-rs/src/main.rs | 101 +++++++++++++------------------- kittybox-rs/templates/src/onboarding.rs | 6 +- kittybox-rs/templates/src/templates.rs | 8 ++- 4 files changed, 50 insertions(+), 67 deletions(-) (limited to 'kittybox-rs') diff --git a/kittybox-rs/src/frontend/onboarding.js b/kittybox-rs/src/frontend/onboarding.js index 89ad84a..c5a1481 100644 --- a/kittybox-rs/src/frontend/onboarding.js +++ b/kittybox-rs/src/frontend/onboarding.js @@ -75,7 +75,7 @@ form.onsubmit = async (event) => { }).filter(feed => feed.name == "" || feed.slug == "") }; - await fetch("/onboarding", { + await fetch("/.kittybox/onboarding", { method: "POST", body: JSON.stringify(json), headers: { "Content-Type": "application/json" } diff --git a/kittybox-rs/src/main.rs b/kittybox-rs/src/main.rs index eb70885..fd1875c 100644 --- a/kittybox-rs/src/main.rs +++ b/kittybox-rs/src/main.rs @@ -25,6 +25,7 @@ async fn main() { std::process::exit(1); } }; + let token_endpoint: Url = match env::var("TOKEN_ENDPOINT") { Ok(val) => { debug!("Token endpoint: {}", val); @@ -41,6 +42,7 @@ async fn main() { std::process::exit(1) } }; + let authorization_endpoint: Url = match env::var("AUTHORIZATION_ENDPOINT") { Ok(val) => { debug!("Auth endpoint: {}", val); @@ -58,32 +60,6 @@ async fn main() { } }; - //let internal_token: Option = env::var("KITTYBOX_INTERNAL_TOKEN").ok(); - - /*let cookie_secret: String = match env::var("COOKIE_SECRET").ok() { - Some(value) => value, - None => { - if let Ok(filename) = env::var("COOKIE_SECRET_FILE") { - use tokio::io::AsyncReadExt; - - let mut file = tokio::fs::File::open(filename).await.map_err(|e| { - error!("Couldn't open the cookie secret file: {}", e); - std::process::exit(1); - }).unwrap(); - let mut temp_string = String::new(); - file.read_to_string(&mut temp_string).await.map_err(|e| { - error!("Couldn't read the cookie secret from file: {}", e); - std::process::exit(1); - }).unwrap(); - - temp_string - } else { - error!("COOKIE_SECRET or COOKIE_SECRET_FILE is not set, will not be able to log in users securely!"); - std::process::exit(1); - } - } - };*/ - let listen_at = match env::var("SERVE_AT") .ok() .unwrap_or_else(|| "[::]:8080".to_string()) @@ -115,7 +91,6 @@ async fn main() { println!("The Redis backend is deprecated."); std::process::exit(1); } else if backend_uri.starts_with("file") { - let database = { let folder = backend_uri.strip_prefix("file://").unwrap(); let path = std::path::PathBuf::from(folder); @@ -138,14 +113,6 @@ async fn main() { let homepage = warp::get() .and(warp::path::end()) .and(kittybox::frontend::homepage(database.clone(), endpoints.clone())); - - let onboarding = warp::path("onboarding") - .and(warp::path::end()) - .and(kittybox::frontend::onboarding( - database.clone(), - endpoints.clone(), - http.clone() - )); let micropub = warp::path("micropub") .and(warp::path::end() @@ -159,68 +126,82 @@ async fn main() { .and(warp::path::end()) .map(|| warp::reply::html(kittybox::MICROPUB_CLIENT)))); + let static_files = warp::path("static") + .and(kittybox::frontend::static_files()); + let media = warp::path("media") .and(warp::path::end() .and(kittybox::media::media()) .or(kittybox::util::require_host() .and(warp::path::param()) .map(|_host: Authority, path: String| format!("media file {}", path)))); - - // TODO remember how login logic works because I forgor - let login = warp::path("login") - .and(warp::path("callback") - .map(|| "callback!") - // TODO form on GET and handler on POST - .or(warp::path::end().map(|| "login page!"))); + + let technical = warp::path(".kittybox") + .and(warp::path("onboarding") + .and(warp::path::end()) + .and(kittybox::frontend::onboarding( + database.clone(), + endpoints.clone(), + http.clone() + )) + .or(warp::path("health") + .and(warp::path::end()) + .and(warp::get()) + // TODO make healthcheck report on database status too + .map(|| "OK")) + .or(warp::path("metrics") + .and(warp::path::end()) + .and(warp::get()) + .map(kittybox::metrics::gather)) + .or(micropub) + .or(media) + .or(static_files) + .or(warp::path("login") + .and(warp::path("callback") + .map(|| "callback!") + // TODO form on GET and handler on POST + .or(warp::path::end() + .map(|| "login page!")) + ) + ) + ); // TODO prettier error response let coffee = warp::path("coffee") .map(|| warp::reply::with_status("I'm a teapot!", warp::http::StatusCode::IM_A_TEAPOT)); - let static_files = warp::path("static") - .and(kittybox::frontend::static_files()); - let catchall = kittybox::frontend::catchall( database.clone(), endpoints.clone() ); - let health = warp::path("health").and(warp::path::end()).map(|| "OK"); - let metrics = warp::path("metrics").and(warp::path::end()).map(kittybox::metrics::gather); - let app = homepage - .or(onboarding) - .or(metrics - .or(health)) - .or(static_files) - .or(login) + .or(technical) .or(coffee) - .or(micropub) - .or(media) .or(catchall) .with(warp::log("kittybox")) .with(kittybox::metrics::metrics(vec![ - "health".to_string(), - "micropub".to_string(), - "static".to_string(), - "media".to_string(), - "metrics".to_string() + ".kittybox".to_string() ])) ; let svc = warp::service(app); + // A little dance to turn a potential file descriptor into an async network socket let mut listenfd = listenfd::ListenFd::from_env(); let tcp_listener: std::net::TcpListener = if let Ok(Some(listener)) = listenfd.take_tcp_listener(0) { listener } else { std::net::TcpListener::bind(listen_at).unwrap() }; + // Set the socket to non-blocking so tokio can work with it properly + // This is the async magic tcp_listener.set_nonblocking(true).unwrap(); info!("Listening on {}", tcp_listener.local_addr().unwrap()); let server = hyper::server::Server::from_tcp(tcp_listener) .unwrap() + // Otherwise Chrome keeps connections open for too long .tcp_keepalive(Some(Duration::from_secs(30 * 60))) .serve(hyper::service::make_service_fn(move |_| { let service = svc.clone(); diff --git a/kittybox-rs/templates/src/onboarding.rs b/kittybox-rs/templates/src/onboarding.rs index 9d0f2e1..5a9f226 100644 --- a/kittybox-rs/templates/src/onboarding.rs +++ b/kittybox-rs/templates/src/onboarding.rs @@ -3,8 +3,8 @@ markup::define! { h1[style="text-align: center"] { "Welcome to Kittybox" } - script[type="module", src="/static/onboarding.js"] {} - link[rel="stylesheet", href="/static/onboarding.css"]; + script[type="module", src="/.kittybox/static/onboarding.js"] {} + link[rel="stylesheet", href="/.kittybox/static/onboarding.css"]; form.onboarding[action="", method="POST"] { noscript { p { @@ -23,7 +23,7 @@ markup::define! { "Good news though - the code is " b { "open-source AND free software" } " (under GNU AGPLv3) " "and I promise to not obfuscate it or minify it. " - a[href="/static/onboarding.js"] { "Here" } + a[href="/.kittybox/static/onboarding.js"] { "Here" } "'s the link - you can try reading it so you'll be 200% sure " "it won't steal your cookies or turn your kitty into a soulless monster." @markup::raw("") diff --git a/kittybox-rs/templates/src/templates.rs b/kittybox-rs/templates/src/templates.rs index 0054c91..b084fbd 100644 --- a/kittybox-rs/templates/src/templates.rs +++ b/kittybox-rs/templates/src/templates.rs @@ -29,10 +29,12 @@ markup::define! { head { title { @title } link[rel="preconnect", href="https://fonts.gstatic.com"]; - link[rel="stylesheet", href="/static/style.css"]; + link[rel="stylesheet", href="/.kittybox/static/style.css"]; meta[name="viewport", content="initial-scale=1, width=device-width"]; - // TODO: link rel= for common IndieWeb APIs: webmention, microsub - link[rel="micropub", href="/micropub"]; // Static, because it's built into the server itself + // Static, because it's built into the server itself + link[rel="micropub", href="/.kittybox/micropub"]; + link[rel="micropub_media", href="/.kittybox/media"]; + // TODO change this once neccesary endpoints are implemented @if let Some(endpoints) = endpoints { link[rel="authorization_endpoint", href=&endpoints.authorization_endpoint]; link[rel="token_endpoint", href=&endpoints.token_endpoint]; -- cgit 1.4.1