changeset 34:cd2dddf95416

Make renderers modular. Add standard i3status renderer.
author Lewin Bormann <lbo@spheniscida.de>
date Thu, 18 Feb 2016 15:55:27 +0100
parents 1393ea777c92
children cbfe39a75d77
files src/framework.rs src/main.rs src/render.rs
diffstat 3 files changed, 105 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/src/framework.rs	Thu Feb 18 15:23:22 2016 +0100
+++ b/src/framework.rs	Thu Feb 18 15:55:27 2016 +0100
@@ -1,8 +1,5 @@
 #![allow(dead_code)]
 
-use std::thread::sleep;
-use std::time::Duration;
-
 extern crate chrono;
 use self::chrono as chron;
 
@@ -52,7 +49,7 @@
             color: color,
         }
     }
-    fn to_json(&self) -> String {
+    pub fn to_json(&self) -> String {
         let result = format!("{{\"name\": \
                               \"{name}\",\"color\":\"{color}\",\"markup\":\"none\",\"full_text\":\
                               \"{text}\"}}",
@@ -113,23 +110,3 @@
         result
     }
 }
-
-pub fn render_loop(mut metrics: Vec<ActiveMetric>, interval: i32) {
-    let ival_duration = Duration::new((interval / 1000) as u64, 1000000 * (interval as u32 % 1000));
-    let intro = "{\"version\":1}\n[[]\n";
-    print!("{}", intro);
-
-    loop {
-        let mut render_result = metrics.iter_mut()
-                                       .map(|m| m.render())
-                                       .fold(String::from(""), |mut out, p| {
-                                           out.push_str(&p.to_json());
-                                           out.push_str(",");
-                                           out
-                                       });
-        render_result.pop();
-        println!(",[{}]", render_result);
-
-        sleep(ival_duration);
-    }
-}
--- a/src/main.rs	Thu Feb 18 15:23:22 2016 +0100
+++ b/src/main.rs	Thu Feb 18 15:55:27 2016 +0100
@@ -1,6 +1,7 @@
 mod framework;
 mod helper;
 mod metrics;
+mod render;
 
 use std::collections::BTreeMap;
 use std::process;
@@ -10,18 +11,20 @@
 use getopts::Options;
 
 use framework::*;
+use render::*;
 
 /// Represents a/the set of metrics available for display.
-struct AvailableMetrics {
+struct Config {
     metrics: BTreeMap<String, Box<Metric>>,
+    renderers: BTreeMap<String, Box<Renderer>>,
     opts: Options,
 }
 
 
 /// Set of all metrics. Used to register metrics and select the active ones based on the user's
 /// selection.
-impl AvailableMetrics {
-    fn new() -> AvailableMetrics {
+impl Config {
+    fn new() -> Config {
         let mut options = Options::new();
         options.optopt("",
                        "ordering",
@@ -32,10 +35,15 @@
                        "interval",
                        "Interval in milliseconds between individual render cycles. Default: 1000",
                        "SECONDS");
+        options.optopt("",
+                       "renderer",
+                       "Which renderer to use. Currently available: i3status",
+                       "i3status");
         options.optflag("h", "help", "Print a help text");
 
-        AvailableMetrics {
+        Config {
             metrics: BTreeMap::new(),
+            renderers: BTreeMap::new(),
             opts: options,
         }
     }
@@ -49,6 +57,12 @@
         }
     }
 
+    fn register_renderer(&mut self, name: &str, r: Box<Renderer>) {
+        if !self.renderers.contains_key(name) {
+            self.renderers.insert(String::from(name), r);
+        }
+    }
+
     fn print_help(&self) {
         print!("{}", self.opts.usage("Usage: myi3stat [options]"));
     }
@@ -84,9 +98,11 @@
         ordmap
     }
 
-    /// Returns a vec of the selected metrics in the wanted order, and the interval between render
-    /// cycles in seconds.
-    fn evaluate(mut self, args: &[String]) -> (Vec<ActiveMetric>, i32) {
+    /// Returns the selected renderer; the list of selected metrics; and the chosen interval in
+    /// milliseconds.
+    fn evaluate(mut self, args: &[String]) -> (Box<Renderer>, Vec<ActiveMetric>, i32) {
+        use std::str::FromStr;
+
         let matches = self.parse_args(args);
         let mut metrics = Vec::new();
 
@@ -101,8 +117,8 @@
 
         // Sort metrics by position in the supplied ordering list (or alternatively
         // alphabetically).
-        let ordmap = AvailableMetrics::make_ordering_map(matches.opt_str("ordering")
-                                                                .unwrap_or(String::from("")));
+        let ordmap = Config::make_ordering_map(matches.opt_str("ordering")
+                                                      .unwrap_or(String::from("")));
         metrics.sort_by(|a, b| {
             match (ordmap.get(a.name()), ordmap.get(b.name())) {
                 (Some(i1), Some(i2)) => i1.cmp(i2),
@@ -110,16 +126,23 @@
             }
         });
 
-        let interval = i32::from_str_radix(&matches.opt_str("interval")
-                                                   .unwrap_or(String::from("1000")),
-                                           10)
+        // Select and set up renderer
+        let interval = i32::from_str(&matches.opt_str("interval").unwrap_or(String::from("1000")))
                            .unwrap_or(1000);
+        let renderer_name = matches.opt_str("renderer").unwrap_or(String::from("i3status"));
 
-        (metrics, interval)
+
+        if !self.renderers.contains_key(&renderer_name) {
+            panic!(format!("Renderer '{}' not registered!!", renderer_name));
+        }
+
+        let renderer = self.renderers.remove(&renderer_name).unwrap();
+
+        (renderer, metrics, interval)
     }
 }
 
-fn register_metrics(registry: &mut AvailableMetrics) {
+fn register_metrics(registry: &mut Config) {
     use metrics::cpu_load;
     use metrics::load;
     use metrics::net;
@@ -147,11 +170,19 @@
                              cpu_load::make_cpu_load_metric());
 }
 
+fn register_renderers(registry: &mut Config) {
+    use render;
+
+    registry.register_renderer("i3status", render::make_i3status());
+}
+
 fn main() {
     let args: Vec<String> = env::args().collect();
-    let mut all_metrics = AvailableMetrics::new();
-    register_metrics(&mut all_metrics);
-    let (selected_metrics, interval) = all_metrics.evaluate(&args[1..]);
+    let mut cfg = Config::new();
+    register_metrics(&mut cfg);
+    register_renderers(&mut cfg);
+    let (renderer, selected_metrics, interval) = cfg.evaluate(&args[1..]);
 
-    render_loop(selected_metrics, interval);
+
+    render_loop(renderer, selected_metrics, interval);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/render.rs	Thu Feb 18 15:55:27 2016 +0100
@@ -0,0 +1,55 @@
+use framework::*;
+
+pub trait Renderer {
+    fn init(&mut self, metrics: Vec<ActiveMetric>) -> String;
+    fn render(&mut self) -> String;
+}
+
+struct I3statRenderer {
+    metrics: Vec<ActiveMetric>,
+}
+
+impl I3statRenderer {
+    fn new() -> I3statRenderer {
+        I3statRenderer { metrics: Vec::new() }
+    }
+}
+
+impl Renderer for I3statRenderer {
+    fn init(&mut self, metrics: Vec<ActiveMetric>) -> String {
+        self.metrics = metrics;
+
+        String::from("{\"version\":1}\n[[]\n")
+    }
+
+    fn render(&mut self) -> String {
+        let mut render_result = self.metrics
+                                    .iter_mut()
+                                    .map(|m| m.render())
+                                    .fold(String::from(""), |mut out, rendres| {
+                                        out.push_str(&rendres.to_json());
+                                        out.push_str(",");
+                                        out
+                                    });
+        render_result.pop();
+        format!(",[{}]", render_result)
+    }
+}
+
+pub fn make_i3status() -> Box<Renderer> {
+    Box::new(I3statRenderer::new())
+}
+
+pub fn render_loop(mut r: Box<Renderer>, metrics: Vec<ActiveMetric>, interval: i32) {
+    use std::thread::sleep;
+    use std::time::Duration;
+
+    let ival_duration = Duration::new((interval / 1000) as u64, 1000000 * (interval as u32 % 1000));
+
+    print!("{}", r.init(metrics));
+
+    loop {
+        println!("{}", r.render());
+        sleep(ival_duration);
+    }
+}