d3_components/
settings.rs

1extern crate config;
2extern crate serde;
3
4use config::{Config, ConfigError, Environment, File};
5use std::collections::{HashMap, HashSet};
6use std::env;
7
8/// Its unfortunate that we need to make all the bits public. There's
9/// possibly a way to avoid this with serde; I haven't figured it out
10/// yet.
11
12/// This is the top-level settings object
13#[derive(Debug, Default, Deserialize)]
14pub struct Settings {
15    pub dev_mode: bool,
16    pub log_level: String,
17    pub test_server_duration: u64,
18    pub executor: Option<Executor>,
19    pub features: HashSet<Feature>,
20    pub services: HashSet<Service>,
21    pub coordinator: Vec<HashMap<Coordinator, CoordinatorVariant>>,
22    pub component: Vec<HashMap<Component, ComponentVariant>>,
23    pub additional: Vec<HashMap<Additional, AdditionalVariant>>,
24}
25
26pub type Feature = String;
27pub type Service = String;
28pub type Coordinator = String;
29pub type Component = String;
30
31/// Some tuning params, these might be better as fields
32#[derive(Debug, Deserialize)]
33pub struct Executor {
34    pub executors: Option<usize>,
35    pub queue_size: Option<usize>,
36    pub time_slice: Option<usize>,
37}
38
39/// All of the coordinator config variants
40#[derive(Debug, Deserialize, Clone)]
41#[serde(untagged)]
42pub enum CoordinatorVariant {
43    SimpleTcpConfig {
44        tcp_address: String,
45        kv: Option<HashMap<String, String>>,
46    },
47    SimpleUdpConfig {
48        udp_address: String,
49        kv: Option<HashMap<String, String>>,
50    },
51}
52
53/// All of the component config variants
54#[derive(Debug, Deserialize, Clone, Eq, PartialEq)]
55#[serde(untagged)]
56pub enum ComponentVariant {
57    SimpleConfig {
58        enabled: bool,
59        kv: Option<HashMap<String, String>>,
60    },
61}
62
63/// There's always something that is being tinkered with.
64/// Additional is for those things that are being experimented with
65#[derive(Debug, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
66pub enum Additional {
67    Forwarder,
68}
69
70/// These are some fields, which may replace kv
71#[derive(Debug, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
72#[allow(non_camel_case_types)]
73pub enum Field {
74    daisy_chain,
75    fanout_fanin,
76    chaos_monkey,
77    forwarding_multiplier,
78    machines,
79    messages,
80    iterations,
81    timeout,
82    fanin_capacity,
83    inflection_value,
84    unbound_queue,
85}
86/// a more general solution would be to use a variant rather than usize
87pub type FieldMap = HashMap<Field, usize>;
88
89/// We don't want to mess with other variants while experimenting
90#[derive(Debug, Deserialize, Clone, Eq, PartialEq)]
91#[serde(untagged)]
92pub enum AdditionalVariant {
93    Forwarder {
94        run: Vec<Field>,
95        default: FieldMap,
96        daisy_chain: Option<FieldMap>,
97        fanout_fanin: Option<FieldMap>,
98        chaos_monkey: Option<FieldMap>,
99    },
100}
101
102/// Finally, we get to where we assemble the settings from all the
103/// different sources and freeze it.
104impl Settings {
105    pub fn new() -> Result<Self, ConfigError> {
106        let mut s = Config::new();
107
108        // Start off by merging in the "default" configuration file
109        s.merge(File::with_name("config/default"))?;
110
111        // Add in the current environment file
112        // Default to 'development' env
113        // Note that this file is _optional_
114        let env = env::var("RUN_MODE").unwrap_or_else(|_| "development".into());
115        s.merge(File::with_name(&format!("config/{}", env)).required(false))?;
116
117        // Add in a local configuration file
118        // This file shouldn't be checked in to git
119        s.merge(File::with_name("config/local").required(false))?;
120
121        // Add in settings from the environment (with a prefix of APP)
122        // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
123        s.merge(Environment::with_prefix("app"))?;
124
125        // You can deserialize (and thus freeze) the entire configuration as
126        s.try_into()
127    }
128}
129
130// Hopefully, most components will fit into this model
131#[derive(Debug, Default)]
132pub struct SimpleConfig {
133    pub enabled: bool,
134    pub kv: Option<HashMap<String, String>>,
135}
136impl SimpleConfig {
137    pub fn from(v: &ComponentVariant) -> Self {
138        match v.clone() {
139            ComponentVariant::SimpleConfig { enabled, kv } => Self { enabled, kv },
140        }
141    }
142}