use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Client, Request, Response, Server, Uri}; use std::net::SocketAddr; use std::env; use toml; use es_public_proxy::ProxyConfig; async fn upstream_req(req: Request, _config: ProxyConfig) -> Result, hyper::Error> { println!("hit: {}", req.uri()); let req_uri = req.uri(); let upstream_uri = Uri::builder() .scheme("http") .authority("localhost:9200") .path_and_query(req_uri.path_and_query().unwrap().as_str()) .build() .unwrap(); let res = Client::new().get(upstream_uri).await?; println!("resp!"); Ok(res) } async fn shutdown_signal() { // Wait for the CTRL+C signal tokio::signal::ctrl_c() .await .expect("failed to install CTRL+C signal handler"); } async fn run_server(config: ProxyConfig) { let addr = match &config.bind_addr { None => SocketAddr::from(([127, 0, 0, 1], 9292)), Some(addr) => addr.parse().unwrap(), }; println!("Listening on http://{}", addr); // TODO: possible to avoid cloning config on every connection? let make_svc = make_service_fn(move |_| { let inner = config.clone(); async move { Ok::<_, hyper::Error>(service_fn(move |req| { upstream_req(req, inner.clone()) })) } }); let serve_future = Server::bind(&addr).serve(make_svc); let graceful = serve_future.with_graceful_shutdown(shutdown_signal()); if let Err(e) = graceful.await { eprintln!("server error: {}", e); } } fn usage() -> String { "es-public-proxy [--config CONFIG_FILE] [--help]".to_string() } fn load_config() -> ProxyConfig { let args: Vec = env::args().collect(); let args: Vec<&str> = args.iter().map(|x| x.as_str()).collect(); let mut config_path: Option = None; // first parse CLI arg match args.as_slice() { [_] | [] => {}, [_, "-h"] | [_, "--help"] => { println!("{}", usage()); std::process::exit(0); }, [_, "--config", p] => { config_path = Some(p.to_string()) }, _ => { eprintln!("{}", usage()); eprintln!("couldn't parse arguments"); std::process::exit(1); } } // then try environment variables if let None = config_path { config_path = std::env::var("ES_PUBLIC_PROXY_CONFIG_PATH").ok(); } // then either load config file (TOML), or use default config if let Some(config_path) = config_path { let config_toml = std::fs::read_to_string(config_path).unwrap(); let config: ProxyConfig = toml::from_str(&config_toml).unwrap(); config } else { ProxyConfig::default() } } #[tokio::main] async fn main() { let config = load_config(); run_server(config).await; }