Mercurial > lbo > hg > myi3stat
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); + } +}