mod config; mod message; mod monitor; mod output; mod plugins; extern crate getopts; extern crate serde_derive; extern crate serde_yaml; use std::env; use std::fs::File; use std::io::prelude::*; use std::sync::mpsc; use std::thread; use getopts::Options; use crate::config::*; use crate::message::*; use crate::monitor::*; use crate::output::*; fn monitor_factory(name: &str, config: &HashMap) -> Box { match name { "tester" => Box::new(plugins::monitor::tester::Tester::new(&config)), "wifi_availability" => Box::new( plugins::monitor::wifi_availability::WifiAvailability::new(&config), ), _ => panic!("Unknown monitor name: {}", name), } } fn output_factory(name: &str, config: &HashMap) -> Box { match name { "stdout" => Box::new(plugins::output::stdout::Stdout::new(&config)), _ => panic!("Unknown monitor name: {}", name), } } fn main() { let args: Vec = env::args().collect(); // Parse command line args let mut opts = Options::new(); opts.optopt( "c", "config", "Path to config.yaml. Default: ./config.yaml", "config.yaml", ); opts.optflag("h", "help", "print this help menu"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, Err(f) => panic!(f.to_string()), }; if matches.opt_present("h") { let brief = format!("Usage: {} [options]", args[0]); print!("{}", opts.usage(&brief)); return; } // Parse config let config_path = matches.opt_str("c").unwrap_or("./config.yaml".to_owned()); let mut config_file = File::open(config_path).expect("Could not open configuration file"); let mut config_content = String::new(); config_file .read_to_string(&mut config_content) .expect("Could not read configuration file"); let config: Config = serde_yaml::from_str(&config_content).expect("Invalid config file content"); // Monitors -> dispatcher channel let (mon_sender, mon_receiver) = mpsc::channel(); // Instantiate monitor threads and structs for mon_config in config.monitors { let name = mon_config .get("name") .expect("Missing `name` key for monitor") .as_str() .expect("Key `name` for monitor is not a string"); println!("Loading monitor: {}", name); let snd = mon_sender.clone(); let mut mon = monitor_factory(name, &mon_config); thread::spawn(move || loop { mon.run(&snd); }); } // Instantiate output threads and structs let mut output_senders: Vec> = vec![]; for out_config in config.outputs { let name = out_config .get("name") .expect("Missing `name` key for monitor") .as_str() .expect("Key `name` for monitor is not a string"); println!("Loading output: {}", name); let (out_sender, out_receiver) = mpsc::channel(); output_senders.push(out_sender); let mut output = output_factory(name, &out_config); thread::spawn(move || loop { let message = out_receiver.recv().unwrap(); output.process_message(message); }); } let output_senders = output_senders; // Dispatch messages loop { let message = mon_receiver.recv().unwrap(); for out in &output_senders { out.send(message.clone()).unwrap(); } } }