diff --git a/conf/src/lib.rs b/conf/src/lib.rs index 126b017..fd690ef 100644 --- a/conf/src/lib.rs +++ b/conf/src/lib.rs @@ -34,14 +34,9 @@ pub struct GvaConf { pub port: u16, #[serde(default = "path_default")] pub path: String, - #[serde(default = "playground_path_default")] - pub playground_path: String, - #[serde(default = "subscriptions_path_default")] - pub subscriptions_path: String, pub remote_host: Option, pub remote_port: Option, pub remote_path: Option, - pub remote_subscriptions_path: Option, pub remote_tls: Option, #[serde(default = "whitelist_default")] pub whitelist: Vec, @@ -59,18 +54,10 @@ fn path_default() -> String { "gva".to_owned() } -fn playground_path_default() -> String { - "gva-playground".to_owned() -} - const fn port_default() -> u16 { 30_901 } -fn subscriptions_path_default() -> String { - "gva-sub".to_owned() -} - fn whitelist_default() -> Vec { vec![ IpAddr::V4(Ipv4Addr::LOCALHOST), @@ -85,13 +72,10 @@ impl Default for GvaConf { ip4: ip4_default(), ip6: Some(ip6_default()), port: port_default(), - playground_path: playground_path_default(), path: path_default(), - subscriptions_path: subscriptions_path_default(), remote_host: None, remote_port: None, remote_path: None, - remote_subscriptions_path: None, remote_tls: None, whitelist: whitelist_default(), } @@ -107,11 +91,6 @@ impl GvaConf { .clone() .unwrap_or_else(|| self.path.clone()) } - pub fn get_remote_subscriptions_path(&self) -> String { - self.remote_subscriptions_path - .clone() - .unwrap_or_else(|| self.subscriptions_path.clone()) - } } #[derive(StructOpt)] @@ -171,19 +150,6 @@ impl GvaCommand { .msg(format!("Path ? [{}]", conf.path)) .default(conf.path) .get(); - // playgroundPath - conf.path = input() - .msg(format!("playground path ? [{}]", conf.playground_path)) - .default(conf.playground_path.clone()) - .get(); - // subscriptionsPath - conf.subscriptions_path = input() - .msg(format!( - "Subscriptions path ? [{}]", - conf.subscriptions_path - )) - .default(conf.subscriptions_path) - .get(); // remoteHost if let Some(ref remote_host) = conf.remote_host { let new_remote_host = input() @@ -225,17 +191,6 @@ impl GvaCommand { } else { conf.remote_path = None; } - // remoteSubscriptionsPath - let res = input() - .msg("Define a remote subscriptions path? [y/N]") - .default('N') - .get(); - if res == 'y' || res == 'Y' { - conf.remote_subscriptions_path = - Some(input().msg("Enter remote subscriptions path:").get()); - } else { - conf.remote_subscriptions_path = None; - } // whitelist let mut whitelist: HashSet<_> = conf.whitelist.iter().copied().collect(); let res = input().msg("Update whitelist? [y/N]").default('N').get(); diff --git a/src/lib.rs b/src/lib.rs index bad7d1e..ed68001 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,9 @@ use std::{convert::Infallible, path::Path}; use tests::get_public_ips; use warp::{http::Response as HttpResponse, Filter as _, Rejection}; +const PLAYGROUND_SUB_PATH: &str = "playground"; +const SUBSCRIPTION_SUB_PATH: &str = "subscription"; + #[derive(Debug)] pub struct GvaModule { conf: GvaConf, @@ -270,29 +273,16 @@ impl GvaModule { ); // Create warp server routes - let graphql_post = warp_::graphql( + let gva_route = warp_::gva_route( &conf, gva_schema.clone(), async_graphql::http::MultipartOptions::default(), ); - - let conf_clone = conf.clone(); - let graphql_playground = warp::path::path(conf.playground_path.clone()) - .and(warp::get()) - .map(move || { - HttpResponse::builder() - .header("content-type", "text/html") - .body(async_graphql::http::playground_source( - GraphQLPlaygroundConfig::new(&format!("/{}", &conf_clone.path)) - .subscription_endpoint( - &format!("/{}", &conf_clone.subscriptions_path,), - ), - )) - }); - - let routes = graphql_playground - .or(graphql_post) - .or(warp_::graphql_ws(&conf, gva_schema.clone())) + let gva_playground_route = warp_::gva_playground_route(&conf); + let gva_subscription_route = warp_::gva_subscription_route(&conf, gva_schema.clone()); + let routes = gva_route + .or(gva_subscription_route) + .or(gva_playground_route) .recover(|err: Rejection| async move { if let Some(warp_::BadRequest(err)) = err.find() { return Ok::<_, Infallible>(warp::reply::with_status( @@ -373,17 +363,6 @@ impl GvaModule { remote_port, conf.get_remote_path(), )); - endpoints.push(format!( - "GVASUB {}{} {} {}", - if remote_port == 443 || conf.remote_tls.unwrap_or_default() { - "S " - } else { - "" - }, - remote_hosh, - remote_port, - conf.get_remote_subscriptions_path(), - )); } Ok(endpoints) } @@ -433,13 +412,7 @@ mod tests { }, ) .await?; - assert_eq!( - endpoints, - vec![ - "GVA 0.0.0.0 [::] 30901 gva".to_owned(), - "GVASUB 0.0.0.0 [::] 30901 gva-sub".to_owned() - ] - ); + assert_eq!(endpoints, vec!["GVA 0.0.0.0 [::] 30901 gva".to_owned(),]); // only ip4 find let endpoints = test_gen_endpoints( @@ -450,13 +423,7 @@ mod tests { }, ) .await?; - assert_eq!( - endpoints, - vec![ - "GVA 0.0.0.0 30901 gva".to_owned(), - "GVASUB 0.0.0.0 30901 gva-sub".to_owned() - ] - ); + assert_eq!(endpoints, vec!["GVA 0.0.0.0 30901 gva".to_owned(),]); // only ip6 find let endpoints = test_gen_endpoints( @@ -467,13 +434,7 @@ mod tests { }, ) .await?; - assert_eq!( - endpoints, - vec![ - "GVA [::] 30901 gva".to_owned(), - "GVASUB [::] 30901 gva-sub".to_owned() - ] - ); + assert_eq!(endpoints, vec!["GVA [::] 30901 gva".to_owned(),]); // No ips find assert!(test_gen_endpoints( diff --git a/src/warp_.rs b/src/warp_.rs index bcde9d5..e602eee 100644 --- a/src/warp_.rs +++ b/src/warp_.rs @@ -142,7 +142,25 @@ fn add_cache_control(http_resp: &mut warp::reply::Response, resp: &async_graphql } } -pub(crate) fn graphql( +pub(crate) fn gva_playground_route( + conf: &GvaConf, +) -> impl warp::Filter + Clone { + let gva_path = conf.path.clone(); + warp::path::path(gva_path.clone()) + .and(warp::path::path(PLAYGROUND_SUB_PATH)) + .and(warp::get()) + .map(move || { + HttpResponse::builder() + .header("content-type", "text/html") + .body(async_graphql::http::playground_source( + GraphQLPlaygroundConfig::new(&format!("/{}", &gva_path)).subscription_endpoint( + &format!("/{}/{}", &gva_path, SUBSCRIPTION_SUB_PATH), + ), + )) + }) +} + +pub(crate) fn gva_route( conf: &GvaConf, gva_schema: GvaSchema, opts: async_graphql::http::MultipartOptions, @@ -150,6 +168,7 @@ pub(crate) fn graphql( let anti_spam = AntiSpam::from(conf); let opts = Arc::new(opts); warp::path::path(conf.path.clone()) + .and(warp::path::end()) .and(warp::method()) .and(warp::query::raw().or(warp::any().map(String::new)).unify()) .and(warp::addr::remote()) @@ -223,51 +242,13 @@ pub(crate) fn graphql( ) } -async fn process_bincode_batch_queries( - body_reader: impl 'static + futures::TryStream + Send + Unpin, - is_whitelisted: bool, -) -> Result { - Ok(ServerResponse::Bincode( - duniter_bda::execute(body_reader, is_whitelisted).await, - )) -} - -async fn process_json_batch_queries( - body_reader: impl 'static + futures::AsyncRead + Send + Unpin, - content_type: Option, - gva_schema: GvaSchema, - is_whitelisted: bool, - opts: async_graphql::http::MultipartOptions, -) -> Result { - let batch_request = GraphQlRequest::new( - async_graphql::http::receive_batch_body( - content_type, - body_reader, - async_graphql::http::MultipartOptions::clone(&opts), - ) - .await - .map_err(|err| warp::reject::custom(BadRequest(err.into())))?, - ); - if is_whitelisted || batch_request.len() <= anti_spam::MAX_BATCH_SIZE { - Ok(ServerResponse::GraphQl( - batch_request - .data(QueryContext { is_whitelisted }) - .execute(gva_schema) - .await, - )) - } else { - Err(warp::reject::custom(BadRequest(anyhow::Error::msg( - r#"{ "error": "The batch contains too many requests" }"#, - )))) - } -} - -pub(crate) fn graphql_ws( +pub(crate) fn gva_subscription_route( conf: &GvaConf, schema: GvaSchema, ) -> impl warp::Filter + Clone { let anti_spam = AntiSpam::from(conf); - warp::path::path(conf.subscriptions_path.clone()) + warp::path::path(conf.path.clone()) + .and(warp::path::path(SUBSCRIPTION_SUB_PATH)) .and(warp::addr::remote()) .and(warp::header::optional::("X-Real-IP")) .and(warp::ws()) @@ -326,3 +307,42 @@ pub(crate) fn graphql_ws( ))) }) } + +async fn process_bincode_batch_queries( + body_reader: impl 'static + futures::TryStream + Send + Unpin, + is_whitelisted: bool, +) -> Result { + Ok(ServerResponse::Bincode( + duniter_bda::execute(body_reader, is_whitelisted).await, + )) +} + +async fn process_json_batch_queries( + body_reader: impl 'static + futures::AsyncRead + Send + Unpin, + content_type: Option, + gva_schema: GvaSchema, + is_whitelisted: bool, + opts: async_graphql::http::MultipartOptions, +) -> Result { + let batch_request = GraphQlRequest::new( + async_graphql::http::receive_batch_body( + content_type, + body_reader, + async_graphql::http::MultipartOptions::clone(&opts), + ) + .await + .map_err(|err| warp::reject::custom(BadRequest(err.into())))?, + ); + if is_whitelisted || batch_request.len() <= anti_spam::MAX_BATCH_SIZE { + Ok(ServerResponse::GraphQl( + batch_request + .data(QueryContext { is_whitelisted }) + .execute(gva_schema) + .await, + )) + } else { + Err(warp::reject::custom(BadRequest(anyhow::Error::msg( + r#"{ "error": "The batch contains too many requests" }"#, + )))) + } +}