ddmw_client/
conf.rs

1//! DDMW client applications (including proxies) will contain common
2//! configuration parameters.  This module is used to provide a
3//! defacto-standard interface and layout for loading client configuration
4//! parameters.
5
6#[cfg(windows)]
7pub mod winsvc;
8
9use std::path::{Path, PathBuf};
10
11use serde::Deserialize;
12
13use crate::auth::Auth;
14
15use figment::{
16  providers::{Format, Toml},
17  Figment
18};
19
20use protwrap::ProtAddr;
21
22use crate::err::Error;
23use crate::types::AppChannel;
24
25
26#[derive(Debug, Default, Deserialize)]
27pub struct Config {
28  pub channel: Option<String>,
29  pub auth: Option<Auth>,
30  pub sender: Option<Sender>,
31  pub receiver: Option<Receiver>
32}
33
34impl Config {
35  pub fn set_appch(&mut self, appch: AppChannel) -> &mut Self {
36    self.channel = Some(appch.to_string());
37    self
38  }
39
40  pub fn get_appch(&self) -> Result<Option<AppChannel>, Error> {
41    if let Some(appch) = &self.channel {
42      match appch.parse::<AppChannel>() {
43        Ok(appch) => {
44          return Ok(Some(appch));
45        }
46        Err(e) => {
47          let err = format!("AppChannel, {}", e);
48          return Err(Error::parse(err));
49        }
50      }
51    }
52    Ok(None)
53  }
54
55  pub fn set_sender_msgif(&mut self, pa: ProtAddr) -> &mut Self {
56    if self.sender.is_none() {
57      self.sender = Some(Sender::default());
58    }
59    if let Some(ref mut sender) = self.sender {
60      sender.msgif = Some(pa.to_string());
61    }
62    self
63  }
64
65  pub fn get_sender_msgif(&self) -> Result<Option<ProtAddr>, Error> {
66    if let Some(sender) = &self.sender {
67      if let Some(addr) = &sender.msgif {
68        match addr.parse::<ProtAddr>() {
69          Ok(addr) => {
70            return Ok(Some(addr));
71          }
72          Err(_) => {
73            return Err(Error::parse(String::from("ProtAddr")));
74          }
75        }
76      }
77    }
78    Ok(None)
79  }
80
81  pub fn set_auth_account(&mut self, name: &str) -> &mut Self {
82    if self.auth.is_none() {
83      self.auth = Some(Auth::default());
84    }
85    if let Some(ref mut auth) = self.auth {
86      auth.name = Some(name.to_string());
87    }
88    self
89  }
90  pub fn set_auth_pass(&mut self, pass: &str) -> &mut Self {
91    if self.auth.is_none() {
92      self.auth = Some(Auth::default());
93    }
94    if let Some(ref mut auth) = self.auth {
95      auth.pass = Some(pass.to_string());
96    }
97    self
98  }
99  pub fn set_auth_pass_file(&mut self, passfile: &str) -> &mut Self {
100    if self.auth.is_none() {
101      self.auth = Some(Auth::default());
102    }
103    if let Some(ref mut auth) = self.auth {
104      auth.pass_file = Some(passfile.to_string());
105    }
106    self
107  }
108  pub fn set_auth_token(&mut self, tkn: &str) -> &mut Self {
109    if self.auth.is_none() {
110      self.auth = Some(Auth::default());
111    }
112    if let Some(ref mut auth) = self.auth {
113      auth.token = Some(tkn.to_string());
114    }
115    self
116  }
117  pub fn set_auth_token_file(&mut self, tknfile: &str) -> &mut Self {
118    if self.auth.is_none() {
119      self.auth = Some(Auth::default());
120    }
121    if let Some(ref mut auth) = self.auth {
122      auth.token_file = Some(tknfile.to_string());
123    }
124    self
125  }
126}
127
128#[derive(Debug, Default, Deserialize)]
129pub struct Sender {
130  pub mgmtif: Option<String>,
131  pub msgif: Option<String>
132}
133
134
135#[derive(Debug, Default, Deserialize)]
136pub struct Receiver {
137  pub mgmtif: Option<String>,
138  pub subif: Option<String>,
139  #[serde(rename = "sub-retries")]
140  pub sub_retries: Option<u32>,
141  #[serde(rename = "sub-retry-delay")]
142  pub sub_retry_delay: Option<String>,
143  #[serde(rename = "push-listenif")]
144  pub push_listenif: Option<String>
145}
146
147
148/// Load a DDMW application configuration file.
149///
150/// Attempt to load a configuration file in the following order:
151/// 1. If `fname` has `Some` value, its value will be used.  Otherwise:
152/// 2. If the environment variable `DDMW_APPCONF` is set, its value will be
153///    used.  Otherwise:
154/// 3. The filename `ddmwapp.toml`, in the current working directory, will be
155///    used.
156///
157/// If none of these could be be found, `Ok(None)` will be returned.
158///
159/// # Example
160/// Attempt to load a "hello.toml", and return a default `Config` buffer if
161/// unsuccessful.
162///
163/// ```no_run
164/// use std::path::Path;
165/// use ddmw_client::conf::{Config, load};
166/// use ddmw_client::Error;
167/// fn get_conf() -> Result<Config, Error> {
168///   let fname = Path::new("hello.toml");
169///   let fig = load(Some(&fname))?.expect("Load failed");
170///   let conf = fig.extract::<Config>()?;
171///   Ok(conf)
172/// }
173/// ```
174pub fn load(fname: Option<&Path>) -> Result<Option<Figment>, Error> {
175  let f = match fname {
176    Some(p) => p.to_path_buf(),
177    None => match std::env::var_os("DDMW_APPCONF") {
178      Some(val) => PathBuf::from(val),
179      None => PathBuf::from("ddmwapp.toml")
180    }
181  };
182
183  let ret = if !f.exists() {
184    None
185  } else {
186    let conf = Figment::new().merge(Toml::file(f));
187    Some(conf)
188  };
189  Ok(ret)
190}
191
192
193/// Given a loaded [`Figment`], extract an [`Auth`] buffer.
194pub fn extract_auth(fig: &Figment) -> Result<Auth, Error> {
195  let auth: Auth = fig.extract_inner("auth")?;
196
197  Ok(auth)
198}
199
200// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :