zabbixlaunch/src/config/mod.rs
Paul a7dc0a83cd
All checks were successful
continuous-integration/drone/push Build is passing
updated dependencies
2024-12-30 22:24:39 +01:00

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();
}
}