223 lines
6.8 KiB
Rust
223 lines
6.8 KiB
Rust
use crate::zabbix::api::get_zabbix_authtoken;
|
|
use crate::zabbix::problems::DataMatrix;
|
|
use clap::{Arg, ArgMatches, Command};
|
|
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::Error as JsonError;
|
|
use serde_json::Value as JsonValue;
|
|
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::string::String;
|
|
use std::thread::sleep;
|
|
use std::time::Duration;
|
|
|
|
pub enum ReloadFrequency {
|
|
High = 50,
|
|
Medium = 20,
|
|
Low = 10,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Mode {
|
|
Draw,
|
|
Test,
|
|
Input,
|
|
Effect,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Context {
|
|
pub cfg: Config,
|
|
configfile: String,
|
|
inotify: Inotify,
|
|
pub datamatrix: DataMatrix,
|
|
pub mode: Option<Mode>,
|
|
}
|
|
|
|
impl Context {
|
|
pub fn new() -> Self {
|
|
let argp: ArgMatches = Context::argparse();
|
|
|
|
let configfile = argp
|
|
.get_one::<String>("config")
|
|
.unwrap_or(&"config.json".to_string())
|
|
.to_string();
|
|
|
|
let mut ctx = Context {
|
|
cfg: Config::new(),
|
|
configfile: configfile,
|
|
inotify: Inotify::init(InitFlags::IN_NONBLOCK).unwrap(),
|
|
datamatrix: DataMatrix::new(),
|
|
mode: match argp.get_one::<String>("mode").unwrap().as_str() {
|
|
"draw" => Some(Mode::Draw),
|
|
"test" => Some(Mode::Test),
|
|
"input" => Some(Mode::Input),
|
|
"effect" => Some(Mode::Effect),
|
|
_ => {
|
|
println!("No valid mode choosen");
|
|
None
|
|
}
|
|
},
|
|
};
|
|
|
|
println!("Loading {configfile} file ...", configfile = ctx.configfile);
|
|
ctx.cfg.load(&ctx.configfile);
|
|
|
|
println!(
|
|
"Adding inotify watch on {configfile} file ...",
|
|
configfile = ctx.configfile
|
|
);
|
|
ctx.inotify
|
|
.add_watch(ctx.configfile.as_str(), AddWatchFlags::IN_MODIFY)
|
|
.unwrap();
|
|
get_zabbix_authtoken(&mut ctx.cfg);
|
|
|
|
ctx
|
|
}
|
|
|
|
fn argparse() -> ArgMatches {
|
|
Command::new(env!("CARGO_PKG_NAME"))
|
|
.version(env!("CARGO_PKG_VERSION"))
|
|
.author(env!("CARGO_PKG_AUTHORS"))
|
|
.about(env!("CARGO_PKG_DESCRIPTION"))
|
|
.arg(
|
|
Arg::new("config")
|
|
.short('c')
|
|
.long("config")
|
|
.value_name("FILE")
|
|
.default_value("/etc/zabbixlaunch/config.json")
|
|
.help("Sets a custom config file"),
|
|
)
|
|
.arg(
|
|
Arg::new("mode")
|
|
.short('m')
|
|
.long("mode")
|
|
.value_name("mode")
|
|
.default_value("draw")
|
|
.value_parser(["draw", "test", "input", "effect"])
|
|
.help("Sets a when running"),
|
|
)
|
|
.arg(Arg::new("debug").short('d').help("Enable debugging"))
|
|
.get_matches()
|
|
}
|
|
|
|
pub fn hotreload(&mut self) {
|
|
let mut i = 0;
|
|
let waitmilli = self.cfg.refresh.unwrap_or(5) * 1000;
|
|
|
|
while i < waitmilli {
|
|
let waitinc = waitmilli / ReloadFrequency::Medium as u64;
|
|
let events = match self.inotify.read_events() {
|
|
Ok(ev) => ev,
|
|
Err(_) => vec![],
|
|
};
|
|
if events.len() > 0 {
|
|
println!("Reloading {cfg}", cfg = self.configfile);
|
|
self.cfg.load(self.configfile.as_str());
|
|
get_zabbix_authtoken(&mut self.cfg);
|
|
break;
|
|
} else {
|
|
sleep(Duration::from_millis(waitinc));
|
|
}
|
|
i += waitinc;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
|
pub struct Config {
|
|
pub server: String,
|
|
pub username: String,
|
|
pub password: String,
|
|
#[serde(skip_serializing)]
|
|
pub authtoken: Option<String>,
|
|
pub sloweffect: Option<bool>,
|
|
pub refresh: Option<u64>,
|
|
pub limit: Option<u64>,
|
|
}
|
|
|
|
impl<'a> Config {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
server: "https://zabbix.acme.com/api_jsonrpc.php".to_string(),
|
|
username: "bob".to_string(),
|
|
password: "password".to_string(),
|
|
authtoken: Some("token".to_string()),
|
|
sloweffect: Some(true),
|
|
refresh: Some(5u64),
|
|
limit: Some(20u64),
|
|
}
|
|
}
|
|
|
|
fn load(&'a mut self, configfile: &str) {
|
|
let fileopen: Result<File, std::io::Error>;
|
|
let filemeta = std::fs::metadata(configfile);
|
|
let mut error_reading = false;
|
|
let fileexists = match filemeta {
|
|
Ok(_) => true,
|
|
Err(_) => false,
|
|
};
|
|
|
|
if !fileexists {
|
|
File::create(configfile).unwrap();
|
|
}
|
|
fileopen = File::open(configfile);
|
|
|
|
let mut file = match fileopen {
|
|
Ok(f) => f,
|
|
Err(err) => {
|
|
panic!("{err}", err = err);
|
|
}
|
|
};
|
|
let mut contents = String::new();
|
|
file.read_to_string(&mut contents).unwrap();
|
|
let parse: Result<JsonValue, JsonError> = serde_json::from_str(contents.as_str());
|
|
let ncfg = match parse {
|
|
Ok(ncfg) => {
|
|
let tmpcfg = Config::new();
|
|
Config {
|
|
server: ncfg["server"]
|
|
.as_str()
|
|
.unwrap_or(tmpcfg.server.as_str())
|
|
.to_string(),
|
|
username: ncfg["username"]
|
|
.as_str()
|
|
.unwrap_or(tmpcfg.username.as_str())
|
|
.to_string(),
|
|
password: ncfg["password"]
|
|
.as_str()
|
|
.unwrap_or(tmpcfg.password.as_str())
|
|
.to_string(),
|
|
authtoken: Some(
|
|
ncfg["authtoken"]
|
|
.as_str()
|
|
.unwrap_or(self.authtoken.clone().unwrap().as_str())
|
|
.to_string(),
|
|
),
|
|
sloweffect: Some(
|
|
ncfg["sloweffect"]
|
|
.as_bool()
|
|
.unwrap_or(tmpcfg.sloweffect.unwrap()),
|
|
),
|
|
refresh: Some(ncfg["refresh"].as_u64().unwrap_or(tmpcfg.refresh.unwrap())),
|
|
limit: Some(ncfg["limit"].as_u64().unwrap_or(tmpcfg.limit.unwrap())),
|
|
}
|
|
}
|
|
Err(err) => {
|
|
error_reading = true;
|
|
println!("error occured: '{}'", err);
|
|
Config::new()
|
|
}
|
|
};
|
|
*self = ncfg;
|
|
if !fileexists || error_reading {
|
|
self.save(&configfile);
|
|
}
|
|
}
|
|
|
|
fn save(&self, configfile: &str) {
|
|
let file = File::create(configfile).unwrap();
|
|
serde_json::to_writer_pretty(file, &self).unwrap();
|
|
}
|
|
}
|