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())) }) }