cfx_config/
config_macro.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5macro_rules! if_option {
6	(Option<$type:ty>, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
7		$($then)*
8	);
9	($type:ty, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
10		$($otherwise)*
11	);
12}
13
14macro_rules! underscore_to_hyphen {
15    ($e:expr) => {
16        str::replace($e, "_", "-")
17    };
18}
19
20#[macro_export]
21macro_rules! build_config{
22    (
23        {
24            $(($name:ident, ($($type:tt)+), $default:expr))*
25        }
26        {
27            $(($c_name:ident, ($($c_type:tt)+), $c_default:expr, $converter:expr))*
28        }
29    ) => {
30        use cfxcore::pow::ProofOfWorkConfig;
31        use cfxcore::verification::VerificationConfig;
32        use cfxcore::cache_config::CacheConfig;
33        use clap;
34        use cfxcore::db::NUM_COLUMNS;
35        use db;
36        use kvdb_rocksdb::DatabaseConfig;
37        use log::LevelFilter;
38        use network::{node_table::validate_node_url, NetworkConfiguration};
39        use std::{
40            fs::{self, File},
41            io::prelude::*,
42            net::ToSocketAddrs,
43            path::Path,
44            str::FromStr,
45            time::Duration,
46        };
47        use toml;
48
49        #[derive(Debug, PartialEq, Clone)]
50        pub struct RawConfiguration {
51            $(pub $name: $($type)+,)*
52            $(pub $c_name: $($c_type)+,)*
53        }
54
55        impl Default for RawConfiguration {
56            fn default() -> Self {
57                RawConfiguration {
58                    $($name: $default,)*
59                    $($c_name: $c_default,)*
60                }
61            }
62        }
63        impl RawConfiguration {
64            // First parse arguments from config file,
65            // and then parse them from commandline.
66            // Replace the ones from config file with the ones
67            // from commandline if duplicates.
68            pub fn parse(matches: &clap::ArgMatches) -> Result<RawConfiguration, String> {
69                let mut config = if let Ok(Some(config_filename)) = matches.try_get_one::<String>("config")  {
70                    RawConfiguration::from_file(config_filename)?
71
72                } else {
73                    RawConfiguration::default()
74                };
75                $(
76                    if let Ok(Some(value)) = matches.try_get_one::<String>(underscore_to_hyphen!(stringify!($name)).as_str()) {
77                        config.$name = if_option!(
78                                $($type)+,
79                                THEN{ Some(value.parse().map_err(|_| concat!("Invalid ", stringify!($name)).to_owned())?) }
80                                ELSE{ value.parse().map_err(|_| concat!("Invalid ", stringify!($name)).to_owned())? }
81                            );
82                    }
83                )*
84                $(
85                    if let Ok(Some(value)) = matches.try_get_one::<String>(underscore_to_hyphen!(stringify!($c_name)).as_str()) {
86                        config.$c_name = if_option!(
87                                $($c_type)+,
88                                THEN{ Some($converter(value)?) }
89                                ELSE{ $converter(value)? }
90                            )
91                    }
92                )*
93                Ok(config)
94            }
95            pub fn from_file(config_path: &str) ->  Result<RawConfiguration, String> {
96
97                let mut config = RawConfiguration::default();
98
99                let mut config_file = File::open(config_path)
100                .map_err(|e| format!("failed to open configuration file: {:?}", e))?;
101
102                let mut config_str = String::new();
103                config_file
104                    .read_to_string(&mut config_str)
105                    .map_err(|e| format!("failed to read configuration file: {:?}", e))?;
106
107                let config_value = config_str.parse::<toml::Value>()
108                    .map_err(|e| format!("failed to parse configuration file: {:?}", e))?;
109                $(
110                    if let Some(value) = config_value.get(stringify!($name)) {
111                        config.$name = if_option!(
112                            $($type)+,
113                            THEN{ Some(value.clone().try_into().map_err(|e| format!("Invalid {}: err={:?}", stringify!($name), e).to_owned())?) }
114                            ELSE{ value.clone().try_into().map_err(|e| format!("Invalid {}: err={:?}", stringify!($name), e).to_owned())? }
115                        );
116                    }
117                )*
118
119                $(
120                  if let Some(value) = config_value.get(stringify!($c_name)) {
121                        config.$c_name = if_option!(
122                            $($c_type)+,
123                            THEN{ Some($converter(value.as_str().unwrap())?) }
124                            ELSE{ $converter(value.as_str().unwrap())? }
125                        )
126                    }
127                )*
128                Ok(config)
129         }
130        }
131    }
132}
133
134#[macro_export]
135macro_rules! set_conf {
136    ($src: expr; $dst: expr => {$($field: tt),* }) => {
137        {
138            let number = $src;
139            $($dst.$field = number;)*
140        }
141    };
142}