aboutsummaryrefslogblamecommitdiff
path: root/src/config/runtime.rs
blob: ee7f682538c5779a0e083e4643a4fa7da62248e1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11



                             
                                                                                                     





                                                                                       
                                                           
 
                




                                
                

                              
                                   


                



                                   
                





                                      
                
                          
                                        


                                                    



                                                      
                                                                            


                                                                                  









                                 












                                                                            





                                                                  
                                              
                                                                                

                                                                                         


                              
                                     



                   
                            




                                                                             


                                                                                         
                              
                                     
                   



                       




                                                                        
                                                        
                                                                                   











                                                                                                                         
                              


                                        
                   

         
use std::time::Duration;

use anyhow::{Result, anyhow};

use crate::config::{ConfigOpts, ConfigOptsConsul, ConfigOptsAcme, ConfigOptsFirewall, ConfigOptsIgd};

// This code is inspired by the Trunk crate (https://github.com/thedodd/trunk)

// In this file, we take ConfigOpts and transform them into ready-to-use RuntimeConfig.
// We apply default values and business logic.

// Consul config is mandatory, all the others are optional.

#[derive(Debug)]
pub struct RuntimeConfigConsul {
	pub node_name: String,
	pub url: String,
}

#[derive(Debug)]
pub struct RuntimeConfigAcme {
	pub email: String,
	pub refresh_time: Duration,
}

#[derive(Debug)]
pub struct RuntimeConfigFirewall {
	pub refresh_time: Duration,
}

#[derive(Debug)]
pub struct RuntimeConfigIgd {
	pub private_ip: String,
	pub expiration_time: Duration,
	pub refresh_time: Duration,
}

#[derive(Debug)]
pub struct RuntimeConfig {
	pub consul: RuntimeConfigConsul,
	pub acme: Option<RuntimeConfigAcme>,
	pub firewall: Option<RuntimeConfigFirewall>,
	pub igd: Option<RuntimeConfigIgd>,
}

impl RuntimeConfig {
	pub fn new(opts: ConfigOpts) -> Result<Self> {
		let consul = RuntimeConfigConsul::new(opts.consul.clone())?;
		let acme = RuntimeConfigAcme::new(opts.acme.clone())?;
		let firewall = RuntimeConfigFirewall::new(opts.firewall.clone())?;
		let igd = RuntimeConfigIgd::new(opts.igd.clone())?;

		Ok(Self {
			acme,
			consul,
			firewall,
			igd,
		})
	}
}

impl RuntimeConfigConsul {
	pub(super) fn new(opts: ConfigOptsConsul) -> Result<Self> {
		let node_name = opts.node_name.expect(
			"'DIPLONAT_CONSUL_NODE_NAME' is required");
		let url = opts.url.unwrap_or(super::CONSUL_URL.to_string());

		Ok(Self {
			node_name,
			url,
		})
	}
}

impl RuntimeConfigAcme {
	pub fn new(opts: ConfigOptsAcme) -> Result<Option<Self>> {
		if !opts.enable {
			return Ok(None);
		}

		let email = opts.email.expect(
			"'DIPLONAT_ACME_EMAIL' is required if ACME is enabled");
		let refresh_time = Duration::from_secs(
				opts.refresh_time.unwrap_or(super::REFRESH_TIME).into());

		Ok(Some(Self {
			email,
			refresh_time,
		}))
	}
}

impl RuntimeConfigFirewall {
	pub(super) fn new(opts: ConfigOptsFirewall) -> Result<Option<Self>> {
		if !opts.enable {
			return Ok(None);
		}

		let refresh_time = Duration::from_secs(
				opts.refresh_time.unwrap_or(super::REFRESH_TIME).into());

		Ok(Some(Self {
			refresh_time,
		}))
	}
}

impl RuntimeConfigIgd {
	pub(super) fn new(opts: ConfigOptsIgd) -> Result<Option<Self>> {
		if !opts.enable {
			return Ok(None);
		}

		let private_ip = opts.private_ip.expect(
			"'DIPLONAT_IGD_PRIVATE_IP' is required if IGD is enabled");
		let expiration_time = Duration::from_secs(
				opts.expiration_time.unwrap_or(super::EXPIRATION_TIME).into());
		let refresh_time = Duration::from_secs(
				opts.refresh_time.unwrap_or(super::REFRESH_TIME).into());

		if refresh_time.as_secs() * 2 > expiration_time.as_secs() {
	      return Err(anyhow!(
	        "IGD expiration time (currently: {}s) must be at least twice bigger than refresh time (currently: {}s)", 
	        expiration_time.as_secs(),
	        refresh_time.as_secs()));
	    }

		Ok(Some(Self {
			private_ip,
			expiration_time,
			refresh_time,
		}))
	}
}