diff options
Diffstat (limited to 'service-joiner/src/main.rs')
-rw-r--r-- | service-joiner/src/main.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/service-joiner/src/main.rs b/service-joiner/src/main.rs new file mode 100644 index 0000000..7cd2844 --- /dev/null +++ b/service-joiner/src/main.rs @@ -0,0 +1,100 @@ +use std::str::FromStr; + +use anyhow::Context; +use anyhow::Error; +use anyhow::Result; +use actix_web::{get, web, App, HttpServer, Responder}; +use derive_more::{Display, Error}; + +#[derive(Clone)] +struct Endpoints { + hello_service_endpoint: String, + hello_service_port: u16, + + world_service_endpoint: String, + world_service_port: u16, +} + +#[derive(Debug, Display, Error)] +#[display(fmt = "error: {}", inner)] +struct AppError { + inner: anyhow::Error, +} + +impl actix_web::error::ResponseError for AppError {} + +#[get("/")] +async fn joiner(state: web::Data<Endpoints>) -> impl Responder { + async fn inner(state: web::Data<Endpoints>) -> Result<impl Responder> { + let hello = { + let url = reqwest::Url::parse(&format!("http://{host}:{port}/", + host = state.hello_service_endpoint, + port = state.hello_service_port))?; + reqwest::get(url) + }; + let world = { + let url = reqwest::Url::parse(&format!("http://{host}:{port}/", + host = state.world_service_endpoint, + port = state.world_service_port))?; + reqwest::get(url) + }; + + let (hello, world) = tokio::try_join!(hello, world)?; + let (hello, world) = tokio::try_join!(hello.text(), world.text())?; + + Ok(format!("{} {}", hello, world)) as Result<String> + } + + inner(state).await.map_err(|inner| AppError { inner }) +} + +#[actix_web::main] +async fn main() -> Result<()> { + env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); + let bind = std::env::var("HOST").expect("environment: HOST variable not set"); + let port = std::env::var("PORT") + .as_ref() + .map(|p| u16::from_str(p)) + .expect("environment: HOST variable not set") + .context("Failed to parse port as integer")?; + + let hello_service = std::env::var("HELLO_SERVICE") + .as_ref() + .map(std::ops::Deref::deref) + .map(parse_endpoint) + .expect("environment: HELLO_SERVICE variable not set")?; + + let world_service = std::env::var("WORLD_SERVICE") + .as_ref() + .map(std::ops::Deref::deref) + .map(parse_endpoint) + .expect("environment: WORLD_SERVICE variable not set")?; + + HttpServer::new(move || { + App::new() + .app_data(web::Data::new(Endpoints { + hello_service_endpoint: hello_service.0.clone(), + hello_service_port: hello_service.1, + + world_service_endpoint: world_service.0.clone(), + world_service_port: world_service.1, + })) + .service(joiner) + }) + .bind(format!("{}:{}", bind, port))? + .run() + .await + .map_err(anyhow::Error::from) +} + +fn parse_endpoint(s: &str) -> Result<(String, u16)> { + let v = s.split(':').collect::<Vec<_>>(); + if v.len() != 2 { + anyhow::bail!("Expected host:port, got: '{}'", s) + } + + u16::from_str(v[1]) + .map(|port| (v[0].to_string(), port)) + .map_err(Error::from) +} + |