batata_consul_client/
config.rs1use std::time::Duration;
2
3use crate::error::{ConsulError, Result};
4
5pub const DEFAULT_HTTP_PORT: u16 = 8500;
7pub const DEFAULT_ADDRESS: &str = "127.0.0.1:8500";
9pub const DEFAULT_SCHEME: &str = "http";
11
12#[derive(Clone, Debug, Default)]
14pub struct TlsConfig {
15 pub ca_cert: Option<String>,
17 pub ca_cert_pem: Option<Vec<u8>>,
19 pub client_cert: Option<String>,
21 pub client_cert_pem: Option<Vec<u8>>,
23 pub client_key: Option<String>,
25 pub client_key_pem: Option<Vec<u8>>,
27 pub insecure_skip_verify: bool,
29}
30
31impl TlsConfig {
32 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn with_ca_cert(mut self, path: &str) -> Self {
37 self.ca_cert = Some(path.to_string());
38 self
39 }
40
41 pub fn with_client_cert(mut self, cert_path: &str, key_path: &str) -> Self {
42 self.client_cert = Some(cert_path.to_string());
43 self.client_key = Some(key_path.to_string());
44 self
45 }
46
47 pub fn with_insecure_skip_verify(mut self) -> Self {
48 self.insecure_skip_verify = true;
49 self
50 }
51}
52
53#[derive(Clone, Debug)]
55pub struct HttpBasicAuth {
56 pub username: String,
58 pub password: String,
60}
61
62impl HttpBasicAuth {
63 pub fn new(username: &str, password: &str) -> Self {
64 Self {
65 username: username.to_string(),
66 password: password.to_string(),
67 }
68 }
69}
70
71#[derive(Clone, Debug)]
73pub struct Config {
74 pub address: String,
76 pub scheme: String,
78 pub datacenter: Option<String>,
80 pub http_auth: Option<HttpBasicAuth>,
82 pub token: Option<String>,
84 pub token_file: Option<String>,
86 pub tls_config: Option<TlsConfig>,
88 pub timeout: Duration,
90 pub namespace: Option<String>,
92 pub partition: Option<String>,
94}
95
96impl Default for Config {
97 fn default() -> Self {
98 Self {
99 address: DEFAULT_ADDRESS.to_string(),
100 scheme: DEFAULT_SCHEME.to_string(),
101 datacenter: None,
102 http_auth: None,
103 token: None,
104 token_file: None,
105 tls_config: None,
106 timeout: Duration::from_secs(30),
107 namespace: None,
108 partition: None,
109 }
110 }
111}
112
113impl Config {
114 pub fn new() -> Self {
116 Self::default()
117 }
118
119 pub fn from_env() -> Result<Self> {
121 let mut config = Self::default();
122
123 if let Ok(addr) = std::env::var("CONSUL_HTTP_ADDR") {
124 if addr.starts_with("https://") {
126 config.scheme = "https".to_string();
127 config.address = addr.trim_start_matches("https://").to_string();
128 } else if addr.starts_with("http://") {
129 config.scheme = "http".to_string();
130 config.address = addr.trim_start_matches("http://").to_string();
131 } else {
132 config.address = addr;
133 }
134 }
135
136 if let Ok(token) = std::env::var("CONSUL_HTTP_TOKEN") {
137 config.token = Some(token);
138 }
139
140 if let Ok(token_file) = std::env::var("CONSUL_HTTP_TOKEN_FILE") {
141 config.token_file = Some(token_file);
142 }
143
144 if let Ok(auth) = std::env::var("CONSUL_HTTP_AUTH") {
145 if let Some((username, password)) = auth.split_once(':') {
146 config.http_auth = Some(HttpBasicAuth::new(username, password));
147 }
148 }
149
150 if let Ok(ssl) = std::env::var("CONSUL_HTTP_SSL") {
151 if ssl == "true" || ssl == "1" {
152 config.scheme = "https".to_string();
153 }
154 }
155
156 if let Ok(verify) = std::env::var("CONSUL_HTTP_SSL_VERIFY") {
157 if verify == "false" || verify == "0" {
158 let mut tls = config.tls_config.unwrap_or_default();
159 tls.insecure_skip_verify = true;
160 config.tls_config = Some(tls);
161 }
162 }
163
164 if let Ok(ca_cert) = std::env::var("CONSUL_CACERT") {
165 let mut tls = config.tls_config.unwrap_or_default();
166 tls.ca_cert = Some(ca_cert);
167 config.tls_config = Some(tls);
168 }
169
170 if let Ok(client_cert) = std::env::var("CONSUL_CLIENT_CERT") {
171 let mut tls = config.tls_config.unwrap_or_default();
172 tls.client_cert = Some(client_cert);
173 config.tls_config = Some(tls);
174 }
175
176 if let Ok(client_key) = std::env::var("CONSUL_CLIENT_KEY") {
177 let mut tls = config.tls_config.unwrap_or_default();
178 tls.client_key = Some(client_key);
179 config.tls_config = Some(tls);
180 }
181
182 if let Ok(ns) = std::env::var("CONSUL_NAMESPACE") {
183 config.namespace = Some(ns);
184 }
185
186 if let Ok(partition) = std::env::var("CONSUL_PARTITION") {
187 config.partition = Some(partition);
188 }
189
190 Ok(config)
191 }
192
193 pub fn base_url(&self) -> String {
195 format!("{}://{}", self.scheme, self.address)
196 }
197
198 pub fn validate(&self) -> Result<()> {
200 if self.address.is_empty() {
201 return Err(ConsulError::InvalidConfig("address is required".to_string()));
202 }
203
204 if self.scheme != "http" && self.scheme != "https" {
205 return Err(ConsulError::InvalidConfig(format!(
206 "invalid scheme: {}",
207 self.scheme
208 )));
209 }
210
211 Ok(())
212 }
213}
214
215pub struct ConfigBuilder {
217 config: Config,
218}
219
220impl ConfigBuilder {
221 pub fn new() -> Self {
222 Self {
223 config: Config::default(),
224 }
225 }
226
227 pub fn address(mut self, address: &str) -> Self {
228 self.config.address = address.to_string();
229 self
230 }
231
232 pub fn scheme(mut self, scheme: &str) -> Self {
233 self.config.scheme = scheme.to_string();
234 self
235 }
236
237 pub fn datacenter(mut self, dc: &str) -> Self {
238 self.config.datacenter = Some(dc.to_string());
239 self
240 }
241
242 pub fn token(mut self, token: &str) -> Self {
243 self.config.token = Some(token.to_string());
244 self
245 }
246
247 pub fn http_auth(mut self, username: &str, password: &str) -> Self {
248 self.config.http_auth = Some(HttpBasicAuth::new(username, password));
249 self
250 }
251
252 pub fn tls_config(mut self, tls: TlsConfig) -> Self {
253 self.config.tls_config = Some(tls);
254 self
255 }
256
257 pub fn timeout(mut self, timeout: Duration) -> Self {
258 self.config.timeout = timeout;
259 self
260 }
261
262 pub fn namespace(mut self, ns: &str) -> Self {
263 self.config.namespace = Some(ns.to_string());
264 self
265 }
266
267 pub fn partition(mut self, partition: &str) -> Self {
268 self.config.partition = Some(partition.to_string());
269 self
270 }
271
272 pub fn build(self) -> Result<Config> {
273 self.config.validate()?;
274 Ok(self.config)
275 }
276}
277
278impl Default for ConfigBuilder {
279 fn default() -> Self {
280 Self::new()
281 }
282}