Modular Diplonat (with the option to disable useless modules) #8
10 changed files with 131 additions and 70 deletions
|
@ -1,2 +1,75 @@
|
|||
unstable_features = true
|
||||
|
||||
array_width = 60
|
||||
attr_fn_like_width = 70
|
||||
binop_separator = "Front"
|
||||
blank_lines_lower_bound = 0
|
||||
blank_lines_upper_bound = 1
|
||||
brace_style = "SameLineWhere"
|
||||
chain_width = 60
|
||||
color = "Auto"
|
||||
combine_control_expr = true
|
||||
comment_width = 80
|
||||
condense_wildcard_suffixes = true
|
||||
control_brace_style = "AlwaysSameLine"
|
||||
disable_all_formatting = false
|
||||
empty_item_single_line = true
|
||||
enum_discrim_align_threshold = 0
|
||||
error_on_line_overflow = true
|
||||
error_on_unformatted = true
|
||||
fn_args_layout = "Tall"
|
||||
fn_call_width = 60
|
||||
fn_single_line = true
|
||||
force_explicit_abi = true
|
||||
force_multiline_blocks = false
|
||||
format_code_in_doc_comments = true
|
||||
# format_generated_files = true
|
||||
format_macro_matchers = true
|
||||
format_macro_bodies = true
|
||||
format_strings = true
|
||||
hard_tabs = false
|
||||
#hex_literal_case = "Lower"
|
||||
hide_parse_errors = false
|
||||
ignore = []
|
||||
imports_indent = "Block"
|
||||
imports_layout = "Mixed"
|
||||
indent_style = "Block"
|
||||
inline_attribute_width = 0
|
||||
license_template_path = ""
|
||||
match_arm_blocks = true
|
||||
match_arm_leading_pipes = "Never"
|
||||
match_block_trailing_comma = false
|
||||
max_width = 100
|
||||
merge_derives = true
|
||||
imports_granularity = "Crate"
|
||||
newline_style = "Unix"
|
||||
normalize_comments = true
|
||||
normalize_doc_attributes = true
|
||||
overflow_delimited_expr = false
|
||||
remove_nested_parens = true
|
||||
reorder_impl_items = true
|
||||
reorder_imports = true
|
||||
group_imports = "StdExternalCrate"
|
||||
reorder_modules = true
|
||||
report_fixme = "Unnumbered"
|
||||
report_todo = "Unnumbered"
|
||||
required_version = "1.4.37"
|
||||
skip_children = false
|
||||
single_line_if_else_max_width = 50
|
||||
space_after_colon = true
|
||||
space_before_colon = false
|
||||
#space_around_ranges = false
|
||||
struct_field_align_threshold = 0
|
||||
struct_lit_single_line = true
|
||||
struct_lit_width = 18
|
||||
struct_variant_width = 35
|
||||
tab_spaces = 2
|
||||
trailing_comma = "Vertical"
|
||||
trailing_semicolon = false
|
||||
type_punctuation_density = "Wide"
|
||||
use_field_init_shorthand = false
|
||||
use_small_heuristics = "Off"
|
||||
use_try_shorthand = true
|
||||
version = "Two"
|
||||
where_single_line = true
|
||||
wrap_comments = true
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::config::RuntimeConfig;
|
|||
// This file parses the options that can be declared in the environment.
|
||||
// runtime.rs applies business logic and builds RuntimeConfig structs.
|
||||
|
||||
// - Note for the future -
|
||||
// Note for the future
|
||||
// There is no *need* to have a 'DIPLONAT_XXX_*' prefix for all config options.
|
||||
// If some config options are shared by several modules, a ConfigOptsBase could
|
||||
// contain them, and parse the 'DIPLONAT_*' prefix directly.
|
||||
|
@ -87,9 +87,7 @@ impl ConfigOpts {
|
|||
// Currently only used in tests
|
||||
#[allow(dead_code)]
|
||||
pub fn from_iter<Iter: Clone>(iter: Iter) -> Result<RuntimeConfig>
|
||||
where
|
||||
Iter: IntoIterator<Item = (String, String)>,
|
||||
{
|
||||
where Iter: IntoIterator<Item = (String, String)> {
|
||||
let consul: ConfigOptsConsul = envy::prefixed("DIPLONAT_CONSUL_").from_iter(iter.clone())?;
|
||||
let acme: ConfigOptsAcme = envy::prefixed("DIPLONAT_ACME_").from_iter(iter.clone())?;
|
||||
let firewall: ConfigOptsFirewall =
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use crate::config::*;
|
||||
|
||||
|
@ -65,22 +64,22 @@ fn ok_minimal_valid_options() {
|
|||
assert!(rt_config.acme.is_none());
|
||||
assert!(rt_config.firewall.is_none());
|
||||
assert!(rt_config.igd.is_none());
|
||||
/*assert_eq!(
|
||||
rt_config.firewall.refresh_time,
|
||||
Duration::from_secs(REFRESH_TIME.into())
|
||||
);
|
||||
assert_eq!(
|
||||
&rt_config.igd.private_ip,
|
||||
opts.get(&"DIPLONAT_PRIVATE_IP".to_string()).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
rt_config.igd.expiration_time,
|
||||
Duration::from_secs(EXPIRATION_TIME.into())
|
||||
);
|
||||
assert_eq!(
|
||||
rt_config.igd.refresh_time,
|
||||
Duration::from_secs(REFRESH_TIME.into())
|
||||
);*/
|
||||
// assert_eq!(
|
||||
// rt_config.firewall.refresh_time,
|
||||
// Duration::from_secs(REFRESH_TIME.into())
|
||||
// );
|
||||
// assert_eq!(
|
||||
// &rt_config.igd.private_ip,
|
||||
// opts.get(&"DIPLONAT_PRIVATE_IP".to_string()).unwrap()
|
||||
// );
|
||||
// assert_eq!(
|
||||
// rt_config.igd.expiration_time,
|
||||
// Duration::from_secs(EXPIRATION_TIME.into())
|
||||
// );
|
||||
// assert_eq!(
|
||||
// rt_config.igd.refresh_time,
|
||||
// Duration::from_secs(REFRESH_TIME.into())
|
||||
// );
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -8,8 +8,8 @@ use crate::config::{
|
|||
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
|
@ -74,7 +74,7 @@ impl RuntimeConfigConsul {
|
|||
impl RuntimeConfigAcme {
|
||||
pub fn new(opts: ConfigOptsAcme) -> Result<Option<Self>> {
|
||||
if !opts.enable {
|
||||
return Ok(None);
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
let email = opts
|
||||
|
@ -88,7 +88,7 @@ impl RuntimeConfigAcme {
|
|||
impl RuntimeConfigFirewall {
|
||||
pub(super) fn new(opts: ConfigOptsFirewall) -> Result<Option<Self>> {
|
||||
if !opts.enable {
|
||||
return Ok(None);
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
let refresh_time = Duration::from_secs(opts.refresh_time.unwrap_or(super::REFRESH_TIME).into());
|
||||
|
@ -100,7 +100,7 @@ impl RuntimeConfigFirewall {
|
|||
impl RuntimeConfigIgd {
|
||||
pub(super) fn new(opts: ConfigOptsIgd) -> Result<Option<Self>> {
|
||||
if !opts.enable {
|
||||
return Ok(None);
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
let private_ip = opts
|
||||
|
@ -116,9 +116,11 @@ impl RuntimeConfigIgd {
|
|||
|
||||
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)",
|
||||
"IGD expiration time (currently: {}s) must be at least twice bigger than refresh time \
|
||||
(currently: {}s)",
|
||||
expiration_time.as_secs(),
|
||||
refresh_time.as_secs()));
|
||||
refresh_time.as_secs()
|
||||
))
|
||||
}
|
||||
|
||||
Ok(Some(Self {
|
||||
|
|
|
@ -25,12 +25,10 @@ impl Consul {
|
|||
client: reqwest::Client::new(),
|
||||
url: url.to_string(),
|
||||
idx: None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn watch_node_reset(&mut self) -> () {
|
||||
self.idx = None;
|
||||
}
|
||||
pub fn watch_node_reset(&mut self) -> () { self.idx = None; }
|
||||
|
||||
pub async fn watch_node(&mut self, host: &str) -> Result<CatalogNode> {
|
||||
let url = match self.idx {
|
||||
|
@ -45,6 +43,6 @@ impl Consul {
|
|||
};
|
||||
|
||||
let resp: CatalogNode = http.json().await?;
|
||||
return Ok(resp);
|
||||
return Ok(resp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
use std::cmp;
|
||||
use std::collections::HashSet;
|
||||
use std::time::Duration;
|
||||
use std::{cmp, collections::HashSet, time::Duration};
|
||||
|
||||
use anyhow::Result;
|
||||
use log::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_lexpr::{error, from_str};
|
||||
use tokio::sync::watch;
|
||||
use tokio::time::delay_for;
|
||||
use tokio::{sync::watch, time::delay_for};
|
||||
|
||||
use crate::config::RuntimeConfigConsul;
|
||||
use crate::consul;
|
||||
use crate::messages;
|
||||
use crate::{config::RuntimeConfigConsul, consul, messages};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum DiplonatParameter {
|
||||
|
@ -36,11 +31,12 @@ pub struct ConsulActor {
|
|||
|
||||
fn retry_to_time(retries: u32, max_time: Duration) -> Duration {
|
||||
// 1.2^x seems to be a good value to exponentially increase time at a good pace
|
||||
// eg. 1.2^32 = 341 seconds ~= 5 minutes - ie. after 32 retries we wait 5 minutes
|
||||
// eg. 1.2^32 = 341 seconds ~= 5 minutes - ie. after 32 retries we wait 5
|
||||
// minutes
|
||||
return Duration::from_secs(cmp::min(
|
||||
max_time.as_secs(),
|
||||
1.2f64.powf(retries as f64) as u64,
|
||||
));
|
||||
))
|
||||
}
|
||||
|
||||
fn to_parameters(catalog: &consul::CatalogNode) -> Vec<DiplonatConsul> {
|
||||
|
@ -56,7 +52,7 @@ fn to_parameters(catalog: &consul::CatalogNode) -> Vec<DiplonatConsul> {
|
|||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
return r
|
||||
}
|
||||
|
||||
fn to_open_ports(params: &Vec<DiplonatConsul>) -> messages::PublicExposedPorts {
|
||||
|
@ -75,7 +71,7 @@ fn to_open_ports(params: &Vec<DiplonatConsul>) -> messages::PublicExposedPorts {
|
|||
}
|
||||
}
|
||||
|
||||
return op;
|
||||
return op
|
||||
}
|
||||
|
||||
impl ConsulActor {
|
||||
|
@ -91,7 +87,7 @@ impl ConsulActor {
|
|||
retries: 0,
|
||||
rx_open_ports: rx,
|
||||
tx_open_ports: tx,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn listen(&mut self) -> Result<()> {
|
||||
|
@ -108,7 +104,7 @@ impl ConsulActor {
|
|||
e
|
||||
);
|
||||
delay_for(will_retry_in).await;
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
};
|
||||
self.retries = 0;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use tokio::try_join;
|
||||
|
||||
use crate::config::ConfigOpts;
|
||||
use crate::consul_actor::ConsulActor;
|
||||
use crate::fw_actor::FirewallActor;
|
||||
use crate::igd_actor::IgdActor;
|
||||
use crate::{
|
||||
config::ConfigOpts, consul_actor::ConsulActor, fw_actor::FirewallActor, igd_actor::IgdActor,
|
||||
};
|
||||
|
||||
pub struct Diplonat {
|
||||
consul: ConsulActor,
|
||||
|
@ -27,7 +26,7 @@ impl Diplonat {
|
|||
if firewall_actor.is_none() && igd_actor.is_none() {
|
||||
return Err(anyhow!(
|
||||
"At least enable *one* module, otherwise it's boring!"
|
||||
));
|
||||
))
|
||||
}
|
||||
|
||||
let ctx = Self {
|
||||
|
@ -36,7 +35,7 @@ impl Diplonat {
|
|||
igd: igd_actor,
|
||||
};
|
||||
|
||||
return Ok(ctx);
|
||||
return Ok(ctx)
|
||||
}
|
||||
|
||||
pub async fn listen(&mut self) -> Result<()> {
|
||||
|
@ -59,6 +58,6 @@ impl Diplonat {
|
|||
},
|
||||
)?;
|
||||
|
||||
return Ok(());
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@ use tokio::{
|
|||
time::{self, Duration},
|
||||
};
|
||||
|
||||
use crate::config::RuntimeConfigFirewall;
|
||||
use crate::fw;
|
||||
use crate::messages;
|
||||
use crate::{config::RuntimeConfigFirewall, fw, messages};
|
||||
|
||||
pub struct FirewallActor {
|
||||
pub ipt: iptables::IPTables,
|
||||
|
@ -28,7 +26,7 @@ impl FirewallActor {
|
|||
rxp: &watch::Receiver<messages::PublicExposedPorts>,
|
||||
) -> Result<Option<Self>> {
|
||||
if config.is_none() {
|
||||
return Ok(None);
|
||||
return Ok(None)
|
||||
}
|
||||
let config = config.unwrap();
|
||||
|
||||
|
@ -41,7 +39,7 @@ impl FirewallActor {
|
|||
|
||||
fw::setup(&ctx.ipt)?;
|
||||
|
||||
return Ok(Some(ctx));
|
||||
return Ok(Some(ctx))
|
||||
}
|
||||
|
||||
pub async fn listen(&mut self) -> Result<()> {
|
||||
|
@ -90,6 +88,6 @@ impl FirewallActor {
|
|||
|
||||
fw::open_ports(&self.ipt, ports_to_open)?;
|
||||
|
||||
return Ok(());
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::net::SocketAddrV4;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use igd::aio::*;
|
||||
use igd::PortMappingProtocol;
|
||||
use igd::{aio::*, PortMappingProtocol};
|
||||
use log::*;
|
||||
use tokio::{
|
||||
select,
|
||||
|
@ -10,8 +9,7 @@ use tokio::{
|
|||
time::{self, Duration},
|
||||
};
|
||||
|
||||
use crate::config::RuntimeConfigIgd;
|
||||
use crate::messages;
|
||||
use crate::{config::RuntimeConfigIgd, messages};
|
||||
|
||||
pub struct IgdActor {
|
||||
expire: Duration,
|
||||
|
@ -29,7 +27,7 @@ impl IgdActor {
|
|||
rxp: &watch::Receiver<messages::PublicExposedPorts>,
|
||||
) -> Result<Option<Self>> {
|
||||
if config.is_none() {
|
||||
return Ok(None);
|
||||
return Ok(None)
|
||||
}
|
||||
let config = config.unwrap();
|
||||
|
||||
|
@ -47,7 +45,7 @@ impl IgdActor {
|
|||
rx_ports: rxp.clone(),
|
||||
};
|
||||
|
||||
return Ok(Some(ctx));
|
||||
return Ok(Some(ctx))
|
||||
}
|
||||
|
||||
pub async fn listen(&mut self) -> Result<()> {
|
||||
|
@ -99,6 +97,6 @@ impl IgdActor {
|
|||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ impl PublicExposedPorts {
|
|||
return Self {
|
||||
tcp_ports: HashSet::new(),
|
||||
udp_ports: HashSet::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue