rnetmon/src/main.rs

125 lines
3.5 KiB
Rust

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<String, serde_yaml::Value>) -> Box<Monitor + Send> {
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<String, serde_yaml::Value>) -> Box<Output + Send> {
match name {
"stdout" => Box::new(plugins::output::stdout::Stdout::new(&config)),
_ => panic!("Unknown monitor name: {}", name),
}
}
fn main() {
let args: Vec<String> = 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<mpsc::Sender<Message>> = 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();
}
}
}