pub vroutes: Vec<CidrString>,
}
-type SectionMap = HashMap<String, Option<String>>;
+#[derive(Debug,Clone,Hash,Eq,PartialEq)]
+pub enum SectionName {
+ Link { server: ServerName, client: ClientName },
+ Client(ClientName),
+ Server(ServerName), // includes SERVER, which is slightly special
+ ServerLimit(ServerName),
+ GlobalLimit,
+ Common,
+ Default,
+}
+pub use SectionName as SN;
+
+#[derive(Debug,Clone)]
+struct RawVal { val: Option<String>, loc: Arc<PathBuf> }
+type SectionMap = HashMap<String, RawVal>;
pub struct Config {
opts: Opts,
#[derive(Default,Debug)]
struct Aggregate {
- sections: HashMap<String, SectionMap>,
+ sections: HashMap<SectionName, SectionMap>,
}
type OkAnyway<'f,A> = &'f dyn Fn(ErrorKind) -> Option<A>;
}
}
+impl FromStr for SectionName {
+ type Err = AE;
+ #[throws(AE)]
+ fn from_str(s: &str) -> Self {
+ match s {
+ "COMMON" => return SN::Common,
+ "DEFAULT" => return SN::Default,
+ "LIMIT" => return SN::GlobalLimit,
+ _ => { }
+ };
+ if let Ok(n@ ServerName(_)) = s.parse() { return SN::Server(n) }
+ if let Ok(n@ ClientName(_)) = s.parse() { return SN::Client(n) }
+ let (server, client) = s.split_ascii_whitespace().collect_tuple()
+ .ok_or_else(|| anyhow!(
+ "bad section name {:?} \
+ (must be COMMON, DEFAULT, <server>, <client>, or <server> <client>",
+ s
+ ))?;
+ let server = server.parse().context("server name in link section name")?;
+ if client == "LIMIT" { return SN::ServerLimit(server) }
+ let client = client.parse().context("client name in link section name")?;
+ SN::Link { server, client }
+ }
+}
+
impl Aggregate {
#[throws(AE)] // AE does not include path
fn read_file<A>(&mut self, path: &Path, anyway: OkAnyway<A>) -> Option<A>
let mut ini = Ini::new_cs();
ini.set_default_section(OUTSIDE_SECTION);
ini.read(s).map_err(|e| anyhow!("{}", e)).context("parse as INI")?;
- let mut map = mem::take(ini.get_mut_map());
+ let map = mem::take(ini.get_mut_map());
if map.get(OUTSIDE_SECTION).is_some() {
throw!(anyhow!("INI file contains settings outside a section"));
}
- // xxx parse section names here
- // xxx save Arc<PathBuf> where we found each item
-
- self.sections.extend(map.drain());
+ let loc = Arc::new(path.to_owned());
+
+ for (sn, vars) in map {
+ let sn = sn.parse().dcontext(&sn)?;
+ self.sections.entry(sn)
+ .or_default()
+ .extend(
+ vars.into_iter()
+ .map(|(k,val)| {
+ (k.replace('-',"_"),
+ RawVal { val, loc: loc.clone() })
+ })
+ );
+ }
None
}
agg.read_extra(extra).context("extra config")?;
}
- eprintln!("GOT {:?}", agg);
+ eprintln!("GOT {:#?}", agg);
Ok::<_,AE>(())
})().context("read configuration")?;