diff options
author | Vika <vika@fireburn.ru> | 2022-02-15 02:44:33 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2022-02-15 02:46:24 +0300 |
commit | 9e4c4551a786830bf34d74c4ef111a8ed292fa9f (patch) | |
tree | 7796d7e529c89f22bccfbba4566b6bf5efca8071 /src/micropub | |
parent | d1327ed6b28a49770aa5d9b06245aa063b406f78 (diff) | |
download | kittybox-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.rs | 128 |
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())) + }) +} |