about summary refs log tree commit diff
path: root/kittybox-rs/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'kittybox-rs/src/main.rs')
-rw-r--r--kittybox-rs/src/main.rs166
1 files changed, 115 insertions, 51 deletions
diff --git a/kittybox-rs/src/main.rs b/kittybox-rs/src/main.rs
index fd1875c..ef051ba 100644
--- a/kittybox-rs/src/main.rs
+++ b/kittybox-rs/src/main.rs
@@ -1,17 +1,16 @@
-use log::{debug, error, info};
-use std::{convert::Infallible, env, time::Duration};
+use kittybox::database::FileStorage;
+use std::{env, time::Duration};
+use tracing::{debug, error, info};
 use url::Url;
-use warp::{Filter, host::Authority};
 
 #[tokio::main]
 async fn main() {
-    // TODO turn into a feature so I can enable and disable it
-    #[cfg(debug_assertions)]
-    console_subscriber::init();
-
     // TODO use tracing instead of log
-    let logger_env = env_logger::Env::new().filter_or("RUST_LOG", "info");
-    env_logger::init_from_env(logger_env);
+    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
+    Registry::default()
+        .with(EnvFilter::from_default_env())
+        .with(tracing_subscriber::fmt::layer().json())
+        .init();
 
     info!("Starting the kittybox server...");
 
@@ -63,24 +62,22 @@ async fn main() {
     let listen_at = match env::var("SERVE_AT")
         .ok()
         .unwrap_or_else(|| "[::]:8080".to_string())
-        .parse::<std::net::SocketAddr>() {
-            Ok(addr) => addr,
-            Err(e) => {
-                error!("Cannot parse SERVE_AT: {}", e);
-                std::process::exit(1);
-            }
-        };
+        .parse::<std::net::SocketAddr>()
+    {
+        Ok(addr) => addr,
+        Err(e) => {
+            error!("Cannot parse SERVE_AT: {}", e);
+            std::process::exit(1);
+        }
+    };
 
-    // This thing handles redirects automatically but is type-incompatible with hyper::Client
-    // Bonus: less generics to be aware of, this thing hides its complexity
     let http: reqwest::Client = {
         #[allow(unused_mut)]
-        let mut builder = reqwest::Client::builder()
-            .user_agent(concat!(
-                env!("CARGO_PKG_NAME"),
-                "/",
-                env!("CARGO_PKG_VERSION")
-            ));
+        let mut builder = reqwest::Client::builder().user_agent(concat!(
+            env!("CARGO_PKG_NAME"),
+            "/",
+            env!("CARGO_PKG_VERSION")
+        ));
         // TODO: add a root certificate if there's an environment variable pointing at it
         //builder = builder.add_root_certificate(reqwest::Certificate::from_pem(todo!()));
 
@@ -109,12 +106,8 @@ async fn main() {
             webmention: None,
             microsub: None,
         };
-        
-        let homepage = warp::get()
-            .and(warp::path::end())
-            .and(kittybox::frontend::homepage(database.clone(), endpoints.clone()));
-        
-        let micropub = warp::path("micropub")
+
+        /*let micropub = warp::path("micropub")
             .and(warp::path::end()
                  .and(kittybox::micropub::micropub(
                      database.clone(),
@@ -169,11 +162,8 @@ async fn main() {
         // 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 catchall = kittybox::frontend::catchall(
-            database.clone(),
-            endpoints.clone()
-        );
+
+        et catchall = ;
 
         let app = homepage
             .or(technical)
@@ -186,29 +176,103 @@ async fn main() {
             ;
 
         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();
+        let svc = axum::Router::new()
+            .route(
+                "/",
+                axum::routing::get(kittybox::frontend::homepage::<FileStorage>),
+            )
+            .route(
+                "/.kittybox/coffee",
+                axum::routing::get(|| async {
+                    use axum::http::{header, StatusCode};
+                    (
+                        StatusCode::IM_A_TEAPOT,
+                        [(header::CONTENT_TYPE, "text/plain")],
+                        "Sorry, can't brew coffee yet!",
+                    )
+                }),
+            )
+            .route(
+                "/.kittybox/onboarding",
+                axum::routing::get(kittybox::frontend::onboarding::get)
+                    .post(kittybox::frontend::onboarding::post::<FileStorage>)
+            )
+            .route(
+                "/.kittybox/micropub",
+                axum::routing::get(kittybox::micropub::query::<FileStorage>)
+                    .post(kittybox::micropub::post::<FileStorage>)
+                    .layer(tower_http::cors::CorsLayer::new()
+                           .allow_methods([axum::http::Method::GET, axum::http::Method::POST])
+                           .allow_origin(tower_http::cors::Any)),
+            )
+            .route(
+                "/.kittybox/micropub/client",
+                axum::routing::get(|| {
+                    std::future::ready(axum::response::Html(kittybox::MICROPUB_CLIENT))
+                }),
+            )
+            .route(
+                "/.kittybox/health",
+                axum::routing::get(|| async {
+                    // TODO health-check the database
+                    "OK"
+                }),
+            )
+            .route(
+                "/.kittybox/metrics",
+                axum::routing::get(|| async { todo!() }),
+            )
+            .nest(
+                "/.kittybox/media",
+                axum::Router::new()
+                    .route(
+                        "/",
+                        axum::routing::get(|| async { todo!() }).post(|| async { todo!() }),
+                    )
+                    .route("/:filename", axum::routing::get(|| async { todo!() })),
+            )
+            .route(
+                "/.kittybox/static/:path",
+                axum::routing::get(kittybox::frontend::statics),
+            )
+            .fallback(axum::routing::get(
+                kittybox::frontend::catchall::<FileStorage>,
+            ))
+            .layer(axum::Extension(database))
+            .layer(axum::Extension(http))
+            .layer(axum::Extension(kittybox::indieauth::TokenEndpoint(
+                token_endpoint,
+            )))
+            .layer(
+                tower::ServiceBuilder::new()
+                    .layer(tower_http::trace::TraceLayer::new_for_http())
+                    .into_inner(),
+            );
+
+        // A little dance to turn a potential file descriptor into a guaranteed async network socket
+        let tcp_listener: std::net::TcpListener = {
+            let mut listenfd = listenfd::ListenFd::from_env();
 
+            let tcp_listener = 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();
+
+            tcp_listener
+        };
         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();
-                async move {
-                    Ok::<_, Infallible>(service)
-                }
-            }))
+            .serve(svc.into_make_service())
             .with_graceful_shutdown(async move {
                 // Defer to C-c handler whenever we're not on Unix
                 // TODO consider using a diverging future here