feat(gva): use sub-path for playground and subscriptions

Consequently:
- deletion of the GVASUB endpoint
- remove conf param playground_path
- remove conf param subscriptions_path
This commit is contained in:
librelois 2021-05-30 17:33:41 +02:00
parent 02b68de3e8
commit ec334ef78b
3 changed files with 74 additions and 138 deletions

View file

@ -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<String>,
pub remote_port: Option<u16>,
pub remote_path: Option<String>,
pub remote_subscriptions_path: Option<String>,
pub remote_tls: Option<bool>,
#[serde(default = "whitelist_default")]
pub whitelist: Vec<IpAddr>,
@ -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<IpAddr> {
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();

View file

@ -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(

View file

@ -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<Extract = (impl warp::Reply,), Error = Rejection> + 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<Ok = Bytes, Error = std::io::Error> + Send + Unpin,
is_whitelisted: bool,
) -> Result<ServerResponse, warp::Rejection> {
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<String>,
gva_schema: GvaSchema,
is_whitelisted: bool,
opts: async_graphql::http::MultipartOptions,
) -> Result<ServerResponse, warp::Rejection> {
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<Extract = (impl warp::Reply,), Error = Rejection> + 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::<IpAddr>("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<Ok = Bytes, Error = std::io::Error> + Send + Unpin,
is_whitelisted: bool,
) -> Result<ServerResponse, warp::Rejection> {
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<String>,
gva_schema: GvaSchema,
is_whitelisted: bool,
opts: async_graphql::http::MultipartOptions,
) -> Result<ServerResponse, warp::Rejection> {
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" }"#,
))))
}
}