}
},
}
+
+ #[throws(AE)]
+ fn subst(var: &mut String,
+ kv: &mut dyn Iterator<Item=(&'static str, &dyn Display)>
+ ) {
+ let substs = kv
+ .map(|(k,v)| (k.to_string(), v.to_string()))
+ .collect::<HashMap<String, String>>();
+ let bad = parking_lot::Mutex::new(vec![]);
+ *var = regex_replace_all!(
+ r#"%(?:%|\((\w+)\)s|.)"#,
+ &var,
+ |whole, k| (|| Ok::<_,String>({
+ if whole == "%%" { "%" }
+ else if k != "" {
+ substs.get(k).ok_or_else(
+ || format!("unknown key %({})s", k)
+ )?
+ } else {
+ throw!(format!("bad percent escape {:?}", &whole));
+ }
+ }))().unwrap_or_else(|e| { bad.lock().push(e); "" })
+ ).into_owned();
+ let bad = bad.into_inner();
+ if ! bad.is_empty() {
+ throw!(anyhow!("substitution failed: {}", bad.iter().format("; ")));
+ }
+ }
+
+ let ifname = match match end {
+ LinkEnd::Client => (&mut self.ifname_client, "ifname_client"),
+ LinkEnd::Server => (&mut self.ifname_server, "ifname_server"),
+ } { (var,name) => {
+ subst(var, &mut iter::empty()).context(name).context("interface name")?;
+ var
+ } };
+
+ {
+ use LinkEnd::*;
+ type DD<'d> = &'d dyn Display;
+ fn dv<T:Display>(v: &[T]) -> String {
+ format!("{}", v.iter().format(" "))
+ }
+ let vnetwork = dv(&self.vnetwork);
+ let vroutes = dv(&self.vroutes);
+
+ let keys = &["local", "peer", "rnets", "ifname"];
+ let values = match end {
+ Server => [&self.vaddr as DD , &self.vrelay, &vnetwork, ifname],
+ Client => [&self.link.client as DD, &self.vaddr, &vroutes, ifname],
+ };
+ subst(
+ &mut self.ipif,
+ &mut keys.iter().cloned()
+ .zip_eq(values)
+ .chain([( "mtu", &self.mtu as DD )].iter().cloned()),
+ ).context("ipif")?;
+ }
}
}
pub use std::fs;
pub use std::fmt::{self, Debug, Display};
pub use std::io::{self, ErrorKind, Read as _};
+pub use std::iter;
pub use std::mem;
pub use std::net::{IpAddr, Ipv4Addr};
pub use std::path::{Path, PathBuf};
pub use hyper_tls::HttpsConnector;
pub use ipnet::IpNet;
pub use itertools::{iproduct, Itertools};
-pub use lazy_regex::regex_is_match;
+pub use lazy_regex::{regex_is_match, regex_replace_all};
pub use log::{debug, info, error};
pub use structopt::StructOpt;
pub use tokio::task;