about summary refs log tree commit diff
path: root/src/micropub
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/micropub
parentd1327ed6b28a49770aa5d9b06245aa063b406f78 (diff)
downloadkittybox-9e4c4551a786830bf34d74c4ef111a8ed292fa9f.tar.zst
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/micropub')
-rw-r--r--src/micropub/mod.rs128
1 files changed, 99 insertions, 29 deletions
diff --git a/src/micropub/mod.rs b/src/micropub/mod.rs
index 23f20c4..95595cf 100644
--- a/src/micropub/mod.rs
+++ b/src/micropub/mod.rs
@@ -1,31 +1,101 @@
-pub mod get;
-pub mod post;
-
-pub use get::get_handler;
-pub use post::normalize_mf2;
-pub use post::post_handler;
-
-pub struct CORSMiddleware {}
-
-use crate::database;
-use crate::ApplicationState;
-use async_trait::async_trait;
-use tide::{Next, Request, Result};
-
-#[async_trait]
-impl<B> tide::Middleware<ApplicationState<B>> for CORSMiddleware
-where
-    B: database::Storage + Send + Sync + Clone,
-{
-    async fn handle(
-        &self,
-        req: Request<ApplicationState<B>>,
-        next: Next<'_, ApplicationState<B>>,
-    ) -> Result {
-        let mut res = next.run(req).await;
-
-        res.insert_header("Access-Control-Allow-Origin", "*");
-
-        Ok(res)
+use warp::http::StatusCode;
+use warp::{Filter, Rejection, reject::InvalidQuery};
+use serde_json::{json, Value};
+use serde::{Serialize, Deserialize};
+use crate::database::{MicropubChannel, Storage};
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+enum QueryType {
+    Source,
+    Config,
+    Channel,
+    SyndicateTo
+}
+
+#[derive(Serialize, Deserialize)]
+struct MicropubQuery {
+    q: QueryType,
+    url: Option<String>
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+enum ErrorType {
+    InvalidRequest,
+    InternalServerError
+}
+
+#[derive(Serialize, Deserialize)]
+struct MicropubError {
+    error: ErrorType,
+    error_description: String
+}
+
+impl From<MicropubError> for StatusCode {
+    fn from(err: MicropubError) -> Self {
+        match err.error {
+            ErrorType::InvalidRequest => StatusCode::BAD_REQUEST,
+            ErrorType::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR
+        }
+    }
+}
+
+impl MicropubError {
+    fn new(error: ErrorType, error_description: &str) -> Self {
+        Self {
+            error,
+            error_description: error_description.to_owned()
+        }
     }
 }
+
+pub fn query<D: Storage>(db: D) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
+    warp::get()
+        .map(move || db.clone())
+        .and(crate::util::require_host())
+        .and(warp::query::<MicropubQuery>())
+        .then(|db: D, host: warp::host::Authority, query: MicropubQuery| async move {
+            match query.q {
+                QueryType::Config => {
+                    let channels: Vec<MicropubChannel> = match db.get_channels(host.as_str()).await {
+                        Ok(chans) => chans,
+                        Err(err) => return warp::reply::json(&MicropubError::new(
+                            ErrorType::InternalServerError,
+                            &format!("Error fetching channels: {}", err)
+                        ))
+                    };
+                    
+                    warp::reply::json(json!({
+                        "q": [
+                            QueryType::Source,
+                            QueryType::Config,
+                            QueryType::Channel,
+                            QueryType::SyndicateTo
+                        ],
+                        "channels": channels,
+                        "_kittybox_authority": host.as_str()
+                    }).as_object().unwrap())
+                },
+                _ => {
+                    todo!()
+                }
+            }
+        })
+        .recover(|err: Rejection| async move {
+            let error = if let Some(_) = err.find::<InvalidQuery>() {
+                MicropubError::new(
+                    ErrorType::InvalidRequest,
+                    "Invalid query parameters sent. Try ?q=config to see what you can do."
+                )
+            } else {
+                log::error!("Unhandled rejection: {:?}", err);
+                MicropubError::new(
+                    ErrorType::InternalServerError,
+                    &format!("Unknown error: {:?}", err)
+                )
+            };
+
+            Ok(warp::reply::with_status(warp::reply::json(&error), error.into()))
+        })
+}