updates on hotreload branch
This commit is contained in:
parent
8c9575b6bd
commit
b322e4bdb1
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -117,6 +117,7 @@ dependencies = [
|
|||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"vec_map",
|
"vec_map",
|
||||||
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1230,6 +1231,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zabbixlaunch"
|
name = "zabbixlaunch"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "2.33.3" }
|
clap = { version = "2.33.3", features = ["yaml"] }
|
||||||
embedded-graphics = { version = "0.7.1", optional = true }
|
embedded-graphics = { version = "0.7.1", optional = true }
|
||||||
launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" }
|
launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" }
|
||||||
reqwest = { version = "0.11.5", features = ["blocking", "json"] }
|
reqwest = { version = "0.11.5", features = ["blocking", "json"] }
|
||||||
|
17
src/config/cli.yml
Normal file
17
src/config/cli.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: zabbixlaunch
|
||||||
|
version: "1.0.0"
|
||||||
|
author: PaulBSD <paul@paulbsd.com>
|
||||||
|
about: Lights up Launchpad mini using Zabbix data
|
||||||
|
args:
|
||||||
|
- config:
|
||||||
|
short: c
|
||||||
|
long: config
|
||||||
|
value_name: FILE
|
||||||
|
help: Sets a custom config file
|
||||||
|
takes_value: true
|
||||||
|
- mode:
|
||||||
|
short: m
|
||||||
|
value_name: MODE
|
||||||
|
help: Handles mode
|
||||||
|
takes_value: true
|
@ -1,68 +1,83 @@
|
|||||||
use clap::{App, Arg, ArgMatches};
|
use crate::zabbix::api::get_zabbix_authtoken;
|
||||||
|
use crate::zabbix::problems::DataMatrix;
|
||||||
|
use clap::{App, ArgMatches};
|
||||||
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
|
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Error as JsonError;
|
use serde_json::Error as JsonError;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{fs::File, io::Read};
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ReloadFrequency {
|
||||||
|
High = 50,
|
||||||
|
Medium = 20,
|
||||||
|
Low = 10,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub cfg: Config,
|
pub cfg: Config,
|
||||||
pub configfile: String,
|
pub configfile: String,
|
||||||
pub inotify: Inotify,
|
pub inotify: Inotify,
|
||||||
|
pub datamatrix: DataMatrix,
|
||||||
|
pub mode: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let configfile = Context::argparse()
|
let yaml = load_yaml!("cli.yml");
|
||||||
.value_of("config")
|
let cli = App::from_yaml(yaml).get_matches();
|
||||||
.unwrap_or("config.json")
|
|
||||||
.to_string();
|
let configfile = cli.value_of("config").unwrap_or("config.json").to_string();
|
||||||
|
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
cfg: Config::new(),
|
cfg: Config::new(),
|
||||||
configfile: configfile,
|
configfile: configfile,
|
||||||
inotify: Inotify::init(InitFlags::IN_NONBLOCK).unwrap(),
|
inotify: Inotify::init(InitFlags::IN_NONBLOCK).unwrap(),
|
||||||
|
datamatrix: DataMatrix::new(),
|
||||||
|
mode: cli.value_of("mode").unwrap_or("draw").to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Loading {} file ...", ctx.configfile);
|
println!("Loading {configfile} file ...", configfile = ctx.configfile);
|
||||||
ctx.cfg.load(&ctx.configfile);
|
ctx.cfg.load(&ctx.configfile);
|
||||||
|
|
||||||
println!("Adding inotify watch on {} file ...", ctx.configfile);
|
println!(
|
||||||
|
"Adding inotify watch on {configfile} file ...",
|
||||||
|
configfile = ctx.configfile
|
||||||
|
);
|
||||||
ctx.inotify
|
ctx.inotify
|
||||||
.add_watch(ctx.configfile.as_str(), AddWatchFlags::IN_MODIFY)
|
.add_watch(ctx.configfile.as_str(), AddWatchFlags::IN_MODIFY)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
get_zabbix_authtoken(&mut ctx.cfg);
|
||||||
|
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
pub fn hotreload(&mut self) {
|
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() {
|
let events = match self.inotify.read_events() {
|
||||||
Ok(ev) => ev,
|
Ok(ev) => ev,
|
||||||
Err(_) => vec![],
|
Err(_) => vec![],
|
||||||
};
|
};
|
||||||
if events.len() > 0 {
|
if events.len() > 0 {
|
||||||
self.cfg.load(self.configfile.as_str());
|
self.cfg.load(self.configfile.as_str());
|
||||||
println!("{:?} {} {:?}", self.cfg, events.len(), events);
|
println!(
|
||||||
|
"{cfg:?} {numevents} {events:?}",
|
||||||
|
cfg = self.cfg,
|
||||||
|
numevents = events.len(),
|
||||||
|
events = events
|
||||||
|
);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
sleep(Duration::from_secs(self.cfg.refresh.unwrap_or(5)));
|
sleep(Duration::from_millis(waitinc));
|
||||||
}
|
}
|
||||||
|
i += waitinc;
|
||||||
}
|
}
|
||||||
pub fn argparse() -> ArgMatches<'static> {
|
|
||||||
App::new("Zabbix Launch")
|
|
||||||
.version("1.0.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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +141,8 @@ impl<'a> Config {
|
|||||||
|
|
||||||
let mut file = match fileopen {
|
let mut file = match fileopen {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => {
|
Err(err) => {
|
||||||
panic!("{}", e);
|
panic!("{err}", err = err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
12
src/main.rs
12
src/main.rs
@ -2,16 +2,14 @@ pub mod config;
|
|||||||
mod padcontrol;
|
mod padcontrol;
|
||||||
mod zabbix;
|
mod zabbix;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate clap;
|
||||||
|
|
||||||
use config::Context;
|
use config::Context;
|
||||||
use zabbix::problems::ZabbixLayout;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut datamatrix = ZabbixLayout::new();
|
|
||||||
|
|
||||||
// load configuration
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
zabbix::api::get_zabbix_authtoken(&mut context.cfg);
|
|
||||||
//let (mut canvas, mut _poller) = padcontrol::initpad();
|
|
||||||
//padcontrol::draw(&mut canvas, &mut datamatrix, &mut context);
|
//padcontrol::draw(&mut canvas, &mut datamatrix, &mut context);
|
||||||
padcontrol::test(&mut context);
|
//padcontrol::test(&mut context)
|
||||||
|
padcontrol::run(&mut context);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,44 @@
|
|||||||
use crate::config::Context;
|
use crate::config::Context;
|
||||||
use crate::zabbix::api::get_zabbix_problems;
|
use crate::zabbix::api::get_zabbix_problems;
|
||||||
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::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub const MATRIX_WIDTH: i32 = 8;
|
const MATRIX_WIDTH: i32 = 8;
|
||||||
pub const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH;
|
const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH;
|
||||||
|
|
||||||
pub fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) {
|
pub fn run(ctx: &mut Context) {
|
||||||
|
match ctx.mode.as_str() {
|
||||||
|
"draw" => {
|
||||||
|
let (mut canvas, mut _poller) = initpad();
|
||||||
|
draw(&mut canvas, ctx);
|
||||||
|
}
|
||||||
|
"input" => {
|
||||||
|
let (mut canvas, mut poller) = initpad();
|
||||||
|
input(&mut canvas, &mut poller);
|
||||||
|
}
|
||||||
|
"effect" => {
|
||||||
|
let (mut canvas, mut poller) = initpad();
|
||||||
|
effect(&mut canvas, &mut poller)
|
||||||
|
}
|
||||||
|
"test" => test(ctx),
|
||||||
|
_ => {
|
||||||
|
println!("No valid option choosen for mode");
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
Ok(o) => o,
|
Ok(o) => o,
|
||||||
_ => {
|
Err(err) => {
|
||||||
eprintln!("Failed to connect to device, check USB connection");
|
eprintln!(
|
||||||
std::process::exit(1);
|
"Failed to connect to device, check USB connection {err}",
|
||||||
|
err = err
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
println!("Connected to device using USB");
|
println!("Connected to device using USB");
|
||||||
@ -23,50 +46,40 @@ pub fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) {
|
|||||||
(canvas, poller)
|
(canvas, poller)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _input(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
|
fn input(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
|
||||||
for color in (0u64..).map(|f| Color::red_green_color(f as f32 / 60.0 / 2.5)) {
|
for color in (0u64..).map(|f| Color::red_green_color(f as f32 / 60.0 / 2.5)) {
|
||||||
for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
|
for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
|
||||||
canvas[msg.pad()] = color;
|
canvas[msg.pad()] = color;
|
||||||
println!("{:?}", msg.pad())
|
println!("{msg:?}", msg = msg.pad())
|
||||||
}
|
}
|
||||||
let _res = canvas.flush();
|
let _res = canvas.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test(ctx: &mut Context) {
|
fn draw(canvas: &mut CanvasLayout, ctx: &mut Context) {
|
||||||
println!("Refresh rate is {} seconds", ctx.cfg.refresh.unwrap());
|
println!(
|
||||||
loop {
|
"Refresh rate is {sec} seconds",
|
||||||
let zabbix_data_result = get_zabbix_problems(&ctx.cfg);
|
sec = ctx.cfg.refresh.unwrap()
|
||||||
let zabbix_data = match zabbix_data_result {
|
);
|
||||||
Ok(z) => z,
|
|
||||||
Err(_) => {
|
|
||||||
let duration = 10;
|
|
||||||
println!("Error requesting zabbix service, retrying in {}", duration);
|
|
||||||
sleep(Duration::from_secs(duration));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
println!("{}", zabbix_data);
|
|
||||||
ctx.hotreload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(canvas: &mut CanvasLayout, datamatrix: &mut ZabbixLayout, ctx: &mut Context) {
|
|
||||||
println!("Refresh rate is {} seconds", ctx.cfg.refresh.unwrap());
|
|
||||||
loop {
|
loop {
|
||||||
let zabbix_data_result = get_zabbix_problems(&ctx.cfg);
|
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(err) => {
|
||||||
println!("Error requesting service");
|
let duration = 10;
|
||||||
sleep(Duration::from_secs(10));
|
println!(
|
||||||
|
"Error requesting zabbix service, err is {err}, retrying in {duration}",
|
||||||
|
err = err,
|
||||||
|
duration = duration
|
||||||
|
);
|
||||||
|
sleep(Duration::from_secs(duration));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
datamatrix.compute(&zabbix_data);
|
ctx.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 ctx.datamatrix.layout.iter().enumerate() {
|
||||||
let p = Pad {
|
let p = Pad {
|
||||||
x: ((i as i32) % MATRIX_WIDTH),
|
x: ((i as i32) % MATRIX_WIDTH),
|
||||||
y: ((i as i32) / MATRIX_WIDTH) + 1,
|
y: ((i as i32) / MATRIX_WIDTH) + 1,
|
||||||
@ -88,15 +101,40 @@ pub fn draw(canvas: &mut CanvasLayout, datamatrix: &mut ZabbixLayout, ctx: &mut
|
|||||||
}
|
}
|
||||||
canvas.flush().unwrap();
|
canvas.flush().unwrap();
|
||||||
}
|
}
|
||||||
sleep(Duration::from_secs(ctx.cfg.refresh.unwrap_or(5)));
|
ctx.hotreload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _effect(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
|
fn test(ctx: &mut Context) {
|
||||||
|
println!(
|
||||||
|
"Refresh rate is {sec} seconds",
|
||||||
|
sec = ctx.cfg.refresh.unwrap()
|
||||||
|
);
|
||||||
|
loop {
|
||||||
|
let zabbix_data_result = get_zabbix_problems(&ctx.cfg);
|
||||||
|
let zabbix_data = match zabbix_data_result {
|
||||||
|
Ok(z) => z,
|
||||||
|
Err(err) => {
|
||||||
|
let duration = 10;
|
||||||
|
println!(
|
||||||
|
"Error requesting zabbix service, err is {err}, retrying in {duration}",
|
||||||
|
err = err,
|
||||||
|
duration = duration
|
||||||
|
);
|
||||||
|
sleep(Duration::from_secs(duration));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("{zabbix_data}", zabbix_data = zabbix_data);
|
||||||
|
ctx.hotreload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn effect(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
|
||||||
for color in (0u64..).map(|f| Color::red_green_color(f as f32 / 60.0 / 2.5)) {
|
for color in (0u64..).map(|f| Color::red_green_color(f as f32 / 60.0 / 2.5)) {
|
||||||
for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
|
for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
|
||||||
canvas[msg.pad()] = color;
|
canvas[msg.pad()] = color;
|
||||||
println!("{:?}", msg.pad())
|
println!("{msg:?}", msg = msg.pad())
|
||||||
}
|
}
|
||||||
let _res = canvas.flush();
|
let _res = canvas.flush();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::fmt::{Display, Formatter, Result};
|
use std::fmt::{Display, Formatter, Result};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ZabbixStatus {
|
pub enum ZabbixStatus {
|
||||||
High = 4,
|
High = 4,
|
||||||
Average = 3,
|
Average = 3,
|
||||||
@ -9,29 +9,15 @@ pub enum ZabbixStatus {
|
|||||||
Info = 1,
|
Info = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ZabbixLayout {
|
pub struct DataMatrix {
|
||||||
pub layout: Vec<ZabbixProblems>,
|
pub layout: Vec<ZabbixProblems>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZabbixLayout {
|
impl DataMatrix {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { layout: Vec::new() }
|
Self { layout: Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ZabbixProblems {
|
|
||||||
pub status: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ZabbixProblems {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
|
||||||
write!(f, "status: {:?}", self.status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZabbixLayout {
|
|
||||||
pub fn compute(&mut self, input: &Value) {
|
pub fn compute(&mut self, input: &Value) {
|
||||||
self.layout = Vec::new();
|
self.layout = Vec::new();
|
||||||
for j in input.as_object().unwrap()["result"].as_array().unwrap() {
|
for j in input.as_object().unwrap()["result"].as_array().unwrap() {
|
||||||
@ -41,3 +27,14 @@ impl ZabbixLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ZabbixProblems {
|
||||||
|
pub status: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ZabbixProblems {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
|
write!(f, "status: {status:?}", status = self.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user