about summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs124
1 files changed, 80 insertions, 44 deletions
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<String> = env::var("MEDIA_ENDPOINT").ok();
+    //let internal_token: Option<String> = env::var("KITTYBOX_INTERNAL_TOKEN").ok();
 
-    let internal_token: Option<String> = 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::<std::net::SocketAddr>() {
             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);