diff options
Diffstat (limited to 'src/config/runtime.rs')
-rw-r--r-- | src/config/runtime.rs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/config/runtime.rs b/src/config/runtime.rs new file mode 100644 index 0000000..58c86b9 --- /dev/null +++ b/src/config/runtime.rs @@ -0,0 +1,121 @@ +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, + }) + } +}
\ No newline at end of file |