WIP: added hot reload of config using inotify
This commit is contained in:
parent
0976a71057
commit
b7a90a81ba
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
/config.json
|
/config.json
|
||||||
|
|
||||||
|
*.swp
|
35
Cargo.lock
generated
35
Cargo.lock
generated
@ -11,7 +11,7 @@ dependencies = [
|
|||||||
"alsa-sys",
|
"alsa-sys",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
"nix",
|
"nix 0.15.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -64,9 +64,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
@ -470,9 +470,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.101"
|
version = "0.2.103"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
@ -501,6 +501,15 @@ version = "2.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "micromath"
|
name = "micromath"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -519,7 +528,7 @@ dependencies = [
|
|||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"memalloc",
|
"memalloc",
|
||||||
"nix",
|
"nix 0.15.0",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi",
|
"winapi",
|
||||||
@ -584,6 +593,19 @@ dependencies = [
|
|||||||
"void",
|
"void",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cc",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"libc",
|
||||||
|
"memoffset",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "ntapi"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@ -1217,6 +1239,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"embedded-graphics",
|
"embedded-graphics",
|
||||||
"launchy",
|
"launchy",
|
||||||
|
"nix 0.23.0",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -12,3 +12,4 @@ launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" }
|
|||||||
reqwest = { version = "0.11.4", features = ["blocking", "json"] }
|
reqwest = { version = "0.11.4", features = ["blocking", "json"] }
|
||||||
serde = { version = "1.0.130", features = ["derive"] }
|
serde = { version = "1.0.130", features = ["derive"] }
|
||||||
serde_json = "1.0.68"
|
serde_json = "1.0.68"
|
||||||
|
nix = "0.23.0"
|
@ -1,10 +1,58 @@
|
|||||||
use clap::{App, Arg, ArgMatches};
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify, InotifyEvent};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Error;
|
use serde_json::Error;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
pub struct Context {
|
||||||
|
pub cfg: Config,
|
||||||
|
pub configfile: String,
|
||||||
|
pub events: Option<Vec<InotifyEvent>>,
|
||||||
|
pub inotify: Inotify,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let configfile = Context::argparse()
|
||||||
|
.value_of("config")
|
||||||
|
.unwrap_or("config.json")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let mut ctx = Context {
|
||||||
|
cfg: Config::new(),
|
||||||
|
configfile: configfile,
|
||||||
|
events: None,
|
||||||
|
inotify: Inotify::init(InitFlags::empty()).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Loading {} file ...", ctx.configfile);
|
||||||
|
ctx.cfg.load(&ctx.configfile);
|
||||||
|
|
||||||
|
ctx.inotify
|
||||||
|
.add_watch(ctx.configfile.as_str(), AddWatchFlags::IN_MODIFY)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
pub fn argparse() -> ArgMatches<'static> {
|
||||||
|
App::new("Zabbix Launch")
|
||||||
|
.version("1.0")
|
||||||
|
.author("PaulBSD <paul@paulbsd.com>")
|
||||||
|
.about("Lights up Launchpad mini using Zabbix data")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("config")
|
||||||
|
.short("c")
|
||||||
|
.long("config")
|
||||||
|
.value_name("FILE")
|
||||||
|
.help("Sets a custom config file")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.get_matches()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub server: String,
|
pub server: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
@ -15,7 +63,7 @@ pub struct Config {
|
|||||||
pub limit: Option<u64>,
|
pub limit: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl<'a> Config {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
server: String::from("https://zabbix.acme.com/api_jsonrpc.php"),
|
server: String::from("https://zabbix.acme.com/api_jsonrpc.php"),
|
||||||
@ -43,7 +91,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load<'a>(&mut self, configfile: &'a str) {
|
pub fn load(&'a mut self, configfile: &str) {
|
||||||
let fileopen: Result<File, std::io::Error>;
|
let fileopen: Result<File, std::io::Error>;
|
||||||
let filemeta = std::fs::metadata(configfile);
|
let filemeta = std::fs::metadata(configfile);
|
||||||
let fileexists = match filemeta {
|
let fileexists = match filemeta {
|
||||||
@ -74,24 +122,8 @@ impl Config {
|
|||||||
self.save(&configfile);
|
self.save(&configfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save<'a>(&self, configfile: &'a str) {
|
pub fn save(&self, configfile: &str) {
|
||||||
let file = File::create(configfile).unwrap();
|
let file = File::create(configfile).unwrap();
|
||||||
serde_json::to_writer_pretty(file, &self).unwrap();
|
serde_json::to_writer_pretty(file, &self).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn argparse<'a>() -> ArgMatches<'a> {
|
|
||||||
App::new("Zabbix Launch")
|
|
||||||
.version("1.0")
|
|
||||||
.author("PaulBSD <paul@paulbsd.com>")
|
|
||||||
.about("Lights up Launchpad mini using Zabbix data")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("config")
|
|
||||||
.short("c")
|
|
||||||
.long("config")
|
|
||||||
.value_name("FILE")
|
|
||||||
.help("Sets a custom config file")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.get_matches()
|
|
||||||
}
|
|
||||||
|
18
src/main.rs
18
src/main.rs
@ -2,24 +2,16 @@ pub mod config;
|
|||||||
mod padcontrol;
|
mod padcontrol;
|
||||||
mod zabbix;
|
mod zabbix;
|
||||||
|
|
||||||
use config::Config;
|
use config::Context;
|
||||||
use zabbix::problems::ZabbixLayout;
|
use zabbix::problems::ZabbixLayout;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut datamatrix = ZabbixLayout { layout: Vec::new() };
|
let mut datamatrix = ZabbixLayout { layout: Vec::new() };
|
||||||
|
|
||||||
// parse arguments
|
|
||||||
let matches = config::argparse();
|
|
||||||
|
|
||||||
// load configuration
|
// load configuration
|
||||||
let configfile = matches.value_of("config").unwrap_or("config.json");
|
let mut context = Context::new();
|
||||||
let mut cfg = Config::new();
|
zabbix::api::get_zabbix_authtoken(&mut context.cfg);
|
||||||
cfg.load(&configfile);
|
|
||||||
zabbix::api::get_zabbix_authtoken(&mut cfg);
|
|
||||||
cfg.save(&configfile);
|
|
||||||
|
|
||||||
// init/connect to launchpad and clear it
|
|
||||||
let (mut canvas, mut _poller) = padcontrol::initpad();
|
let (mut canvas, mut _poller) = padcontrol::initpad();
|
||||||
//padcontrol::input(&mut canvas, &mut _poller);
|
padcontrol::draw(&mut canvas, &mut datamatrix, &mut context);
|
||||||
padcontrol::draw(&mut canvas, &mut datamatrix, &mut cfg);
|
//padcontrol::test(&mut context);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
use std::time::Duration;
|
use crate::config::Context;
|
||||||
use std::thread::sleep;
|
|
||||||
use crate::config::Config;
|
|
||||||
use crate::zabbix::api::get_zabbix_problems;
|
use crate::zabbix::api::get_zabbix_problems;
|
||||||
use crate::zabbix::problems::ZabbixLayout;
|
use crate::zabbix::problems::ZabbixLayout;
|
||||||
use launchy::Color;
|
use launchy::Color;
|
||||||
use launchy::{self, Canvas, CanvasLayout, CanvasLayoutPoller, MsgPollingWrapper, Pad};
|
use launchy::{self, Canvas, CanvasLayout, CanvasLayoutPoller, MsgPollingWrapper, Pad};
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
pub const MATRIX_WIDTH: i32 = 8;
|
pub const MATRIX_WIDTH: i32 = 8;
|
||||||
pub const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH;
|
pub const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH;
|
||||||
|
|
||||||
|
|
||||||
pub fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) {
|
pub fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) {
|
||||||
let (mut canvas, poller) = launchy::CanvasLayout::new_polling();
|
let (mut canvas, poller) = launchy::CanvasLayout::new_polling();
|
||||||
match canvas.add_by_guess_rotated::<launchy::mini::Canvas>(0, 0, launchy::Rotation::None) {
|
match canvas.add_by_guess_rotated::<launchy::mini::Canvas>(0, 0, launchy::Rotation::None) {
|
||||||
@ -35,10 +33,37 @@ pub fn _input(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(canvas: &mut CanvasLayout, datamatrix: &mut ZabbixLayout, cfg: &mut Config) {
|
pub fn test<'a>(ctx: &mut Context) {
|
||||||
println!("Refresh rate is {} seconds", cfg.refresh.unwrap());
|
println!("Refresh rate is {} seconds", ctx.cfg.refresh.unwrap());
|
||||||
loop {
|
loop {
|
||||||
let zabbix_data_result = get_zabbix_problems(cfg);
|
println!("test");
|
||||||
|
let events = match ctx.inotify.read_events() {
|
||||||
|
Ok(ok) => ok,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
println!("nombre d'events: {}", events.len());
|
||||||
|
for i in events {
|
||||||
|
println!("test event");
|
||||||
|
println!("{:?}", i);
|
||||||
|
}
|
||||||
|
let zabbix_data_result = get_zabbix_problems(&ctx.cfg);
|
||||||
|
let zabbix_data = match zabbix_data_result {
|
||||||
|
Ok(z) => z,
|
||||||
|
Err(_) => {
|
||||||
|
println!("Error requesting zabbix service");
|
||||||
|
sleep(Duration::from_secs(10));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("{:?}", zabbix_data);
|
||||||
|
sleep(Duration::from_secs(ctx.cfg.refresh.unwrap_or(5)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(canvas: &mut CanvasLayout, datamatrix: &mut ZabbixLayout, ctx: &mut Context) {
|
||||||
|
println!("Refresh rate is {} seconds", ctx.cfg.refresh.unwrap());
|
||||||
|
loop {
|
||||||
|
let zabbix_data_result = get_zabbix_problems(&ctx.cfg);
|
||||||
let zabbix_data = match zabbix_data_result {
|
let zabbix_data = match zabbix_data_result {
|
||||||
Ok(zabbix_data) => zabbix_data,
|
Ok(zabbix_data) => zabbix_data,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@ -50,8 +75,11 @@ pub fn draw(canvas: &mut CanvasLayout, datamatrix: &mut ZabbixLayout, cfg: &mut
|
|||||||
datamatrix.compute(&zabbix_data);
|
datamatrix.compute(&zabbix_data);
|
||||||
clear(canvas);
|
clear(canvas);
|
||||||
let mut max = 0;
|
let mut max = 0;
|
||||||
for (i,j) in datamatrix.layout.iter().enumerate() {
|
for (i, j) in datamatrix.layout.iter().enumerate() {
|
||||||
let p = Pad { x: ((i as i32) % MATRIX_WIDTH ), y: ((i as i32) / MATRIX_WIDTH )+1 };
|
let p = Pad {
|
||||||
|
x: ((i as i32) % MATRIX_WIDTH),
|
||||||
|
y: ((i as i32) / MATRIX_WIDTH) + 1,
|
||||||
|
};
|
||||||
let c = match j.status {
|
let c = match j.status {
|
||||||
5 => Color::RED,
|
5 => Color::RED,
|
||||||
4 => Color::from_hue(0.05),
|
4 => Color::from_hue(0.05),
|
||||||
@ -64,12 +92,12 @@ pub fn draw(canvas: &mut CanvasLayout, datamatrix: &mut ZabbixLayout, cfg: &mut
|
|||||||
if max >= MATRIX_SIZE {
|
if max >= MATRIX_SIZE {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if cfg.sloweffect.unwrap() {
|
if ctx.cfg.sloweffect.unwrap() {
|
||||||
sleep(Duration::from_millis(15));
|
sleep(Duration::from_millis(15));
|
||||||
}
|
}
|
||||||
canvas.flush().unwrap();
|
canvas.flush().unwrap();
|
||||||
}
|
}
|
||||||
sleep(Duration::from_secs(cfg.refresh.unwrap_or(5)));
|
sleep(Duration::from_secs(ctx.cfg.refresh.unwrap_or(5)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,19 +16,13 @@ pub fn get_zabbix_authtoken(cfg: &mut Config) {
|
|||||||
cfg.authtoken = Some(values["result"].as_str().unwrap().to_string());
|
cfg.authtoken = Some(values["result"].as_str().unwrap().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_zabbix_problems(cfg: &mut Config) -> Result<Value, reqwest::Error> {
|
pub fn get_zabbix_problems(cfg: &Config) -> Result<Value, reqwest::Error> {
|
||||||
let body = query_triggers(
|
let body = query_triggers(&cfg.authtoken.as_ref().unwrap_or(&String::from("")));
|
||||||
&cfg.authtoken.as_ref().unwrap_or(&String::from("")),
|
|
||||||
);
|
|
||||||
let resp = reqwest::blocking::Client::new()
|
let resp = reqwest::blocking::Client::new()
|
||||||
.post(&cfg.server)
|
.post(&cfg.server)
|
||||||
.json(&body)
|
.json(&body)
|
||||||
.send();
|
.send();
|
||||||
|
|
||||||
//let res = match resp {
|
|
||||||
// Ok(res) => res.json()
|
|
||||||
//};
|
|
||||||
|
|
||||||
Ok(resp.unwrap().json().unwrap())
|
Ok(resp.unwrap().json().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +61,6 @@ fn _query_problems(zabbix_token: &String, zabbix_limit: i64) -> Value {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn query_triggers(zabbix_token: &String) -> Value {
|
pub fn query_triggers(zabbix_token: &String) -> Value {
|
||||||
let zabbix_api_function = "trigger.get";
|
let zabbix_api_function = "trigger.get";
|
||||||
json!({
|
json!({
|
||||||
|
Loading…
Reference in New Issue
Block a user