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:
parent
02b68de3e8
commit
ec334ef78b
3 changed files with 74 additions and 138 deletions
|
@ -34,14 +34,9 @@ pub struct GvaConf {
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
#[serde(default = "path_default")]
|
#[serde(default = "path_default")]
|
||||||
pub path: String,
|
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_host: Option<String>,
|
||||||
pub remote_port: Option<u16>,
|
pub remote_port: Option<u16>,
|
||||||
pub remote_path: Option<String>,
|
pub remote_path: Option<String>,
|
||||||
pub remote_subscriptions_path: Option<String>,
|
|
||||||
pub remote_tls: Option<bool>,
|
pub remote_tls: Option<bool>,
|
||||||
#[serde(default = "whitelist_default")]
|
#[serde(default = "whitelist_default")]
|
||||||
pub whitelist: Vec<IpAddr>,
|
pub whitelist: Vec<IpAddr>,
|
||||||
|
@ -59,18 +54,10 @@ fn path_default() -> String {
|
||||||
"gva".to_owned()
|
"gva".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn playground_path_default() -> String {
|
|
||||||
"gva-playground".to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn port_default() -> u16 {
|
const fn port_default() -> u16 {
|
||||||
30_901
|
30_901
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscriptions_path_default() -> String {
|
|
||||||
"gva-sub".to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn whitelist_default() -> Vec<IpAddr> {
|
fn whitelist_default() -> Vec<IpAddr> {
|
||||||
vec![
|
vec![
|
||||||
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
IpAddr::V4(Ipv4Addr::LOCALHOST),
|
||||||
|
@ -85,13 +72,10 @@ impl Default for GvaConf {
|
||||||
ip4: ip4_default(),
|
ip4: ip4_default(),
|
||||||
ip6: Some(ip6_default()),
|
ip6: Some(ip6_default()),
|
||||||
port: port_default(),
|
port: port_default(),
|
||||||
playground_path: playground_path_default(),
|
|
||||||
path: path_default(),
|
path: path_default(),
|
||||||
subscriptions_path: subscriptions_path_default(),
|
|
||||||
remote_host: None,
|
remote_host: None,
|
||||||
remote_port: None,
|
remote_port: None,
|
||||||
remote_path: None,
|
remote_path: None,
|
||||||
remote_subscriptions_path: None,
|
|
||||||
remote_tls: None,
|
remote_tls: None,
|
||||||
whitelist: whitelist_default(),
|
whitelist: whitelist_default(),
|
||||||
}
|
}
|
||||||
|
@ -107,11 +91,6 @@ impl GvaConf {
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| self.path.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)]
|
#[derive(StructOpt)]
|
||||||
|
@ -171,19 +150,6 @@ impl GvaCommand {
|
||||||
.msg(format!("Path ? [{}]", conf.path))
|
.msg(format!("Path ? [{}]", conf.path))
|
||||||
.default(conf.path)
|
.default(conf.path)
|
||||||
.get();
|
.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
|
// remoteHost
|
||||||
if let Some(ref remote_host) = conf.remote_host {
|
if let Some(ref remote_host) = conf.remote_host {
|
||||||
let new_remote_host = input()
|
let new_remote_host = input()
|
||||||
|
@ -225,17 +191,6 @@ impl GvaCommand {
|
||||||
} else {
|
} else {
|
||||||
conf.remote_path = None;
|
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
|
// whitelist
|
||||||
let mut whitelist: HashSet<_> = conf.whitelist.iter().copied().collect();
|
let mut whitelist: HashSet<_> = conf.whitelist.iter().copied().collect();
|
||||||
let res = input().msg("Update whitelist? [y/N]").default('N').get();
|
let res = input().msg("Update whitelist? [y/N]").default('N').get();
|
||||||
|
|
63
src/lib.rs
63
src/lib.rs
|
@ -51,6 +51,9 @@ use std::{convert::Infallible, path::Path};
|
||||||
use tests::get_public_ips;
|
use tests::get_public_ips;
|
||||||
use warp::{http::Response as HttpResponse, Filter as _, Rejection};
|
use warp::{http::Response as HttpResponse, Filter as _, Rejection};
|
||||||
|
|
||||||
|
const PLAYGROUND_SUB_PATH: &str = "playground";
|
||||||
|
const SUBSCRIPTION_SUB_PATH: &str = "subscription";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GvaModule {
|
pub struct GvaModule {
|
||||||
conf: GvaConf,
|
conf: GvaConf,
|
||||||
|
@ -270,29 +273,16 @@ impl GvaModule {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create warp server routes
|
// Create warp server routes
|
||||||
let graphql_post = warp_::graphql(
|
let gva_route = warp_::gva_route(
|
||||||
&conf,
|
&conf,
|
||||||
gva_schema.clone(),
|
gva_schema.clone(),
|
||||||
async_graphql::http::MultipartOptions::default(),
|
async_graphql::http::MultipartOptions::default(),
|
||||||
);
|
);
|
||||||
|
let gva_playground_route = warp_::gva_playground_route(&conf);
|
||||||
let conf_clone = conf.clone();
|
let gva_subscription_route = warp_::gva_subscription_route(&conf, gva_schema.clone());
|
||||||
let graphql_playground = warp::path::path(conf.playground_path.clone())
|
let routes = gva_route
|
||||||
.and(warp::get())
|
.or(gva_subscription_route)
|
||||||
.map(move || {
|
.or(gva_playground_route)
|
||||||
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()))
|
|
||||||
.recover(|err: Rejection| async move {
|
.recover(|err: Rejection| async move {
|
||||||
if let Some(warp_::BadRequest(err)) = err.find() {
|
if let Some(warp_::BadRequest(err)) = err.find() {
|
||||||
return Ok::<_, Infallible>(warp::reply::with_status(
|
return Ok::<_, Infallible>(warp::reply::with_status(
|
||||||
|
@ -373,17 +363,6 @@ impl GvaModule {
|
||||||
remote_port,
|
remote_port,
|
||||||
conf.get_remote_path(),
|
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)
|
Ok(endpoints)
|
||||||
}
|
}
|
||||||
|
@ -433,13 +412,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(
|
assert_eq!(endpoints, vec!["GVA 0.0.0.0 [::] 30901 gva".to_owned(),]);
|
||||||
endpoints,
|
|
||||||
vec![
|
|
||||||
"GVA 0.0.0.0 [::] 30901 gva".to_owned(),
|
|
||||||
"GVASUB 0.0.0.0 [::] 30901 gva-sub".to_owned()
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// only ip4 find
|
// only ip4 find
|
||||||
let endpoints = test_gen_endpoints(
|
let endpoints = test_gen_endpoints(
|
||||||
|
@ -450,13 +423,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(
|
assert_eq!(endpoints, vec!["GVA 0.0.0.0 30901 gva".to_owned(),]);
|
||||||
endpoints,
|
|
||||||
vec![
|
|
||||||
"GVA 0.0.0.0 30901 gva".to_owned(),
|
|
||||||
"GVASUB 0.0.0.0 30901 gva-sub".to_owned()
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// only ip6 find
|
// only ip6 find
|
||||||
let endpoints = test_gen_endpoints(
|
let endpoints = test_gen_endpoints(
|
||||||
|
@ -467,13 +434,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(
|
assert_eq!(endpoints, vec!["GVA [::] 30901 gva".to_owned(),]);
|
||||||
endpoints,
|
|
||||||
vec![
|
|
||||||
"GVA [::] 30901 gva".to_owned(),
|
|
||||||
"GVASUB [::] 30901 gva-sub".to_owned()
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// No ips find
|
// No ips find
|
||||||
assert!(test_gen_endpoints(
|
assert!(test_gen_endpoints(
|
||||||
|
|
104
src/warp_.rs
104
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<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,
|
conf: &GvaConf,
|
||||||
gva_schema: GvaSchema,
|
gva_schema: GvaSchema,
|
||||||
opts: async_graphql::http::MultipartOptions,
|
opts: async_graphql::http::MultipartOptions,
|
||||||
|
@ -150,6 +168,7 @@ pub(crate) fn graphql(
|
||||||
let anti_spam = AntiSpam::from(conf);
|
let anti_spam = AntiSpam::from(conf);
|
||||||
let opts = Arc::new(opts);
|
let opts = Arc::new(opts);
|
||||||
warp::path::path(conf.path.clone())
|
warp::path::path(conf.path.clone())
|
||||||
|
.and(warp::path::end())
|
||||||
.and(warp::method())
|
.and(warp::method())
|
||||||
.and(warp::query::raw().or(warp::any().map(String::new)).unify())
|
.and(warp::query::raw().or(warp::any().map(String::new)).unify())
|
||||||
.and(warp::addr::remote())
|
.and(warp::addr::remote())
|
||||||
|
@ -223,51 +242,13 @@ pub(crate) fn graphql(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_bincode_batch_queries(
|
pub(crate) fn gva_subscription_route(
|
||||||
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(
|
|
||||||
conf: &GvaConf,
|
conf: &GvaConf,
|
||||||
schema: GvaSchema,
|
schema: GvaSchema,
|
||||||
) -> impl warp::Filter<Extract = (impl warp::Reply,), Error = Rejection> + Clone {
|
) -> impl warp::Filter<Extract = (impl warp::Reply,), Error = Rejection> + Clone {
|
||||||
let anti_spam = AntiSpam::from(conf);
|
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::addr::remote())
|
||||||
.and(warp::header::optional::<IpAddr>("X-Real-IP"))
|
.and(warp::header::optional::<IpAddr>("X-Real-IP"))
|
||||||
.and(warp::ws())
|
.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" }"#,
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue