From 998ffd3e3ac85a38aec8fc15c7addd02fa1af9ae Mon Sep 17 00:00:00 2001 From: Vika Date: Sun, 6 Mar 2022 17:14:10 +0300 Subject: Restored most of the functionality (except onboarding and some queries) --- src/main.rs | 124 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 44 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index 261e8a2..3ce32af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ use log::{debug, error, info}; -use std::env; +use std::{convert::Infallible, env, time::Duration}; use http_types::Url; use hyper::client::{HttpConnector,connect::dns::GaiResolver}; use hyper_rustls::HttpsConnector; -use warp::{Filter, host::Authority, path::FullPath}; +use warp::{Filter, host::Authority}; #[tokio::main] -async fn main() -> Result<(), kittybox::database::StorageError> { +async fn main() { // TODO json logging in the future? let logger_env = env_logger::Env::new().filter_or("RUST_LOG", "info"); env_logger::init_from_env(logger_env); @@ -59,19 +59,23 @@ async fn main() -> Result<(), kittybox::database::StorageError> { } } - let media_endpoint: Option = env::var("MEDIA_ENDPOINT").ok(); + //let internal_token: Option = env::var("KITTYBOX_INTERNAL_TOKEN").ok(); - let internal_token: Option = env::var("KITTYBOX_INTERNAL_TOKEN").ok(); - - let cookie_secret: String = match env::var("COOKIE_SECRET").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?; + 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?; + 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 { @@ -79,12 +83,12 @@ async fn main() -> Result<(), kittybox::database::StorageError> { std::process::exit(1); } } - }; + };*/ - let host: std::net::SocketAddr = match env::var("SERVE_AT") + let listen_at = match env::var("SERVE_AT") .ok() - .unwrap_or_else(|| "0.0.0.0:8080".to_string()) - .parse() { + .unwrap_or_else(|| "[::]:8080".to_string()) + .parse::() { Ok(addr) => addr, Err(e) => { error!("Cannot parse SERVE_AT: {}", e); @@ -111,17 +115,27 @@ async fn main() -> Result<(), kittybox::database::StorageError> { let database = { let folder = backend_uri.strip_prefix("file://").unwrap(); let path = std::path::PathBuf::from(folder); - kittybox::database::FileStorage::new(path).await? + match kittybox::database::FileStorage::new(path).await { + Ok(db) => db, + Err(err) => { + error!("Error creating database: {:?}", err); + std::process::exit(1); + } + } }; + let endpoints = kittybox::frontend::IndiewebEndpoints { + authorization_endpoint: authorization_endpoint.to_string(), + token_endpoint: token_endpoint.to_string(), + webmention: None, + microsub: None, + }; + // TODO interpret HEAD - let homepage = kittybox::util::require_host() - .and(warp::get()) + let homepage = warp::get() .and(warp::path::end()) - // TODO fetch content from the database - // TODO parse content-type and determine appropriate response - .map(|host| format!("front page for {}!", host)); - + .and(kittybox::frontend::homepage(database.clone(), endpoints.clone())); + let micropub = warp::path("micropub") .and(warp::path::end() .and(kittybox::micropub::micropub( @@ -132,14 +146,14 @@ async fn main() -> Result<(), kittybox::database::StorageError> { .or(warp::get() .and(warp::path("client")) .and(warp::path::end()) - .map(|| kittybox::MICROPUB_CLIENT))); + .map(|| warp::reply::html(kittybox::MICROPUB_CLIENT)))); let media = warp::path("media") .and(warp::path::end() .and(kittybox::micropub::media::media()) .or(kittybox::util::require_host() .and(warp::path::param()) - .map(|host: Authority, path: String| format!("media file {}", path)))); + .map(|_host: Authority, path: String| format!("media file {}", path)))); // TODO remember how login logic works because I forgor let login = warp::path("login") @@ -152,40 +166,62 @@ async fn main() -> Result<(), kittybox::database::StorageError> { let coffee = warp::path("coffee") .map(|| warp::reply::with_status("I'm a teapot!", warp::http::StatusCode::IM_A_TEAPOT)); - // TODO interpret HEAD - let static_files = warp::get() - .and(warp::path!("static" / String)) - .map(|path| path); + let static_files = warp::path("static") + .and(kittybox::frontend::static_files()); - // TODO interpret HEAD - let catchall = warp::get() - .and(kittybox::util::require_host()) - .and(warp::path::full()) - .map(|host: Authority, path: FullPath| host.to_string() + path.as_str() + ".json") - // TODO fetch content from the database - // TODO parse content-type and determine appropriate response - ; + let catchall = kittybox::frontend::catchall( + database.clone(), + endpoints.clone() + ); let health = warp::path("health").and(warp::path::end()).map(|| "OK"); - // TODO instrumentation middleware (see metrics.rs for comments) - //let metrics = warp::path("metrics").and(warp::path::end()).map(kittybox::metrics::gather); + let metrics = warp::path("metrics").and(warp::path::end()).map(kittybox::metrics::gather); + let app = homepage - .or(login) + .or(metrics + .or(health)) .or(static_files) + .or(login) .or(coffee) - .or(health) .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() + ])) ; - let server = warp::serve(app); + let svc = warp::service(app); - // TODO https://github.com/seanmonstar/warp/issues/854 - // TODO move to Hyper to wrap the requests in metrics - info!("Listening on {:?}", host); - server.bind(host).await; - Ok(()) + let tcp_listener: std::net::TcpListener; + let mut listenfd = listenfd::ListenFd::from_env(); + if let Ok(Some(listener)) = listenfd.take_tcp_listener(0) { + tcp_listener = listener; + } else { + tcp_listener = std::net::TcpListener::bind(listen_at).unwrap(); + } + tcp_listener.set_nonblocking(true).unwrap(); + + info!("Listening on {}", tcp_listener.local_addr().unwrap()); + let server: hyper::server::Server<_, _> = hyper::server::Server::from_tcp(tcp_listener) + .unwrap() + .tcp_keepalive(Some(Duration::from_secs(30 * 60))) + .serve(hyper::service::make_service_fn(move |_| { + let service = svc.clone(); + async move { + Ok::<_, Infallible>(service) + } + })); + + if let Err(err) = server.await { + error!("Error serving requests: {}", err); + std::process::exit(1); + } } else { println!("Unknown backend, not starting."); std::process::exit(1); -- cgit 1.4.1