summaryrefslogtreecommitdiffstats
path: root/service-joiner/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'service-joiner/src/main.rs')
-rw-r--r--service-joiner/src/main.rs100
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)
+}
+