chiark / gitweb /
document and parse limit section headings
[hippotat.git] / src / config.rs
index 58ffd6cbdf4f89ce79abf1fffa096fef6ec354b2..63665f96f15071be3f81fef558da536984388d18 100644 (file)
@@ -57,17 +57,21 @@ pub struct InstanceConfig {
   pub vroutes:                      Vec<CidrString>,
 }
 
-#[derive(Debug,Clone)]
+#[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;
 
-type SectionMap = HashMap<SectionName, Option<String>>;
+#[derive(Debug,Clone)]
+struct RawVal { val: Option<String>, loc: Arc<PathBuf> }
+type SectionMap = HashMap<String, RawVal>;
 
 pub struct Config {
   opts: Opts,
@@ -77,7 +81,7 @@ static OUTSIDE_SECTION: &str = "[";
 
 #[derive(Default,Debug)]
 struct Aggregate {
-  sections: HashMap<String, SectionMap>,
+  sections: HashMap<SectionName, SectionMap>,
 }
 
 type OkAnyway<'f,A> = &'f dyn Fn(ErrorKind) -> Option<A>;
@@ -98,16 +102,19 @@ impl FromStr for SectionName {
     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>"
+        "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 }
   }
@@ -129,19 +136,24 @@ impl Aggregate {
     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
+    let loc = Arc::new(path.to_owned());
 
-    for (sn, vars) in map.drain() {
+    for (sn, vars) in map {
       let sn = sn.parse().dcontext(&sn)?;
-      self.sections.entry(sn)
+        self.sections.entry(sn)
         .or_default()
-        .extend(vars);
+        .extend(
+          vars.into_iter()
+            .map(|(k,val)| {
+              (k.replace('-',"_"),
+               RawVal { val, loc: loc.clone() })
+            })
+        );
     }
     None
   }
@@ -253,7 +265,7 @@ pub fn read() {
       agg.read_extra(extra).context("extra config")?;
     }
 
-    eprintln!("GOT {:?}", agg);
+    eprintln!("GOT {:#?}", agg);
 
     Ok::<_,AE>(())
   })().context("read configuration")?;