Compare commits

..

5 Commits

11 changed files with 920 additions and 833 deletions

View File

@ -1,37 +1,101 @@
--- ---
kind: pipeline kind: pipeline
type: docker type: docker
name: default name: cleanup-before
steps: steps:
- name: test - name: clean
image: rust:1 image: alpine
commands: commands:
- apt-get update -y - rm -rf /build/*
- apt-get install libasound2-dev -y volumes:
- cargo build --verbose --all - name: build
- cargo test --verbose --all path: /build
- 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: when:
event: tag event: tag
- name: publish
volumes:
- name: build
host:
path: /tmp/ipbl/build
---
kind: pipeline
type: docker
name: default-linux-amd64
steps:
- name: Build
image: rust:latest
commands:
- cargo build --verbose --all
---
kind: pipeline
type: docker
name: gitea-release
steps:
- name: move
image: alpine
commands:
- mv target/release/* ./
volumes:
- name: build
path: /drone/src/build
when:
event: tag
- name: release
image: plugins/gitea-release image: plugins/gitea-release
settings: settings:
base_url: https://git.paulbsd.com base_url: https://git.paulbsd.com
api_key: api_key:
from_secret: gitea_token from_secret: gitea_token
files: "target/release/*.tar.gz" files: "*.tar.gz"
checksum: checksum:
- sha256 - sha256
- sha512 - sha512
environment: title: VERSION
PLUGIN_TITLE: "" volumes:
- name: build
path: /drone/src/build
when: when:
event: tag event: tag
- name: ls
image: alpine
commands:
- find .
volumes:
- name: build
path: /drone/src/build
when:
event: tag
volumes:
- name: build
host:
path: /tmp/ipbl/build
depends_on:
- default-linux-amd64
---
kind: pipeline
type: docker
name: cleanup-after
steps:
- name: clean
image: alpine
commands:
- rm -rf /build/*
volumes:
- name: build
path: /build
when:
event: tag
volumes:
- name: build
host:
path: /tmp/ipbl/build

1130
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,17 @@
[package] [package]
name = "zabbixlaunch" name = "zabbixlaunch"
version = "1.0.1" version = "1.0.0"
edition = "2021" edition = "2018"
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 = "4.3" clap = { version = "2", features = ["yaml"] }
embedded-graphics = { version = "0.8", optional = true } embedded-graphics = { version = "0.7", optional = true }
launchy = { git = "https://github.com/paulbsd/launchy", branch = "develop-launchpad-mini-mk3" } futures = "*"
nix = "0.26" launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" }
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] } nix = "0.23"
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
tokio = { version = "1", features = ["full"] }

View File

@ -1,7 +1,5 @@
# 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
@ -16,9 +14,8 @@ 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",
"sloweffect": true, "authtoken": "token",
"refresh": 2, "limit": 20
"limit": 100
} }
``` ```
@ -51,7 +48,7 @@ cargo build --release
## License ## License
```text ```text
Copyright (c) 2021, 2022 PaulBSD Copyright (c) 2021 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

View File

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

17
src/config/cli.yml Normal file
View 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

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::{Arg, ArgMatches, Command}; use clap::App;
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;
@ -8,60 +8,42 @@ use serde_json::Value as JsonValue;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::string::String; use std::string::String;
use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use tokio::time::sleep;
#[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,
configfile: String, pub configfile: String,
inotify: Inotify, pub inotify: Inotify,
pub datamatrix: DataMatrix, pub datamatrix: DataMatrix,
pub mode: Option<Mode>, pub mode: String,
} }
impl Context { impl Context {
pub fn new() -> Self { pub async fn new() -> Self {
let argp: ArgMatches = Context::argparse(); let yaml = load_yaml!("cli.yml");
let cli = App::from_yaml(yaml).get_matches();
let configfile = argp let configfile = cli.value_of("config").unwrap_or("config.json").to_string();
.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: match argp.get_one::<String>("mode").unwrap().as_str() { mode: cli.value_of("mode").unwrap_or("draw").to_string(),
"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);
ctx.cfg.load(&ctx.configfile); ctx.cfg.load(&ctx.configfile.to_string()).await;
println!( println!(
"Adding inotify watch on {configfile} file ...", "Adding inotify watch on {configfile} file ...",
@ -70,57 +52,38 @@ impl Context {
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); get_zabbix_authtoken(&mut ctx.cfg).await;
ctx ctx
} }
fn argparse() -> ArgMatches { /*pub async fn hotreload(&mut self) {
Command::new(env!("CARGO_PKG_NAME")) let events = match self.inotify.read_events() {
.version(env!("CARGO_PKG_VERSION")) Ok(ev) => ev,
.author(env!("CARGO_PKG_AUTHORS")) Err(_) => vec![],
.about(env!("CARGO_PKG_DESCRIPTION")) };
.arg( if events.len() > 0 {
Arg::new("config") println!("Reloading {cfg}", cfg = self.configfile);
.short('c') get_zabbix_authtoken(&mut self.cfg).await;
.long("config") self.cfg.load(self.configfile.as_str());
.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;
} }
std::thread::sleep(std::time::Duration::from_secs(5));
}*/
}
pub async fn hotreload(ctx: &mut Context, ctxsender: &tokio::sync::mpsc::Sender<Context>) {
println!("function hotreload, {:?}", ctxsender);
loop {
let events = match ctx.to_owned().inotify.read_events() {
Ok(ev) => ev,
Err(_) => vec![],
};
if events.len() > 0 {
ctx.cfg.load(&ctx.configfile).await;
println!("{cfg:?}", cfg = ctx.cfg);
}
println!("Sending {:?}", ctx);
ctxsender.send(ctx.to_owned()).await;
} }
} }
@ -149,21 +112,8 @@ impl<'a> Config {
} }
} }
fn load(&'a mut self, configfile: &str) { async fn load(&mut self, configfile: &String) {
let fileopen: Result<File, std::io::Error>; let mut file = match File::open(configfile) {
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, Ok(f) => f,
Err(err) => { Err(err) => {
panic!("{err}", err = err); panic!("{err}", err = err);
@ -172,51 +122,56 @@ 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());
let ncfg = match parse { *self = match parse {
Ok(ncfg) => { Ok(cfg) => {
let tmpcfg = Config::new(); let tmpcfg = Config::new();
Config { Config {
server: ncfg["server"] server: cfg["server"]
.as_str() .as_str()
.unwrap_or(tmpcfg.server.as_str()) .unwrap_or(tmpcfg.server.as_str())
.to_string(), .to_string(),
username: ncfg["username"] username: cfg["username"]
.as_str() .as_str()
.unwrap_or(tmpcfg.username.as_str()) .unwrap_or(tmpcfg.username.as_str())
.to_string(), .to_string(),
password: ncfg["password"] password: cfg["password"]
.as_str() .as_str()
.unwrap_or(tmpcfg.password.as_str()) .unwrap_or(tmpcfg.password.as_str())
.to_string(), .to_string(),
authtoken: Some( authtoken: Some(
ncfg["authtoken"] self.authtoken
.as_str() .clone()
.unwrap_or(self.authtoken.clone().unwrap().as_str()) .unwrap_or(tmpcfg.authtoken.unwrap().to_string())
.to_string(), .to_string(),
), ),
sloweffect: Some( sloweffect: Some(
ncfg["sloweffect"] cfg["sloweffect"]
.as_bool() .as_bool()
.unwrap_or(tmpcfg.sloweffect.unwrap()), .unwrap_or(tmpcfg.sloweffect.unwrap()),
), ),
refresh: Some(ncfg["refresh"].as_u64().unwrap_or(tmpcfg.refresh.unwrap())), refresh: Some(cfg["refresh"].as_u64().unwrap_or(tmpcfg.refresh.unwrap())),
limit: Some(ncfg["limit"].as_u64().unwrap_or(tmpcfg.limit.unwrap())), limit: Some(cfg["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 = ncfg; self.save(&configfile).await;
if !fileexists || error_reading {
self.save(&configfile);
}
} }
fn save(&self, configfile: &str) { async fn save(&self, configfile: &String) {
let file = File::create(configfile).unwrap(); let file: File;
serde_json::to_writer_pretty(file, &self).unwrap(); let filemeta = std::fs::metadata(configfile);
let fileexists = match filemeta {
Ok(_) => true,
Err(_) => false,
};
if !fileexists {
file = File::create(configfile).unwrap();
serde_json::to_writer_pretty(file, &self).unwrap();
sleep(Duration::from_millis(1)).await;
}
} }
} }

View File

@ -1,10 +1,11 @@
mod config; pub mod config;
mod padcontrol; mod padcontrol;
mod zabbix; mod zabbix;
use config::Context; #[macro_use]
extern crate clap;
fn main() { #[tokio::main]
let mut context = Context::new(); async fn main() {
padcontrol::run(&mut context); padcontrol::run().await;
} }

View File

@ -1,163 +1,177 @@
use crate::config::{Context, Mode}; use crate::config::{hotreload, Context};
use crate::zabbix::api::get_zabbix_problems; use crate::zabbix::api::*;
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; use std::time::Duration;
use tokio::sync::mpsc;
use tokio::time::sleep;
const MATRIX_WIDTH: i32 = 8; const MATRIX_WIDTH: i32 = 8;
const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH; const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH;
const REQUEST_TIMEOUT: i32 = 5; const REQUEST_WAITFOR: i32 = 5;
const ZERO_COLOR: f32 = 0.; const ZERO_COLOR: f32 = 0.;
const ONE_COLOR: f32 = 1.; const ONE_COLOR: f32 = 1.;
const SLOWEFFECT_FACTOR: f32 = 800.0;
pub fn run(ctx: &mut Context) { const POLLER_ITER: u64 = 17;
match ctx.mode {
Some(Mode::Draw) => { fn log(num: i64) {
let (mut canvas, mut _poller) = initpad(); return println!("test{} 🦀", num);
draw(&mut canvas, ctx); }
}
Some(Mode::Input) => { pub async fn run<'a>() {
let (mut canvas, mut poller) = initpad(); log(1);
input(&mut canvas, &mut poller); let mut ctx = Box::new(Context::new().await);
} log(2);
Some(Mode::Effect) => { let (tx1, mut rx1) = mpsc::channel(1);
let (mut canvas, mut poller) = initpad(); log(3);
effect(&mut canvas, &mut poller) let t1 = tokio::task::spawn(async move { test(&mut rx1).await });
} let t2 = tokio::task::spawn(async move { hotreload(&mut ctx, &tx1).await });
Some(Mode::Test) => test(ctx), tokio::join!(t1, t2);
None => { log(4);
println!("No valid option choosen for mode"); }
}
async fn test<'a>(ctxreceiver: &mut tokio::sync::mpsc::Receiver<Context>) {
while let Some(val) = ctxreceiver.recv().await {
println!("Fetching zabbix problems, {:?}", val.cfg);
let zabbix_data = get_zabbix_problems(&val.cfg).await.unwrap();
println!("{}", zabbix_data["result"][0]);
println!("sleeping during {}", val.cfg.refresh.unwrap());
sleep(Duration::from_secs(val.cfg.refresh.unwrap())).await;
} }
} }
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(_) => { Ok(o) => o,
println!("Connected to device using USB");
clear(&mut canvas);
}
Err(err) => { Err(err) => {
eprintln!("Failed to connect to device, check USB connection {err}",); eprintln!(
"Failed to connect to device, check USB connection {err}",
err = err
);
} }
}; };
println!("Connected to device using USB");
clear(&mut canvas);
(canvas, poller) (canvas, poller)
} }
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(POLLER_ITER)
.filter(|msg| msg.is_press())
{
canvas[msg.pad()] = color; canvas[msg.pad()] = color;
println!("{msg:?}", msg = msg.pad()) println!("{msg:?}", msg = msg.pad())
} }
canvas.flush().unwrap(); let _res = canvas.flush();
} }
} }
fn test(ctx: &mut Context) { /*
println!( async fn draw(canvas: &mut CanvasLayout<'_>, ctx: &mut Context) {
"Refresh rate is {sec} seconds",
sec = ctx.cfg.refresh.unwrap()
);
loop {
let zabbix_data = match get_zabbix_problems(&ctx.cfg) {
Ok(z) => z,
Err(_) => {
println!(
"Error requesting zabbix service, retrying in {} seconds",
REQUEST_TIMEOUT
);
sleep(Duration::from_secs(REQUEST_TIMEOUT as u64));
continue;
}
};
println!("{}", zabbix_data);
ctx.hotreload();
}
}
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 mut max = 0; 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(zabbix_data) => zabbix_data, Ok(zabbix_data) => zabbix_data,
Err(_) => { Err(_) => {
println!( println!(
"Error requesting zabbix service, retrying in {}", "Error requesting zabbix service, retrying in {}",
REQUEST_TIMEOUT REQUEST_WAITFOR
); );
sleep(Duration::from_secs(REQUEST_TIMEOUT as u64)); sleep(Duration::from_secs(REQUEST_WAITFOR 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,
}; };
canvas[p] = 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),
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,
}; };
if ctx.cfg.sloweffect.unwrap() { canvas[p] = c;
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) {
loop { 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:?}", msg = msg.pad())
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);
});
} }
clear(canvas); let _res = canvas.flush();
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..MATRIX_WIDTH { for a in 0..8 {
for b in 0..MATRIX_WIDTH + 1 { for b in 0..9 {
canvas[Pad { x: a, y: b }] = Color { canvas[Pad { x: a, y: b }] = Color {
r: ZERO_COLOR, r: 0f32,
g: ZERO_COLOR, g: 0f32,
b: ONE_COLOR, b: 1f32,
}; };
} }
} }
canvas.flush().unwrap(); let _res = canvas.flush();
} }
/*
let (send, recv): (Sender<Context>, Receiver<Context>) = channel();
match ctx.mode.as_str() {
/*"draw" => {
let (mut canvas, mut _poller) = initpad();
draw(&mut canvas, c);
}
"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" => loop {
let mut data = cm.lock().unwrap();
let future1 = test(&mut data);
let mut data = cm.lock().unwrap();
let future2 = data.hotreload();
//futures::join!(future1, future2);
},
_ => {
println!("No valid option choosen for mode");
std::process::exit(1)
}
}*/

View File

@ -1,64 +1,54 @@
use crate::config::Config; use crate::config::Config;
use serde_json::json; use serde_json::json;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
//use std::thread::sleep; use std::thread::sleep;
//use std::time::Duration; 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;
/// Refresh the user token /// Refresh the user token
pub fn get_zabbix_authtoken(cfg: &mut Config) { pub async fn get_zabbix_authtoken(cfg: &mut Config) -> Result<(), reqwest::Error> {
let body = build_query_auth_token(&cfg.username, &cfg.password); let body = build_query_auth_token(&cfg.username, &cfg.password);
let resp = reqwest::blocking::Client::new() let resp = reqwest::Client::new()
.post(&cfg.server) .post(&cfg.server)
.json(&body) .json(&body)
.send(); .send()
match resp { .await?;
Ok(v) => { let values: JsonValue = resp.json().await?;
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()); Ok(())
}
Err(e) => {
println!("{}", e);
cfg.authtoken = Some("".to_string());
}
};
} }
/// Fetch Zabbix problems /// Fetch Zabbix problems
pub fn get_zabbix_problems(cfg: &Config) -> Result<JsonValue, reqwest::Error> { pub async 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::Client::new()
.post(&cfg.server) .post(&cfg.server)
.json(&body) .json(&body)
.send(); .send()
.await?;
match resp { Ok(resp.json().await?)
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 { async fn _async_check_zabbix_connection(cfg: &Config) -> Result<bool, reqwest::Error> {
let mut res: bool = false; let mut res: bool = false;
let delay = 5; let delay = 5;
let timeout = 10; let timeout = 10;
while !res { while !res {
let req = reqwest::blocking::Client::builder().timeout(Duration::from_secs(timeout)).build().unwrap(); let req = reqwest::Client::builder()
let resp = req.get(&cfg.server) .timeout(Duration::from_secs(timeout))
.send(); .build()
match resp { .unwrap();
Ok(_) => res = true, req.get(&cfg.server).send().await?;
Err(_) => res = false res = true;
} println!("Waiting for {delay}", delay = delay);
println!("Waiting for {delay}", delay=delay);
sleep(Duration::from_secs(delay)); sleep(Duration::from_secs(delay));
} }
res Ok(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) -> JsonValue { fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) -> JsonValue {
@ -67,7 +57,7 @@ fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) ->
"jsonrpc": ZABBIX_API_VERSION, "jsonrpc": ZABBIX_API_VERSION,
"method": zabbix_api_function, "method": zabbix_api_function,
"params": { "params": {
"username": zabbix_username, "user": zabbix_username,
"password": zabbix_password "password": zabbix_password
}, },
"id": ZABBIX_API_ID "id": ZABBIX_API_ID
@ -75,7 +65,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) -> JsonValue { 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,
@ -95,7 +85,7 @@ fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) ->
"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) -> JsonValue { fn build_query_triggers(zabbix_token: &String) -> JsonValue {

View File

@ -1,14 +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, _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 {
@ -26,10 +26,6 @@ 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 });
}*/
} }
} }