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.rs129
1 files changed, 68 insertions, 61 deletions
diff --git a/kittybox-rs/src/main.rs b/kittybox-rs/src/main.rs
index 50c0ca5..59c3e69 100644
--- a/kittybox-rs/src/main.rs
+++ b/kittybox-rs/src/main.rs
@@ -110,11 +110,55 @@ async fn main() {
             kittybox::media::storage::file::FileStore::new(path)
         };
 
-        let svc = axum::Router::new()
+        // This code proves that different components of Kittybox can
+        // be split up without hurting the app
+        //
+        // If needed, some features could be omitted from the binary
+        // or just not spun up in the future
+        //
+        // For example, the frontend code could run spearately from
+        // Micropub and only have read access to the database folder
+        let frontend = axum::Router::new()
             .route(
                 "/",
-                axum::routing::get(kittybox::frontend::homepage::<FileStorage>),
-            )
+                axum::routing::get(kittybox::frontend::homepage::<FileStorage>)
+                    .layer(axum::Extension(database.clone())))
+            .route("/.kittybox/static/:path", axum::routing::get(kittybox::frontend::statics))
+            .fallback(
+                axum::routing::get(kittybox::frontend::catchall::<FileStorage>)
+                    .layer(axum::Extension(database.clone())));
+
+        // Onboarding is a bit of a special case. One might argue that
+        // the onboarding makes Kittybox a monolith. This is wrong.
+        // The "onboarding receiver" doesn't need any code from the
+        // onboarding form - they're grouped in a single module for
+        // convenience only, since modifying one usually requires
+        // updating the other to match.
+        //
+        // For example, this "router" just groups two separate methods
+        // in one request, because logically they live in the same
+        // subtree. But one could manually construct only one but not
+        // the other, to receive a "frontend-only" application. Of
+        // course, in this scenario, one must employ a reverse proxy
+        // to distinguish between GET and POST requests to the same
+        // path, and route them to the correct set of endpoints with
+        // write access.
+        let onboarding = axum::Router::new()
+            .route("/.kittybox/onboarding", kittybox::frontend::onboarding::router(
+                database.clone(), http.clone()
+            ));
+
+        let micropub = axum::Router::new()
+            .route("/.kittybox/micropub", kittybox::micropub::router(database.clone(), http.clone()))
+            .nest("/.kittybox/micropub/client", kittybox::companion::router());
+
+        let media = axum::Router::new()
+            .nest("/.kittybox/media", kittybox::media::router(blobstore).layer(axum::Extension(http)));
+
+        /*let indieauth = axum::Router::new()
+            .nest("/.kittybox/indieauth", kittybox::indieauth::router());*/
+
+        let technical = axum::Router::new()
             .route(
                 "/.kittybox/coffee",
                 axum::routing::get(|| async {
@@ -127,71 +171,34 @@ async fn main() {
                 }),
             )
             .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 {
+                axum::routing::get(
+                    |axum::Extension(db): axum::Extension<FileStorage>| async move {
                     // TODO health-check the database
                     "OK"
-                }),
+                    }
+                )
+                    .layer(axum::Extension(database))
             )
             .route(
                 "/.kittybox/metrics",
                 axum::routing::get(|| async { todo!() }),
-            )
-            .nest(
-                "/.kittybox/media",
-                axum::Router::new()
-                    .route(
-                        "/",
-                        axum::routing::get(|| async { todo!() })
-                            .post(
-                                kittybox::media::upload::<kittybox::media::FileStore>
-                            ),
-                    )
-                    .route("/uploads/*file", axum::routing::get(
-                        kittybox::media::serve::<kittybox::media::FileStore>
-                    )),
-            )
-            .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::tokenauth::TokenEndpoint(
-                token_endpoint,
-            )))
-            .layer(axum::Extension(blobstore))
-            .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 svc = axum::Router::new()
+            .merge(frontend)
+            .merge(onboarding)
+            .merge(micropub)
+            .merge(media)
+            //.merge(indieauth)
+            .merge(technical)
+            .layer(axum::Extension(kittybox::tokenauth::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();
 
@@ -200,8 +207,8 @@ async fn main() {
             } 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
+            // Set the socket to non-blocking so tokio can poll it
+            // properly -- this is the async magic!
             tcp_listener.set_nonblocking(true).unwrap();
 
             tcp_listener