use anyhow::{Context, Result}; use futures::future::FutureExt; use tokio::try_join; use crate::{ config::ConfigOpts, consul_actor::ConsulActor, fw_actor::FirewallActor, igd_actor::IgdActor, stun_actor::StunActor, }; pub struct Diplonat { consul: ConsulActor, firewall: FirewallActor, igd: Option, stun: StunActor, } impl Diplonat { pub async fn new() -> Result { let rt_cfg = ConfigOpts::from_env().context("Parse configuration")?; println!("{:#?}", rt_cfg); let ca = ConsulActor::new(&rt_cfg.consul, &rt_cfg.consul.node_name); let fw = FirewallActor::new( rt_cfg.firewall.ipv6_only, rt_cfg.firewall.refresh_time, &ca.rx_open_ports, ) .await .context("Setup fireall actor")?; let ia = match rt_cfg.igd { Some(igdc) => Some( IgdActor::new( igdc.private_ip, igdc.refresh_time, igdc.expiration_time, &ca.rx_open_ports, ) .await .context("Setup IGD actor")?, ), None => None, }; let sa = StunActor::new(&rt_cfg.consul, &rt_cfg.stun, &rt_cfg.consul.node_name); let ctx = Self { consul: ca, igd: ia, firewall: fw, stun: sa, }; Ok(ctx) } pub async fn listen(&mut self) -> Result<()> { let igd_opt = &mut self.igd; try_join!( self.consul.listen().map(|x| x.context("Run consul actor")), async { if let Some(igd) = igd_opt { igd.listen().await.context("Run IGD actor") } else { Ok(()) } }, self.firewall .listen() .map(|x| x.context("Run firewall actor")), self.stun.listen().map(|x| x.context("Run STUN actor")), )?; Ok(()) } }