about summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2022-02-15 02:44:33 +0300
committerVika <vika@fireburn.ru>2022-02-15 02:46:24 +0300
commit9e4c4551a786830bf34d74c4ef111a8ed292fa9f (patch)
tree7796d7e529c89f22bccfbba4566b6bf5efca8071 /src/main.rs
parentd1327ed6b28a49770aa5d9b06245aa063b406f78 (diff)
WIP: convert to Tokio and Warp
Warp allows requests to be applied as "filters", allowing to flexibly
split up logic and have it work in a functional style, similar to
pipes.

Tokio is just an alternative runtime. I thought that maybe switching
runtimes and refactoring the code might allow me to fish out that
pesky bug with the whole application hanging after a certain amount of
requests...
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs118
1 files changed, 101 insertions, 17 deletions
diff --git a/src/main.rs b/src/main.rs
index 79e0cf5..4036d46 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,10 @@
 use log::{debug, error, info};
 use std::env;
-use surf::Url;
+use http_types::Url;
+use warp::{Filter, host::Authority, path::FullPath};
 
-#[async_std::main]
-async fn main() -> Result<(), std::io::Error> {
+#[tokio::main]
+async fn main() -> Result<(), kittybox::database::StorageError> {
     // 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);
@@ -64,13 +65,14 @@ async fn main() -> Result<(), std::io::Error> {
         Some(value) => value,
         None => {
             if let Ok(filename) = env::var("COOKIE_SECRET_FILE") {
-                use async_std::io::ReadExt;
+                /*use async_std::io::ReadExt;
 
                 let mut file = async_std::fs::File::open(filename).await?;
                 let mut temp_string = String::new();
                 file.read_to_string(&mut temp_string).await?;
 
-                temp_string
+                temp_string*/
+                todo!()
             } else {
                 error!("COOKIE_SECRET or COOKIE_SECRET_FILE is not set, will not be able to log in users securely!");
                 std::process::exit(1);
@@ -78,24 +80,106 @@ async fn main() -> Result<(), std::io::Error> {
         }
     };
 
-    let host = env::var("SERVE_AT")
+    let host: std::net::SocketAddr = match env::var("SERVE_AT")
         .ok()
-        .unwrap_or_else(|| "0.0.0.0:8080".to_string());
+        .unwrap_or_else(|| "0.0.0.0:8080".to_string())
+        .parse() {
+            Ok(addr) => addr,
+            Err(e) => {
+                error!("Cannot parse SERVE_AT: {}", e);
+                std::process::exit(1);
+            }
+        };
 
     if backend_uri.starts_with("redis") {
         println!("The Redis backend is deprecated.");
         std::process::exit(1);
     } else if backend_uri.starts_with("file") {
-        let app = kittybox::get_app_with_file(
-            token_endpoint,
-            authorization_endpoint,
-            backend_uri,
-            media_endpoint,
-            cookie_secret,
-            internal_token,
-        )
-        .await;
-        app.listen(host).await
+        
+        let database = {
+            let folder = backend_uri.strip_prefix("file://").unwrap();
+            let path = std::path::PathBuf::from(folder);
+            kittybox::database::FileStorage::new(path).await?
+        };
+
+        // TODO interpret HEAD
+        let homepage = kittybox::util::require_host()
+            .and(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));
+        
+        let micropub = warp::path("micropub")
+            .and(warp::path::end()
+                 .and(warp::get()
+                      .and(kittybox::micropub::query(database))
+                      .or(warp::post()
+                          .and(kittybox::util::require_host())
+                          .map(|host| "micropub post!"))
+                      .or(warp::options()
+                          .map(|| warp::reply::json::<Option<()>>(&None))
+                          // TODO: why doesn't this work?
+                          // .map(warp::reply::with::header("Allow", "GET, POST"))
+                          .map(|reply| warp::reply::with_header(reply, "Allow", "GET, POST"))
+                      ))
+                 .or(warp::get()
+                     .and(warp::path("client"))
+                     .and(warp::path::end())
+                     .map(|| kittybox::MICROPUB_CLIENT)));
+
+        let media = warp::path("media")
+            .and(warp::path::end()
+                 .and(kittybox::util::require_host())
+                 .map(|host| "media endpoint?...")
+                 .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!")));
+
+        // TODO prettier error response
+        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);
+
+        // 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 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 app = homepage
+            .or(login)
+            .or(static_files)
+            .or(coffee)
+            .or(health)
+            .or(micropub)
+            .or(media)
+            .or(catchall)
+            ;
+
+        let server = warp::serve(app);
+
+        // TODO use warp::Server::bind_with_graceful_shutdown
+        info!("Listening on {:?}", host);
+        server.bind(host).await;
+        Ok(())
     } else {
         println!("Unknown backend, not starting.");
         std::process::exit(1);