changeset 23:2b5e442c8bbb draft

Move rule logic into dedicated module
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 04 Dec 2016 16:32:37 +0100
parents 226f1c607612
children ed9eb9cfeb83
files src/config.rs src/rule.rs
diffstat 2 files changed, 173 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- a/src/config.rs	Sat Dec 03 16:27:07 2016 +0100
+++ b/src/config.rs	Sun Dec 04 16:32:37 2016 +0100
@@ -13,6 +13,7 @@
 use toml;
 
 use priority;
+use rule::{self, Rule};
 
 /// Parses strings like 0/1s/2m/3h/4d/5w and returns seconds. If no unit is there, seconds is
 /// assumed.
@@ -183,7 +184,7 @@
     Some(res)
 }
 
-fn tomlerr<T>(s: String) -> Result<T, toml::Error> {
+pub fn tomlerr<T>(s: String) -> Result<T, toml::Error> {
     Err(toml::Error::Custom(s))
 }
 
@@ -280,174 +281,17 @@
     Ok(f)
 }
 
-#[derive(Clone, Debug)]
-pub enum FacPattern {
-    /// '*'
-    Wildcard,
-    Facility(priority::Facility),
-    MultiFacility(Vec<priority::Facility>),
-}
-
-#[derive(Clone, Debug)]
-pub enum LvlPattern {
-    Wildcard,
-    /// Matches that level, or any lower (more important) level
-    Level(priority::Level),
-    /// Matches only that level
-    ExactLevel(priority::Level),
-    MultiLevel(Vec<priority::Level>),
-}
-
-impl Default for FacPattern {
-    fn default() -> FacPattern {
-        FacPattern::Wildcard
-    }
-}
-
-impl Default for LvlPattern {
-    fn default() -> LvlPattern {
-        LvlPattern::Wildcard
-    }
-}
-
-/// A Filter specifies one or more Facilities, and one or more Levels.
-type Filter = (FacPattern, LvlPattern);
-/// A Matcher is one or more Filters.
-type Matcher = Vec<Filter>;
-
-/// a pattern for a rule matches syslog messages based on level and facility. Valid patterns
-/// are:
-///
-/// *.* -- match all
-/// mail.* -- match all mail records
-/// mail,news.* -- match all mail and news records
-/// mail.warn,info -- match all mail records at warn or info
-/// mail,news.info,warn -- match all mail or news records at warn or info.
-/// mail.*;news,auth.info -- match all mail records and records for news or auth at info or higher
-/// (!) => if only a single level is given, this means "this level or more important"; if you only want to
-/// match that single level, use a rule like "mail.=info".
-fn parse_matcher(s: &str) -> Result<Matcher, toml::Error> {
-    let mut matcher = Vec::with_capacity(3);
-
-    for filter in s.trim().split(';') {
-        if filter.len() == 0 {
-            return Ok(matcher);
-        }
-
-        match parse_filter(filter) {
-            Ok(f) => matcher.push(f),
-            Err(e) => return Err(e),
-        }
-    }
-    Ok(matcher)
-}
-
-fn parse_filter(s: &str) -> Result<Filter, toml::Error> {
-    let mut parts = s.trim().split('.');
-
-    if let Some(facilities) = parts.next() {
-        if let Some(levels) = parts.next() {
-            return match (parse_facility_pattern(facilities), parse_level_pattern(levels)) {
-                (Ok(f), Ok(l)) => Ok((f, l)),
-                (Err(e), Err(f)) => tomlerr(format!("{} {}", e, f)),
-                (Ok(_), Err(e)) => tomlerr(format!("{}", e)),
-                (Err(e), Ok(_)) => tomlerr(format!("{}", e)),
-            };
-        }
-    }
-    tomlerr(format!("Bad filter pattern: {}", s))
-}
-
-fn parse_facility_pattern(s: &str) -> Result<FacPattern, toml::Error> {
-    let list: Vec<String> = s.trim().split(',').map(String::from).collect();
-
-    if list.len() > 1 {
-        let mut facilities = Vec::with_capacity(list.len());
-
-        for f in list {
-            if let Some(fac) = priority::str_to_facility(f.trim()) {
-                facilities.push(fac);
-            } else {
-                return tomlerr(format!("Unrecognized facility: {}", f));
-            }
-        }
-        Ok(FacPattern::MultiFacility(facilities))
-    } else if list.len() == 1 {
-        let l = &list[0];
-
-        if l == "*" {
-            Ok(FacPattern::Wildcard)
-        } else if let Some(fac) = priority::str_to_facility(l) {
-            Ok(FacPattern::Facility(fac))
-        } else {
-            tomlerr(format!("Unknown facility: {}", l))
-        }
-    } else {
-        return tomlerr(format!("Level pattern can't be empty"));
-    }
-}
-
-fn parse_level_pattern(s: &str) -> Result<LvlPattern, toml::Error> {
-    let list: Vec<String> = s.trim().split(',').map(String::from).collect();
-
-    if list.len() > 1 {
-        let mut levels = Vec::with_capacity(list.len());
-
-        for l in list {
-            if let Some(lvl) = priority::str_to_level(l.trim()) {
-                levels.push(lvl);
-            } else {
-                return tomlerr(format!("Unrecognized facility: {}", l));
-            }
-        }
-        Ok(LvlPattern::MultiLevel(levels))
-    } else if list.len() == 1 {
-        let l = &list[0];
-
-        // exact rule
-        if &l[0..1] == "=" {
-            if let Some(fac) = priority::str_to_level(&l[1..]) {
-                Ok(LvlPattern::ExactLevel(fac))
-            } else {
-                tomlerr(format!("Unknown exact facility: {}", l))
-            }
-        } else if &l[..] == "*" {
-            Ok(LvlPattern::Wildcard)
-        } else if let Some(lvl) = priority::str_to_level(l) {
-            Ok(LvlPattern::Level(lvl))
-        } else {
-            tomlerr(format!("Unknown facility: {}", &list[0]))
-        }
-    } else {
-        return tomlerr(format!("Level pattern can't be empty"));
-    }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct Rule {
-    pattern: Matcher,
-    // refers to the file entry name, not the file name.
-    file: String,
-    remote_dest: String,
-    stop: bool,
-}
-
 /// Takes a "rule" table
 fn assemble_rule(t: &toml::Table) -> Result<Rule, toml::Error> {
     let pattern = get_string(t, "pattern", "".to_string());
-    let matcher = try!(parse_matcher(&pattern));
+    let matcher = try!(rule::parse_matcher(&pattern));
 
     let file = get_string(t, "dest", "null".to_string());
     let remote = get_string(t, "remote_dest", "".to_string());
 
     let stop = get_bool(t, "stop", false);
 
-    Ok(Rule {
-        pattern: matcher,
-        file: file,
-        remote_dest: remote,
-        stop: stop,
-    })
+    Ok(rule::new_rule(matcher, file, remote, stop))
 }
 
 #[derive(Clone, Debug, Default)]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/rule.rs	Sun Dec 04 16:32:37 2016 +0100
@@ -0,0 +1,169 @@
+#![allow(dead_code)]
+
+use std::default::Default;
+
+use toml;
+
+use config::tomlerr;
+use priority;
+
+#[derive(Clone, Debug)]
+pub enum FacPattern {
+    /// '*'
+    Wildcard,
+    Facility(priority::Facility),
+    MultiFacility(Vec<priority::Facility>),
+}
+
+#[derive(Clone, Debug)]
+pub enum LvlPattern {
+    Wildcard,
+    /// Matches that level, or any lower (more important) level
+    Level(priority::Level),
+    /// Matches only that level
+    ExactLevel(priority::Level),
+    MultiLevel(Vec<priority::Level>),
+}
+
+impl Default for FacPattern {
+    fn default() -> FacPattern {
+        FacPattern::Wildcard
+    }
+}
+
+impl Default for LvlPattern {
+    fn default() -> LvlPattern {
+        LvlPattern::Wildcard
+    }
+}
+
+/// A Filter specifies one or more Facilities, and one or more Levels.
+type Filter = (FacPattern, LvlPattern);
+/// A Matcher is one or more Filters.
+type Matcher = Vec<Filter>;
+
+/// a pattern for a rule matches syslog messages based on level and facility. Valid patterns
+/// are:
+///
+/// *.* -- match all
+/// mail.* -- match all mail records
+/// mail,news.* -- match all mail and news records
+/// mail.warn,info -- match all mail records at warn or info
+/// mail,news.info,warn -- match all mail or news records at warn or info.
+/// mail.*;news,auth.info -- match all mail records and records for news or auth at info or higher
+/// (!) => if only a single level is given, this means "this level or more important"; if you only want to
+/// match that single level, use a rule like "mail.=info".
+pub fn parse_matcher(s: &str) -> Result<Matcher, toml::Error> {
+    let mut matcher = Vec::with_capacity(3);
+
+    for filter in s.trim().split(';') {
+        if filter.len() == 0 {
+            return Ok(matcher);
+        }
+
+        match parse_filter(filter) {
+            Ok(f) => matcher.push(f),
+            Err(e) => return Err(e),
+        }
+    }
+    Ok(matcher)
+}
+
+fn parse_filter(s: &str) -> Result<Filter, toml::Error> {
+    let mut parts = s.trim().split('.');
+
+    if let Some(facilities) = parts.next() {
+        if let Some(levels) = parts.next() {
+            return match (parse_facility_pattern(facilities), parse_level_pattern(levels)) {
+                (Ok(f), Ok(l)) => Ok((f, l)),
+                (Err(e), Err(f)) => tomlerr(format!("{} {}", e, f)),
+                (Ok(_), Err(e)) => tomlerr(format!("{}", e)),
+                (Err(e), Ok(_)) => tomlerr(format!("{}", e)),
+            };
+        }
+    }
+    tomlerr(format!("Bad filter pattern: {}", s))
+}
+
+fn parse_facility_pattern(s: &str) -> Result<FacPattern, toml::Error> {
+    let list: Vec<String> = s.trim().split(',').map(String::from).collect();
+
+    if list.len() > 1 {
+        let mut facilities = Vec::with_capacity(list.len());
+
+        for f in list {
+            if let Some(fac) = priority::str_to_facility(f.trim()) {
+                facilities.push(fac);
+            } else {
+                return tomlerr(format!("Unrecognized facility: {}", f));
+            }
+        }
+        Ok(FacPattern::MultiFacility(facilities))
+    } else if list.len() == 1 {
+        let l = &list[0];
+
+        if l == "*" {
+            Ok(FacPattern::Wildcard)
+        } else if let Some(fac) = priority::str_to_facility(l) {
+            Ok(FacPattern::Facility(fac))
+        } else {
+            tomlerr(format!("Unknown facility: {}", l))
+        }
+    } else {
+        return tomlerr(format!("Level pattern can't be empty"));
+    }
+}
+
+fn parse_level_pattern(s: &str) -> Result<LvlPattern, toml::Error> {
+    let list: Vec<String> = s.trim().split(',').map(String::from).collect();
+
+    if list.len() > 1 {
+        let mut levels = Vec::with_capacity(list.len());
+
+        for l in list {
+            if let Some(lvl) = priority::str_to_level(l.trim()) {
+                levels.push(lvl);
+            } else {
+                return tomlerr(format!("Unrecognized facility: {}", l));
+            }
+        }
+        Ok(LvlPattern::MultiLevel(levels))
+    } else if list.len() == 1 {
+        let l = &list[0];
+
+        // exact rule
+        if &l[0..1] == "=" {
+            if let Some(fac) = priority::str_to_level(&l[1..]) {
+                Ok(LvlPattern::ExactLevel(fac))
+            } else {
+                tomlerr(format!("Unknown exact facility: {}", l))
+            }
+        } else if &l[..] == "*" {
+            Ok(LvlPattern::Wildcard)
+        } else if let Some(lvl) = priority::str_to_level(l) {
+            Ok(LvlPattern::Level(lvl))
+        } else {
+            tomlerr(format!("Unknown facility: {}", &list[0]))
+        }
+    } else {
+        return tomlerr(format!("Level pattern can't be empty"));
+    }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct Rule {
+    pattern: Matcher,
+    // refers to the file entry name, not the file name.
+    file: String,
+    remote_dest: String,
+    stop: bool,
+}
+
+pub fn new_rule(pattern: Matcher, file: String, remote_dest: String, stop: bool) -> Rule {
+    Rule {
+        pattern: pattern,
+        file: file,
+        remote_dest: remote_dest,
+        stop: stop
+    }
+}