1use crate::args::Args;
2
3#[derive(Clone)]
5pub struct CtlConfig {
6 pub host: String,
8 pub port: u16,
10 pub auth_token: Option<String>,
12 pub disable_auth: bool,
14 pub config_path: Option<String>,
16 pub daemon_mode: bool,
18 pub tls_cert: Option<String>,
20 pub tls_key: Option<String>,
22}
23
24impl Default for CtlConfig {
25 fn default() -> Self {
26 CtlConfig {
27 host: "127.0.0.1".into(),
28 port: 8080,
29 auth_token: None,
30 disable_auth: false,
31 config_path: None,
32 daemon_mode: false,
33 tls_cert: None,
34 tls_key: None,
35 }
36 }
37}
38
39pub fn from_args_and_env(args: &Args) -> CtlConfig {
41 let mut cfg = CtlConfig::default();
42
43 cfg.host = args
45 .get("host")
46 .or_else(|| args.get("H"))
47 .map(String::from)
48 .or_else(|| std::env::var("RNSCTL_HOST").ok())
49 .unwrap_or(cfg.host);
50
51 cfg.port = args
52 .get("port")
53 .or_else(|| args.get("p"))
54 .and_then(|s| s.parse().ok())
55 .or_else(|| {
56 std::env::var("RNSCTL_HTTP_PORT")
57 .ok()
58 .and_then(|s| s.parse().ok())
59 })
60 .unwrap_or(cfg.port);
61
62 cfg.auth_token = args
63 .get("token")
64 .or_else(|| args.get("t"))
65 .map(String::from)
66 .or_else(|| std::env::var("RNSCTL_AUTH_TOKEN").ok());
67
68 cfg.disable_auth = args.has("disable-auth")
69 || std::env::var("RNSCTL_DISABLE_AUTH")
70 .map(|v| v == "true" || v == "1")
71 .unwrap_or(false);
72
73 cfg.config_path = args
74 .get("config")
75 .or_else(|| args.get("c"))
76 .map(String::from)
77 .or_else(|| std::env::var("RNSCTL_CONFIG_PATH").ok());
78
79 cfg.daemon_mode = args.has("daemon") || args.has("d");
80
81 cfg.tls_cert = args
82 .get("tls-cert")
83 .map(String::from)
84 .or_else(|| std::env::var("RNSCTL_TLS_CERT").ok());
85
86 cfg.tls_key = args
87 .get("tls-key")
88 .map(String::from)
89 .or_else(|| std::env::var("RNSCTL_TLS_KEY").ok());
90
91 cfg
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 fn args(s: &[&str]) -> Args {
99 Args::parse_from(s.iter().map(|s| s.to_string()).collect())
100 }
101
102 #[test]
103 fn parse_basic() {
104 let a = args(&["--port", "9090", "--host", "0.0.0.0", "-vv"]);
105 assert_eq!(a.get("port"), Some("9090"));
106 assert_eq!(a.get("host"), Some("0.0.0.0"));
107 assert_eq!(a.verbosity, 2);
108 }
109
110 #[test]
111 fn parse_short_config() {
112 let a = args(&["-c", "/tmp/rns"]);
113 assert_eq!(a.get("c"), Some("/tmp/rns"));
114 }
115
116 #[test]
117 fn parse_daemon_short() {
118 let a = args(&["-d"]);
119 assert!(a.has("d"));
120 let cfg = from_args_and_env(&a);
121 assert!(cfg.daemon_mode);
122 }
123
124 #[test]
125 fn parse_daemon_long() {
126 let a = args(&["--daemon"]);
127 assert!(a.has("daemon"));
128 let cfg = from_args_and_env(&a);
129 assert!(cfg.daemon_mode);
130 }
131
132 #[test]
133 fn parse_disable_auth() {
134 let a = args(&["--disable-auth"]);
135 assert!(a.has("disable-auth"));
136 }
137
138 #[test]
139 fn parse_help() {
140 let a = args(&["--help"]);
141 assert!(a.has("help"));
142 let a = args(&["-h"]);
143 assert!(a.has("help"));
144 }
145
146 #[test]
147 fn config_from_args() {
148 let a = args(&[
149 "--port", "3000", "--host", "0.0.0.0", "--token", "secret", "--daemon",
150 ]);
151 let cfg = from_args_and_env(&a);
152 assert_eq!(cfg.port, 3000);
153 assert_eq!(cfg.host, "0.0.0.0");
154 assert_eq!(cfg.auth_token.as_deref(), Some("secret"));
155 assert!(cfg.daemon_mode);
156 }
157}