Mercurial > lbo > hg > myi3stat
view src/main.rs @ 0:be75e8a90861
Initial commit
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 14 Feb 2016 11:50:16 +0100 |
parents | |
children | 350cc212f07a |
line wrap: on
line source
use std::collections::BTreeMap; use std::process; use std::env; extern crate chrono; use chrono::Local; extern crate getopts; use getopts::Options; #[derive(Clone)] pub enum Color { /// An HTML color (#1234aa) Arbitrary(String), /// The default Standard, /// Various colors White, Red, Green, Blue, Orange, Purple, } /// An output produced by a metric to be displayed in the bar. pub struct RenderResult { pub text: String, pub color: Color, } /// State that is stored in a MetricState between rendering cycles. #[derive(Clone)] pub enum State { Empty, S(String), I(i64), F(f64), C(Color), } /// State that is passed to and returned from every render cycle. pub struct MetricState { /// Arbitrary state state: BTreeMap<String, State>, /// Unix epoch in seconds. This is updated by the framework. pub last_called: i64, } impl MetricState { pub fn new() -> MetricState { MetricState { state: BTreeMap::new(), last_called: 0, } } pub fn get(&self, k: String) -> State { self.state.get(&k).unwrap_or(&State::Empty).clone() } pub fn set(&mut self, k: String, v: State) { self.state.insert(k, v); } pub fn now() -> i64 { Local::now().timestamp() } } trait Metric { /// Initializes a metric using the string supplied as parameter to the command line argument. fn init(&self, argvalue: Option<String>) -> MetricState; /// Renders the metric. fn render(&mut self, st: &mut MetricState) -> RenderResult; } /// A metric that is active in the current run and updated for every cycle. struct ActiveMetric { name: String, m: Box<Metric>, st: MetricState, } /// Represents a/the set of metrics available for display. struct AvailableMetrics { metrics: BTreeMap<String, Box<Metric>>, opts: Options, } impl AvailableMetrics { fn new() -> AvailableMetrics { let mut options = Options::new(); options.optopt("", "ordering", "Ordering of metrics in status bar. Comma-separated list of metric names \ (default ordering is ASCII-ordered, i.e. case sensitive)", "METRIC1,METRIC2,METRIC3"); options.optopt("", "interval", "Interval in seconds between individual render cycles. Default: 1", "SECONDS"); options.optflag("h", "help", "Print a help text"); AvailableMetrics { metrics: BTreeMap::new(), opts: options, } } /// Register a metric under the given name. /// desc and example are for the purpose of documenting the command line option that is added. /// Does fn register_metric(&mut self, name: &str, desc: &str, example: &str, metric: Box<Metric>) { if !self.metrics.contains_key(&String::from(name)) { self.opts.optopt("", name, desc, example); self.metrics.insert(String::from(name), metric); } } fn print_help(&self) { print!("{}", self.opts.usage("Usage: myi3stat [options]")); } fn parse_args(&mut self, args: &[String]) -> getopts::Matches { let matches = self.opts.parse(args); match matches { Err(_) => { self.print_help(); process::exit(1) } Ok(m) => m, } } /// Returns a map of metric -> position in ordering list fn make_ordering_map(ord_list: String) -> BTreeMap<String, i32> { let parts = ord_list.split(","); let mut i = 0; let mut ordmap = BTreeMap::new(); for metric in parts { ordmap.insert(String::from(metric), i); i += 1; } 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) { let matches = self.parse_args(args); let mut metrics = Vec::new(); // Look for every defined metric if the user wants to have it displayed. for (metric_name, metric) in self.metrics.into_iter() { if matches.opt_present(&metric_name) { let st = metric.init(matches.opt_str(&metric_name)); metrics.push(ActiveMetric { name: String::from(metric_name), m: metric, st: st, }); } } // 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(""))); metrics.sort_by(|a, b| { match (ordmap.get(&a.name), ordmap.get(&b.name)) { (Some(i1), Some(i2)) => i1.cmp(i2), (_, _) => a.name.cmp(&b.name), } }); let interval = i32::from_str_radix(&matches.opt_str("interval") .unwrap_or(String::from("1")), 10) .unwrap_or(1); (metrics, interval) } } fn main() { let args: Vec<String> = env::args().collect(); let all_metrics = AvailableMetrics::new(); let (selected_metrics, interval) = all_metrics.evaluate(&args[1..]); }