#![allow(dead_code)]
use std::collections::HashMap;
use crate::err::Error;
pub struct ParsedSpec<'a> {
pub(crate) addr: &'a str,
pub(crate) args: HashMap<&'a str, &'a str>
}
impl ParsedSpec<'_> {
pub(crate) fn parse(spec: &str) -> Result<ParsedSpec<'_>, Error> {
if spec.starts_with('{') && spec.ends_with('}') {
let s = &spec[1..spec.len() - 1];
let mut fields = s.split(',');
let Some(addr) = fields.next() else {
return Err(Error::BadProtSpec(
"Missing address field in spec".into()
));
};
let fields = fields.filter_map(|x| x.split_once('='));
let args: HashMap<&str, &str> = fields.collect::<HashMap<_, _>>();
Ok(ParsedSpec { addr, args })
} else {
Ok(ParsedSpec {
addr: spec,
args: HashMap::new()
})
}
}
}
impl ParsedSpec<'_> {
#[cfg(feature = "tls")]
pub(crate) fn is_tls(&self) -> Result<bool, Error> {
let is_tls = self.get_bool("tls")?;
if is_tls {
return Ok(true);
}
if self.args.contains_key("cafile") {
return Ok(true);
}
Ok(false)
}
#[cfg(unix)]
pub(crate) fn is_uds(&self) -> bool {
self.addr.find('/').is_some()
}
pub(crate) fn get_bool(&self, key: &str) -> Result<bool, Error> {
self.args.get(key).map_or(Ok(false), |val| match *val {
"yes" | "y" | "true" | "t" | "on" | "1" => Ok(true),
"no" | "n" | "false" | "f" | "off" | "0" => Ok(false),
_ => {
let msg = format!("Invalid boolean value '{val}' for key='{key}'");
Err(Error::BadProtSpec(msg))
}
})
}
}
#[cfg(test)]
mod tests {
use super::ParsedSpec;
#[test]
fn tcp() {
let ps = ParsedSpec::parse("127.0.0.1:1234").unwrap();
#[cfg(feature = "tls")]
assert!(!ps.is_tls().unwrap());
#[cfg(unix)]
assert!(!ps.is_uds());
assert_eq!(ps.addr, "127.0.0.1:1234");
}
#[cfg(unix)]
#[test]
fn uds() {
let ps = ParsedSpec::parse("/tmp/foo.sock").unwrap();
assert!(ps.is_uds());
assert_eq!(ps.addr, "/tmp/foo.sock");
}
#[cfg(feature = "tls")]
#[test]
fn tls() {
let ps = ParsedSpec::parse("{127.0.0.1:2345,tls=true}").unwrap();
assert!(ps.is_tls().unwrap());
assert_eq!(ps.addr, "127.0.0.1:2345");
}
#[cfg(feature = "tls")]
#[test]
fn tls_cafile() {
let ps = ParsedSpec::parse("{127.0.0.1:2345,tls=true,cafile=/tmp/ca.pem}")
.unwrap();
let cafile = ps.args.get("cafile").unwrap();
assert_eq!(*cafile, "/tmp/ca.pem");
}
}