Compare commits

...

29 Commits

Author SHA1 Message Date
f2bb375972 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-12 22:45:54 +02:00
872e17f6f2 Merge few changes from branch 'launchpad_mini_mk3'
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-10 19:37:03 +01:00
e30efa1d9a fix: api json data & launchy remote repository
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-10 19:25:19 +01:00
9f07930013 updated dependencies 2023-02-10 18:28:13 +01:00
b73fc7a7c2 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-16 11:42:30 +02:00
ef60d4bda9 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-06-04 15:33:56 +02:00
c128a7dce5 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-27 14:39:44 +02:00
50a2da488d updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-22 19:20:01 +02:00
Paul Lecuq
f6e801dc58 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-16 14:29:27 +02:00
Paul Lecuq
f3a1d5c900 updated zabbixlaunch 2022-05-16 14:29:19 +02:00
Paul Lecuq
ca349dc187 updated README.md
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-10 12:59:24 +02:00
Paul Lecuq
ccf9fd587d updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-10 12:53:44 +02:00
Paul Lecuq
ec23da0565 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-10 12:50:58 +02:00
bf03adb549 updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-08 19:49:27 +02:00
Paul Lecuq
f18f25727d updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-04 19:04:29 +02:00
Paul Lecuq
e364dc7540 update to version 1.0.1
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-29 17:35:33 +02:00
Paul Lecuq
463795385d updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-21 17:31:01 +02:00
Paul Lecuq
95322749fe updated dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-11 10:19:14 +02:00
e9973e109f Merge branch 'master' of ssh://git.paulbsd.com:2222/paulbsd/zabbixlaunch
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-26 12:07:47 +01:00
e7850c8d72 updated .drone.yml 2022-03-26 12:07:33 +01:00
Paul Lecuq
59e1057ca7 updates on dependencies, changed some pub functions to private
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
continuous-integration/drone Build is failing
2022-03-15 13:26:24 +01:00
811f1155a9 updated .drone.yml
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-11 23:43:21 +01:00
Paul Lecuq
2f1be523f8 cleaned-up code and added compiler optimizations
Some checks failed
continuous-integration/drone/push Build is failing
2022-03-04 10:14:53 +01:00
Paul Lecuq
9fefb6e8a0 some code cleaning, updated dependencies
Some checks failed
continuous-integration/drone/push Build is failing
2022-03-01 18:09:20 +01:00
Paul Lecuq
55dc677b46 * Code cleanup, feature updated
- cleanup unsed variables
- added dynamic slow effect based on number of issues
2022-02-16 17:48:24 +01:00
Paul Lecuq
72d12319c1 misc updates and fixes 2022-01-17 17:57:57 +01:00
Paul Lecuq
0dc914beb5 updated Cargo.toml 2021-12-09 09:40:43 +01:00
Paul Lecuq
05b38b3540 updated zabbixlaunch 2021-12-07 18:49:04 +01:00
Paul Lecuq
b7a9def20d updated config management 2021-12-06 17:17:24 +01:00
11 changed files with 811 additions and 612 deletions

37
.drone.yml Normal file
View File

@ -0,0 +1,37 @@
---
kind: pipeline
type: docker
name: default
steps:
- name: test
image: rust:1
commands:
- apt-get update -y
- apt-get install libasound2-dev -y
- cargo build --verbose --all
- cargo test --verbose --all
- name: release
image: rust:1
commands:
- apt-get update -y
- apt-get install libasound2-dev -y
- cargo build --release --verbose --all
- cd target/release
- tar -czvf zabbixlaunch-${DRONE_TAG}.tar.gz zabbixlaunch
when:
event: tag
- name: publish
image: plugins/gitea-release
settings:
base_url: https://git.paulbsd.com
api_key:
from_secret: gitea_token
files: "target/release/*.tar.gz"
checksum:
- sha256
- sha512
environment:
PLUGIN_TITLE: ""
when:
event: tag

1030
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,18 @@
[package] [package]
name = "zabbixlaunch" name = "zabbixlaunch"
version = "1.0.0" version = "1.0.1"
edition = "2018" edition = "2021"
authors = ["PaulBSD <paul@paulbsd.com>"]
description = "Lights up Launchpad mini using Zabbix data"
repository = "https://git.paulbsd.com/paulbsd/zabbixlaunch"
# 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", features = ["yaml"] } clap = "4.3"
embedded-graphics = { version = "0.7.1", optional = true } embedded-graphics = { version = "0.8", optional = true }
launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" } launchy = { git = "https://github.com/paulbsd/launchy", branch = "develop-launchpad-mini-mk3" }
reqwest = { version = "0.11.5", features = ["blocking", "json"] } nix = "0.26"
serde = { version = "1.0.130", features = ["derive"] } reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] }
serde_json = "1.0.68" serde = { version = "1.0", features = ["derive"] }
nix = "0.23.0" serde_json = "1.0"

View File

@ -1,5 +1,7 @@
# zabbixlaunch # zabbixlaunch
[![Build Status](https://drone.paulbsd.com/api/badges/paulbsd/zabbixlaunch/status.svg)](https://drone.paulbsd.com/paulbsd/zabbixlaunch)
## Summary ## Summary
zabbixlaunch is a application that take control over a launchpad mini, and draw problems handled by Zabbix zabbixlaunch is a application that take control over a launchpad mini, and draw problems handled by Zabbix
@ -14,8 +16,9 @@ zabbixlaunch is a application that take control over a launchpad mini, and draw
"server": "https://zabbix.acme.com/api_jsonrpc.php", "server": "https://zabbix.acme.com/api_jsonrpc.php",
"username": "bob", "username": "bob",
"password": "password", "password": "password",
"authtoken": "token", "sloweffect": true,
"limit": 20 "refresh": 2,
"limit": 100
} }
``` ```
@ -48,7 +51,7 @@ cargo build --release
## License ## License
```text ```text
Copyright (c) 2021 PaulBSD Copyright (c) 2021, 2022 PaulBSD
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

8
config.json.sample Normal file
View File

@ -0,0 +1,8 @@
{
"server": "https://zabbix.acme.com/api_jsonrpc.php",
"username": "bob",
"password": "password",
"sloweffect": true,
"refresh": 2,
"limit": 100
}

View File

@ -1,17 +0,0 @@
---
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

View File

@ -1,6 +1,6 @@
use crate::zabbix::api::get_zabbix_authtoken; use crate::zabbix::api::get_zabbix_authtoken;
use crate::zabbix::problems::DataMatrix; use crate::zabbix::problems::DataMatrix;
use clap::App; use clap::{Arg, ArgMatches, Command};
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;
@ -11,35 +11,53 @@ use std::string::String;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
#[derive(Debug)]
pub enum ReloadFrequency { pub enum ReloadFrequency {
High = 50, High = 50,
Medium = 20, Medium = 20,
Low = 10, Low = 10,
} }
#[derive(Debug, Clone)]
pub enum Mode {
Draw,
Test,
Input,
Effect,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Context { pub struct Context {
pub cfg: Config, pub cfg: Config,
pub configfile: String, configfile: String,
pub inotify: Inotify, inotify: Inotify,
pub datamatrix: DataMatrix, pub datamatrix: DataMatrix,
pub mode: String, pub mode: Option<Mode>,
} }
impl Context { impl Context {
pub fn new() -> Self { pub fn new() -> Self {
let yaml = load_yaml!("cli.yml"); let argp: ArgMatches = Context::argparse();
let cli = App::from_yaml(yaml).get_matches();
let configfile = cli.value_of("config").unwrap_or("config.json").to_string(); let configfile = argp
.get_one::<String>("config")
.unwrap_or(&"config.json".to_string())
.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(), datamatrix: DataMatrix::new(),
mode: cli.value_of("mode").unwrap_or("draw").to_string(), 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); println!("Loading {configfile} file ...", configfile = ctx.configfile);
@ -56,9 +74,37 @@ impl Context {
ctx 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) { pub fn hotreload(&mut self) {
let mut i = 0; let mut i = 0;
let waitmilli = self.cfg.refresh.unwrap_or(5) * 1000; let waitmilli = self.cfg.refresh.unwrap_or(5) * 1000;
while i < waitmilli { while i < waitmilli {
let waitinc = waitmilli / ReloadFrequency::Medium as u64; let waitinc = waitmilli / ReloadFrequency::Medium as u64;
let events = match self.inotify.read_events() { let events = match self.inotify.read_events() {
@ -66,11 +112,9 @@ impl Context {
Err(_) => vec![], Err(_) => vec![],
}; };
if events.len() > 0 { if events.len() > 0 {
println!("Reloading {cfg}", cfg = self.configfile);
self.cfg.load(self.configfile.as_str()); self.cfg.load(self.configfile.as_str());
println!( get_zabbix_authtoken(&mut self.cfg);
"Reloading {cfg}",
cfg = self.configfile
);
break; break;
} else { } else {
sleep(Duration::from_millis(waitinc)); sleep(Duration::from_millis(waitinc));
@ -85,6 +129,7 @@ pub struct Config {
pub server: String, pub server: String,
pub username: String, pub username: String,
pub password: String, pub password: String,
#[serde(skip_serializing)]
pub authtoken: Option<String>, pub authtoken: Option<String>,
pub sloweffect: Option<bool>, pub sloweffect: Option<bool>,
pub refresh: Option<u64>, pub refresh: Option<u64>,
@ -104,16 +149,17 @@ impl<'a> Config {
} }
} }
pub fn load(&'a mut self, configfile: &str) { 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 mut error_reading = false;
let fileexists = match filemeta { let fileexists = match filemeta {
Ok(_) => true, Ok(_) => true,
Err(_) => false, Err(_) => false,
}; };
if !fileexists { if !fileexists {
let _a = File::create(configfile); File::create(configfile).unwrap();
} }
fileopen = File::open(configfile); fileopen = File::open(configfile);
@ -126,28 +172,50 @@ impl<'a> Config {
let mut contents = String::new(); let mut contents = String::new();
file.read_to_string(&mut contents).unwrap(); file.read_to_string(&mut contents).unwrap();
let parse: Result<JsonValue, JsonError> = serde_json::from_str(contents.as_str()); let parse: Result<JsonValue, JsonError> = serde_json::from_str(contents.as_str());
*self = match parse { let ncfg = match parse {
Ok(cfg) => { Ok(ncfg) => {
let tmpcfg = Config::new(); let tmpcfg = Config::new();
Config { Config {
server: cfg["server"].as_str().unwrap_or(tmpcfg.server.as_str()).to_string(), server: ncfg["server"]
username: cfg["username"].as_str().unwrap_or(tmpcfg.username.as_str()).to_string(), .as_str()
password: cfg["password"].as_str().unwrap_or(tmpcfg.password.as_str()).to_string(), .unwrap_or(tmpcfg.server.as_str())
authtoken: Some(cfg["authtoken"].as_str().unwrap_or(tmpcfg.authtoken.unwrap().as_str()).to_string()), .to_string(),
sloweffect: Some(cfg["sloweffect"].as_bool().unwrap_or(tmpcfg.sloweffect.unwrap())), username: ncfg["username"]
refresh: Some(cfg["refresh"].as_u64().unwrap_or(tmpcfg.refresh.unwrap())), .as_str()
limit: Some(cfg["limit"].as_u64().unwrap_or(tmpcfg.limit.unwrap())), .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) => { Err(err) => {
error_reading = true;
println!("error occured: '{}'", err); println!("error occured: '{}'", err);
Config::new() Config::new()
} }
}; };
self.save(&configfile); *self = ncfg;
if !fileexists || error_reading {
self.save(&configfile);
}
} }
pub fn save(&self, configfile: &str) { 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();
} }

View File

@ -1,10 +1,7 @@
pub mod config; mod config;
mod padcontrol; mod padcontrol;
mod zabbix; mod zabbix;
#[macro_use]
extern crate clap;
use config::Context; use config::Context;
fn main() { fn main() {

View File

@ -1,32 +1,34 @@
use crate::config::Context; use crate::config::{Context, Mode};
use crate::zabbix::api::get_zabbix_problems; use crate::zabbix::api::get_zabbix_problems;
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 const REQUEST_TIMEOUT: i32 = 10; const REQUEST_TIMEOUT: i32 = 5;
const ZERO_COLOR: f32 = 0.;
const ONE_COLOR: f32 = 1.;
const SLOWEFFECT_FACTOR: f32 = 800.0;
pub fn run(ctx: &mut Context) { pub fn run(ctx: &mut Context) {
match ctx.mode.as_str() { match ctx.mode {
"draw" => { Some(Mode::Draw) => {
let (mut canvas, mut _poller) = initpad(); let (mut canvas, mut _poller) = initpad();
draw(&mut canvas, ctx); draw(&mut canvas, ctx);
} }
"input" => { Some(Mode::Input) => {
let (mut canvas, mut poller) = initpad(); let (mut canvas, mut poller) = initpad();
input(&mut canvas, &mut poller); input(&mut canvas, &mut poller);
} }
"effect" => { Some(Mode::Effect) => {
let (mut canvas, mut poller) = initpad(); let (mut canvas, mut poller) = initpad();
effect(&mut canvas, &mut poller) effect(&mut canvas, &mut poller)
} }
"test" => test(ctx), Some(Mode::Test) => test(ctx),
_ => { None => {
println!("No valid option choosen for mode"); println!("No valid option choosen for mode");
std::process::exit(1)
} }
} }
} }
@ -34,16 +36,14 @@ pub fn run(ctx: &mut Context) {
fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) { 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(_) => {
println!("Connected to device using USB");
clear(&mut canvas);
}
Err(err) => { Err(err) => {
eprintln!( eprintln!("Failed to connect to device, check USB connection {err}",);
"Failed to connect to device, check USB connection {err}",
err = err
);
} }
}; };
println!("Connected to device using USB");
clear(&mut canvas);
(canvas, poller) (canvas, poller)
} }
@ -53,7 +53,7 @@ fn input(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
canvas[msg.pad()] = color; canvas[msg.pad()] = color;
println!("{msg:?}", msg = msg.pad()) println!("{msg:?}", msg = msg.pad())
} }
let _res = canvas.flush(); canvas.flush().unwrap();
} }
} }
@ -63,11 +63,13 @@ fn test(ctx: &mut Context) {
sec = ctx.cfg.refresh.unwrap() sec = ctx.cfg.refresh.unwrap()
); );
loop { loop {
let zabbix_data_result = get_zabbix_problems(&ctx.cfg); let zabbix_data = match get_zabbix_problems(&ctx.cfg) {
let zabbix_data = match zabbix_data_result {
Ok(z) => z, Ok(z) => z,
Err(_) => { Err(_) => {
println!("Error requesting zabbix service, retrying in {}", REQUEST_TIMEOUT); println!(
"Error requesting zabbix service, retrying in {} seconds",
REQUEST_TIMEOUT
);
sleep(Duration::from_secs(REQUEST_TIMEOUT as u64)); sleep(Duration::from_secs(REQUEST_TIMEOUT as u64));
continue; continue;
} }
@ -77,78 +79,85 @@ fn test(ctx: &mut Context) {
} }
} }
pub fn draw(canvas: &mut CanvasLayout, ctx: &mut Context) { fn draw(canvas: &mut CanvasLayout, ctx: &mut Context) {
println!("Refresh rate is {} seconds", ctx.cfg.refresh.unwrap()); println!("Refresh rate is {} seconds", ctx.cfg.refresh.unwrap());
loop { loop {
let zabbix_data_result = get_zabbix_problems(&ctx.cfg); let mut max = 0;
let zabbix_data = match zabbix_data_result { let zabbix_data = match get_zabbix_problems(&ctx.cfg) {
Ok(zabbix_data) => zabbix_data, Ok(zabbix_data) => zabbix_data,
Err(_) => { Err(_) => {
println!("Error requesting zabbix service, retrying in {}", REQUEST_TIMEOUT); println!(
"Error requesting zabbix service, retrying in {}",
REQUEST_TIMEOUT
);
sleep(Duration::from_secs(REQUEST_TIMEOUT as u64)); sleep(Duration::from_secs(REQUEST_TIMEOUT as u64));
continue; continue;
} }
}; };
ctx.datamatrix.compute(&zabbix_data); ctx.datamatrix.compute(&zabbix_data);
clear(canvas); clear(canvas);
let mut max = 0;
for (i, j) in ctx.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,
}; };
let c = match j.status { canvas[p] = match j.status {
5 => Color::RED, 5 => Color::RED,
4 => Color::from_hue(0.05), 4 => Color::from_hue(0.05),
3 => Color::from_hue(0.1), 3 => Color::from_hue(0.1),
2 => Color::from_hue(1.22), 2 => Color::from_hue(1.22),
_ => Color::GREEN, _ => Color::GREEN,
}; };
canvas[p] = c; if ctx.cfg.sloweffect.unwrap() {
sleep(Duration::from_millis(
(SLOWEFFECT_FACTOR * (1.0 / ctx.datamatrix.layout.len() as f32)) as u64,
));
}
canvas.flush().unwrap();
max += 1; max += 1;
if max >= MATRIX_SIZE { if max >= MATRIX_SIZE {
break; break;
} }
if ctx.cfg.sloweffect.unwrap() {
sleep(Duration::from_millis(15));
}
canvas.flush().unwrap();
} }
ctx.hotreload(); ctx.hotreload();
} }
} }
fn effect(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) { 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)) { loop {
for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) { for color in (0u64..).map(|f| Color::red_green_color(f as f32 / 60.0 / 2.5)) {
canvas[msg.pad()] = color; for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
println!("{msg:?}", msg = msg.pad()) canvas[msg.pad()] = color;
println!("{msg:?}", msg = msg.pad())
}
canvas.flush().unwrap();
canvas.iter().for_each(|pad| {
let surrounding_color = pad
.neighbors_5()
.iter()
.map(|&p| canvas.get(p).unwrap_or(Color::GREEN))
.sum::<Color>()
/ 5.0
/ 1.05;
canvas[pad] = canvas[pad].mix(surrounding_color, 0.4);
});
} }
let _res = canvas.flush(); clear(canvas);
canvas.iter().for_each(|pad| {
let surrounding_color = pad
.neighbors_5()
.iter()
.map(|&p| canvas.get(p).unwrap_or(Color::GREEN))
.sum::<Color>()
/ 5.0
/ 1.05;
canvas[pad] = canvas[pad].mix(surrounding_color, 0.4);
});
} }
} }
fn clear(canvas: &mut CanvasLayout) { fn clear(canvas: &mut CanvasLayout) {
for a in 0..8 { for a in 0..MATRIX_WIDTH {
for b in 0..9 { for b in 0..MATRIX_WIDTH + 1 {
canvas[Pad { x: a, y: b }] = Color { canvas[Pad { x: a, y: b }] = Color {
r: 0f32, r: ZERO_COLOR,
g: 0f32, g: ZERO_COLOR,
b: 1f32, b: ONE_COLOR,
}; };
} }
} }
let _res = canvas.flush(); canvas.flush().unwrap();
} }

View File

@ -1,7 +1,8 @@
use std::time::Duration;
use std::thread::sleep;
use crate::config::Config; use crate::config::Config;
use serde_json::{json, Value}; use serde_json::json;
use serde_json::Value as JsonValue;
//use std::thread::sleep;
//use std::time::Duration;
pub const ZABBIX_API_VERSION: &'static str = "2.0"; pub const ZABBIX_API_VERSION: &'static str = "2.0";
pub const ZABBIX_API_ID: i32 = 1; pub const ZABBIX_API_ID: i32 = 1;
@ -12,27 +13,36 @@ pub fn get_zabbix_authtoken(cfg: &mut Config) {
let resp = reqwest::blocking::Client::new() let resp = reqwest::blocking::Client::new()
.post(&cfg.server) .post(&cfg.server)
.json(&body) .json(&body)
.send() .send();
.unwrap(); match resp {
Ok(v) => {
let values: Value = resp.json().unwrap(); let values: JsonValue = v.json().unwrap();
cfg.authtoken = Some(values["result"].as_str().unwrap().to_string()); cfg.authtoken = Some(values["result"].as_str().unwrap().to_string());
}
Err(e) => {
println!("{}", e);
cfg.authtoken = Some("".to_string());
}
};
} }
/// Fetch Zabbix problems /// Fetch Zabbix problems
pub fn get_zabbix_problems(cfg: &Config) -> Result<Value, reqwest::Error> { pub fn get_zabbix_problems(cfg: &Config) -> Result<JsonValue, reqwest::Error> {
let body = build_query_triggers(&cfg.authtoken.as_ref().unwrap_or(&String::from(""))); let body = build_query_triggers(&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();
Ok(resp.unwrap().json().unwrap()) match resp {
Ok(v) => v.json(),
Err(e) => Err(e),
}
} }
/// Check if Zabbix is operational /// Check if Zabbix is operational
/// Undefinitely check that Zabbix works /// Undefinitely check that Zabbix works
fn check_zabbix_connection(cfg: &Config) -> bool { /*fn check_zabbix_connection(cfg: &Config) -> bool {
let mut res: bool = false; let mut res: bool = false;
let delay = 5; let delay = 5;
let timeout = 10; let timeout = 10;
@ -48,16 +58,16 @@ fn check_zabbix_connection(cfg: &Config) -> bool {
sleep(Duration::from_secs(delay)); sleep(Duration::from_secs(delay));
} }
res res
} }*/
/// Build the query that fetchs the token /// Build the query that fetchs the token
fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) -> Value { fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) -> JsonValue {
let zabbix_api_function = "user.login"; let zabbix_api_function = "user.login";
json!({ json!({
"jsonrpc": ZABBIX_API_VERSION, "jsonrpc": ZABBIX_API_VERSION,
"method": zabbix_api_function, "method": zabbix_api_function,
"params": { "params": {
"user": zabbix_username, "username": zabbix_username,
"password": zabbix_password "password": zabbix_password
}, },
"id": ZABBIX_API_ID "id": ZABBIX_API_ID
@ -65,7 +75,7 @@ fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) ->
} }
/// Build the query that fetchs problems /// Build the query that fetchs problems
fn build_query_problems(zabbix_token: &String, zabbix_limit: i64) -> Value { /*fn build_query_problems(zabbix_token: &String, zabbix_limit: i64) -> JsonValue {
let zabbix_api_function = "problem.get"; let zabbix_api_function = "problem.get";
json!({ json!({
"jsonrpc": ZABBIX_API_VERSION, "jsonrpc": ZABBIX_API_VERSION,
@ -85,10 +95,10 @@ fn build_query_problems(zabbix_token: &String, zabbix_limit: i64) -> Value {
"auth": zabbix_token, "auth": zabbix_token,
"id": ZABBIX_API_ID "id": ZABBIX_API_ID
}) })
} }*/
/// Build the query that fetchs triggers /// Build the query that fetchs triggers
fn build_query_triggers(zabbix_token: &String) -> Value { fn build_query_triggers(zabbix_token: &String) -> JsonValue {
let zabbix_api_function = "trigger.get"; let zabbix_api_function = "trigger.get";
json!({ json!({
"jsonrpc": ZABBIX_API_VERSION, "jsonrpc": ZABBIX_API_VERSION,

View File

@ -1,13 +1,14 @@
use serde_json::Value; use serde_json::Value;
use std::fmt::{Display, Formatter, Result}; use std::fmt::{Display, Formatter, Result};
#[derive(Debug, Clone)] /*#[derive(Debug, Clone)]
pub enum ZabbixStatus { pub enum ZabbixStatus {
Disaster = 5,
High = 4, High = 4,
Average = 3, Average = 3,
Warning = 2, Warning = 2,
Info = 1, Info = 1,
} }*/
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DataMatrix { pub struct DataMatrix {
@ -25,6 +26,10 @@ impl DataMatrix {
let severity = res["priority"].as_str().unwrap().parse::<i64>().unwrap(); let severity = res["priority"].as_str().unwrap().parse::<i64>().unwrap();
self.layout.push(ZabbixProblems { status: severity }); self.layout.push(ZabbixProblems { status: severity });
} }
// test
/*for i in 0..1000 {
self.layout.push(ZabbixProblems { status: 5 });
}*/
} }
} }