aboutsummaryrefslogblamecommitdiff
path: root/src/config/runtime.rs
blob: 58c86b951a92861a704e395862e0b1f980bd2db4 (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, ConfigOptsAcme, ConfigOptsBase, ConfigOptsConsul};

// 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.

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

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

#[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 acme: Option<RuntimeConfigAcme>,
	pub consul: RuntimeConfigConsul,
	pub firewall: RuntimeConfigFirewall,
	pub igd: RuntimeConfigIgd,
}

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

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

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

		let email = opts.email.expect(
			"'DIPLONAT_ACME_EMAIL' environment variable is required \
			if 'DIPLONAT_ACME_ENABLE' == 'true'");

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

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

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

impl RuntimeConfigFirewall {
	pub(super) fn new(opts: ConfigOptsBase) -> Result<Self> {
		let refresh_time = Duration::from_secs(
				opts.refresh_time.unwrap_or(super::REFRESH_TIME).into());

		Ok(Self {
			refresh_time,
		})
	}
}

impl RuntimeConfigIgd {
	pub(super) fn new(opts: ConfigOptsBase) -> Result<Self> {
		let private_ip = opts.private_ip.expect(
			"'DIPLONAT_PRIVATE_IP' environment variable is required");
		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(Self {
			private_ip,
			expiration_time,
			refresh_time,
		})
	}
}