From 9e4c4551a786830bf34d74c4ef111a8ed292fa9f Mon Sep 17 00:00:00 2001 From: Vika Date: Tue, 15 Feb 2022 02:44:33 +0300 Subject: 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... --- src/micropub/mod.rs | 128 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 99 insertions(+), 29 deletions(-) (limited to 'src/micropub') 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 tide::Middleware> for CORSMiddleware -where - B: database::Storage + Send + Sync + Clone, -{ - async fn handle( - &self, - req: Request>, - next: Next<'_, ApplicationState>, - ) -> 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 +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +enum ErrorType { + InvalidRequest, + InternalServerError +} + +#[derive(Serialize, Deserialize)] +struct MicropubError { + error: ErrorType, + error_description: String +} + +impl From 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(db: D) -> impl Filter + Clone { + warp::get() + .map(move || db.clone()) + .and(crate::util::require_host()) + .and(warp::query::()) + .then(|db: D, host: warp::host::Authority, query: MicropubQuery| async move { + match query.q { + QueryType::Config => { + let channels: Vec = 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::() { + 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())) + }) +} -- cgit 1.4.1