Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
f2bb375972 | |||
872e17f6f2 | |||
e30efa1d9a | |||
9f07930013 | |||
b73fc7a7c2 | |||
ef60d4bda9 | |||
c128a7dce5 | |||
50a2da488d | |||
|
f6e801dc58 | ||
|
f3a1d5c900 | ||
|
ca349dc187 | ||
|
ccf9fd587d | ||
|
ec23da0565 | ||
bf03adb549 | |||
|
f18f25727d | ||
|
e364dc7540 | ||
|
463795385d | ||
|
95322749fe | ||
e9973e109f | |||
e7850c8d72 | |||
|
59e1057ca7 | ||
811f1155a9 | |||
|
2f1be523f8 | ||
|
9fefb6e8a0 | ||
|
55dc677b46 | ||
|
72d12319c1 | ||
|
0dc914beb5 | ||
|
05b38b3540 | ||
|
b7a9def20d |
98
.drone.yml
98
.drone.yml
@ -1,101 +1,37 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: cleanup-before
|
||||
name: default
|
||||
|
||||
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
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default-linux-amd64
|
||||
|
||||
steps:
|
||||
- name: Build
|
||||
image: rust:latest
|
||||
- name: test
|
||||
image: rust:1
|
||||
commands:
|
||||
- apt-get update -y
|
||||
- apt-get install libasound2-dev -y
|
||||
- cargo build --verbose --all
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: gitea-release
|
||||
|
||||
steps:
|
||||
- name: move
|
||||
image: alpine
|
||||
- cargo test --verbose --all
|
||||
- name: release
|
||||
image: rust:1
|
||||
commands:
|
||||
- mv target/release/* ./
|
||||
volumes:
|
||||
- name: build
|
||||
path: /drone/src/build
|
||||
- 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: release
|
||||
- name: publish
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
base_url: https://git.paulbsd.com
|
||||
api_key:
|
||||
from_secret: gitea_token
|
||||
files: "*.tar.gz"
|
||||
files: "target/release/*.tar.gz"
|
||||
checksum:
|
||||
- sha256
|
||||
- sha512
|
||||
title: VERSION
|
||||
volumes:
|
||||
- name: build
|
||||
path: /drone/src/build
|
||||
environment:
|
||||
PLUGIN_TITLE: ""
|
||||
when:
|
||||
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
|
||||
|
1138
Cargo.lock
generated
1138
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
19
Cargo.toml
19
Cargo.toml
@ -1,17 +1,18 @@
|
||||
[package]
|
||||
name = "zabbixlaunch"
|
||||
version = "1.0.0"
|
||||
edition = "2018"
|
||||
version = "1.0.1"
|
||||
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
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "2", features = ["yaml"] }
|
||||
embedded-graphics = { version = "0.7", optional = true }
|
||||
futures = "*"
|
||||
launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" }
|
||||
nix = "0.23"
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
clap = "4.3"
|
||||
embedded-graphics = { version = "0.8", optional = true }
|
||||
launchy = { git = "https://github.com/paulbsd/launchy", branch = "develop-launchpad-mini-mk3" }
|
||||
nix = "0.26"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
@ -1,5 +1,7 @@
|
||||
# zabbixlaunch
|
||||
|
||||
[![Build Status](https://drone.paulbsd.com/api/badges/paulbsd/zabbixlaunch/status.svg)](https://drone.paulbsd.com/paulbsd/zabbixlaunch)
|
||||
|
||||
## Summary
|
||||
|
||||
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",
|
||||
"username": "bob",
|
||||
"password": "password",
|
||||
"authtoken": "token",
|
||||
"limit": 20
|
||||
"sloweffect": true,
|
||||
"refresh": 2,
|
||||
"limit": 100
|
||||
}
|
||||
```
|
||||
|
||||
@ -48,7 +51,7 @@ cargo build --release
|
||||
## License
|
||||
|
||||
```text
|
||||
Copyright (c) 2021 PaulBSD
|
||||
Copyright (c) 2021, 2022 PaulBSD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
8
config.json.sample
Normal file
8
config.json.sample
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"server": "https://zabbix.acme.com/api_jsonrpc.php",
|
||||
"username": "bob",
|
||||
"password": "password",
|
||||
"sloweffect": true,
|
||||
"refresh": 2,
|
||||
"limit": 100
|
||||
}
|
@ -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
|
@ -1,6 +1,6 @@
|
||||
use crate::zabbix::api::get_zabbix_authtoken;
|
||||
use crate::zabbix::problems::DataMatrix;
|
||||
use clap::App;
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Error as JsonError;
|
||||
@ -8,42 +8,60 @@ 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;
|
||||
use tokio::time::sleep;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ReloadFrequency {
|
||||
High = 50,
|
||||
Medium = 20,
|
||||
Low = 10,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Mode {
|
||||
Draw,
|
||||
Test,
|
||||
Input,
|
||||
Effect,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Context {
|
||||
pub cfg: Config,
|
||||
pub configfile: String,
|
||||
pub inotify: Inotify,
|
||||
configfile: String,
|
||||
inotify: Inotify,
|
||||
pub datamatrix: DataMatrix,
|
||||
pub mode: String,
|
||||
pub mode: Option<Mode>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub async fn new() -> Self {
|
||||
let yaml = load_yaml!("cli.yml");
|
||||
let cli = App::from_yaml(yaml).get_matches();
|
||||
pub fn new() -> Self {
|
||||
let argp: ArgMatches = Context::argparse();
|
||||
|
||||
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 {
|
||||
cfg: Config::new(),
|
||||
configfile: configfile,
|
||||
inotify: Inotify::init(InitFlags::IN_NONBLOCK).unwrap(),
|
||||
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);
|
||||
ctx.cfg.load(&ctx.configfile.to_string()).await;
|
||||
ctx.cfg.load(&ctx.configfile);
|
||||
|
||||
println!(
|
||||
"Adding inotify watch on {configfile} file ...",
|
||||
@ -52,38 +70,57 @@ impl Context {
|
||||
ctx.inotify
|
||||
.add_watch(ctx.configfile.as_str(), AddWatchFlags::IN_MODIFY)
|
||||
.unwrap();
|
||||
get_zabbix_authtoken(&mut ctx.cfg).await;
|
||||
get_zabbix_authtoken(&mut ctx.cfg);
|
||||
|
||||
ctx
|
||||
}
|
||||
|
||||
/*pub async fn hotreload(&mut self) {
|
||||
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);
|
||||
get_zabbix_authtoken(&mut self.cfg).await;
|
||||
self.cfg.load(self.configfile.as_str());
|
||||
get_zabbix_authtoken(&mut self.cfg);
|
||||
break;
|
||||
} else {
|
||||
sleep(Duration::from_millis(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);
|
||||
i += waitinc;
|
||||
}
|
||||
println!("Sending {:?}", ctx);
|
||||
ctxsender.send(ctx.to_owned()).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,8 +149,21 @@ impl<'a> Config {
|
||||
}
|
||||
}
|
||||
|
||||
async fn load(&mut self, configfile: &String) {
|
||||
let mut file = match File::open(configfile) {
|
||||
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);
|
||||
@ -122,56 +172,51 @@ impl<'a> Config {
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let parse: Result<JsonValue, JsonError> = serde_json::from_str(contents.as_str());
|
||||
*self = match parse {
|
||||
Ok(cfg) => {
|
||||
let ncfg = match parse {
|
||||
Ok(ncfg) => {
|
||||
let tmpcfg = Config::new();
|
||||
Config {
|
||||
server: cfg["server"]
|
||||
server: ncfg["server"]
|
||||
.as_str()
|
||||
.unwrap_or(tmpcfg.server.as_str())
|
||||
.to_string(),
|
||||
username: cfg["username"]
|
||||
username: ncfg["username"]
|
||||
.as_str()
|
||||
.unwrap_or(tmpcfg.username.as_str())
|
||||
.to_string(),
|
||||
password: cfg["password"]
|
||||
password: ncfg["password"]
|
||||
.as_str()
|
||||
.unwrap_or(tmpcfg.password.as_str())
|
||||
.to_string(),
|
||||
authtoken: Some(
|
||||
self.authtoken
|
||||
.clone()
|
||||
.unwrap_or(tmpcfg.authtoken.unwrap().to_string())
|
||||
ncfg["authtoken"]
|
||||
.as_str()
|
||||
.unwrap_or(self.authtoken.clone().unwrap().as_str())
|
||||
.to_string(),
|
||||
),
|
||||
sloweffect: Some(
|
||||
cfg["sloweffect"]
|
||||
ncfg["sloweffect"]
|
||||
.as_bool()
|
||||
.unwrap_or(tmpcfg.sloweffect.unwrap()),
|
||||
),
|
||||
refresh: Some(cfg["refresh"].as_u64().unwrap_or(tmpcfg.refresh.unwrap())),
|
||||
limit: Some(cfg["limit"].as_u64().unwrap_or(tmpcfg.limit.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.save(&configfile).await;
|
||||
*self = ncfg;
|
||||
if !fileexists || error_reading {
|
||||
self.save(&configfile);
|
||||
}
|
||||
}
|
||||
|
||||
async fn save(&self, configfile: &String) {
|
||||
let file: File;
|
||||
let filemeta = std::fs::metadata(configfile);
|
||||
let fileexists = match filemeta {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
};
|
||||
if !fileexists {
|
||||
file = File::create(configfile).unwrap();
|
||||
fn save(&self, configfile: &str) {
|
||||
let file = File::create(configfile).unwrap();
|
||||
serde_json::to_writer_pretty(file, &self).unwrap();
|
||||
sleep(Duration::from_millis(1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
src/main.rs
11
src/main.rs
@ -1,11 +1,10 @@
|
||||
pub mod config;
|
||||
mod config;
|
||||
mod padcontrol;
|
||||
mod zabbix;
|
||||
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
use config::Context;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
padcontrol::run().await;
|
||||
fn main() {
|
||||
let mut context = Context::new();
|
||||
padcontrol::run(&mut context);
|
||||
}
|
||||
|
@ -1,126 +1,137 @@
|
||||
use crate::config::{hotreload, Context};
|
||||
use crate::zabbix::api::*;
|
||||
use crate::config::{Context, Mode};
|
||||
use crate::zabbix::api::get_zabbix_problems;
|
||||
use launchy::Color;
|
||||
use launchy::{self, Canvas, CanvasLayout, CanvasLayoutPoller, MsgPollingWrapper, Pad};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::sleep;
|
||||
|
||||
const MATRIX_WIDTH: i32 = 8;
|
||||
const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH;
|
||||
const REQUEST_WAITFOR: i32 = 5;
|
||||
const REQUEST_TIMEOUT: i32 = 5;
|
||||
const ZERO_COLOR: f32 = 0.;
|
||||
const ONE_COLOR: f32 = 1.;
|
||||
const SLOWEFFECT_FACTOR: f32 = 800.0;
|
||||
|
||||
const POLLER_ITER: u64 = 17;
|
||||
|
||||
fn log(num: i64) {
|
||||
return println!("test{} 🦀", num);
|
||||
}
|
||||
|
||||
pub async fn run<'a>() {
|
||||
log(1);
|
||||
let mut ctx = Box::new(Context::new().await);
|
||||
log(2);
|
||||
let (tx1, mut rx1) = mpsc::channel(1);
|
||||
log(3);
|
||||
let t1 = tokio::task::spawn(async move { test(&mut rx1).await });
|
||||
let t2 = tokio::task::spawn(async move { hotreload(&mut ctx, &tx1).await });
|
||||
tokio::join!(t1, t2);
|
||||
log(4);
|
||||
}
|
||||
|
||||
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;
|
||||
pub fn run(ctx: &mut Context) {
|
||||
match ctx.mode {
|
||||
Some(Mode::Draw) => {
|
||||
let (mut canvas, mut _poller) = initpad();
|
||||
draw(&mut canvas, ctx);
|
||||
}
|
||||
Some(Mode::Input) => {
|
||||
let (mut canvas, mut poller) = initpad();
|
||||
input(&mut canvas, &mut poller);
|
||||
}
|
||||
Some(Mode::Effect) => {
|
||||
let (mut canvas, mut poller) = initpad();
|
||||
effect(&mut canvas, &mut poller)
|
||||
}
|
||||
Some(Mode::Test) => test(ctx),
|
||||
None => {
|
||||
println!("No valid option choosen for mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) {
|
||||
let (mut canvas, poller) = launchy::CanvasLayout::new_polling();
|
||||
match canvas.add_by_guess_rotated::<launchy::mini::Canvas>(0, 0, launchy::Rotation::None) {
|
||||
Ok(o) => o,
|
||||
Err(err) => {
|
||||
eprintln!(
|
||||
"Failed to connect to device, check USB connection {err}",
|
||||
err = err
|
||||
);
|
||||
}
|
||||
};
|
||||
Ok(_) => {
|
||||
println!("Connected to device using USB");
|
||||
clear(&mut canvas);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Failed to connect to device, check USB connection {err}",);
|
||||
}
|
||||
};
|
||||
(canvas, poller)
|
||||
}
|
||||
|
||||
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 msg in poller
|
||||
.iter_for_millis(POLLER_ITER)
|
||||
.filter(|msg| msg.is_press())
|
||||
{
|
||||
for msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
|
||||
canvas[msg.pad()] = color;
|
||||
println!("{msg:?}", msg = msg.pad())
|
||||
}
|
||||
let _res = canvas.flush();
|
||||
canvas.flush().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
async fn draw(canvas: &mut CanvasLayout<'_>, ctx: &mut Context) {
|
||||
fn test(ctx: &mut Context) {
|
||||
println!(
|
||||
"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());
|
||||
loop {
|
||||
let zabbix_data_result = get_zabbix_problems(&ctx.cfg);
|
||||
let zabbix_data = match zabbix_data_result {
|
||||
let mut max = 0;
|
||||
let zabbix_data = match get_zabbix_problems(&ctx.cfg) {
|
||||
Ok(zabbix_data) => zabbix_data,
|
||||
Err(_) => {
|
||||
println!(
|
||||
"Error requesting zabbix service, retrying in {}",
|
||||
REQUEST_WAITFOR
|
||||
REQUEST_TIMEOUT
|
||||
);
|
||||
sleep(Duration::from_secs(REQUEST_WAITFOR as u64));
|
||||
sleep(Duration::from_secs(REQUEST_TIMEOUT as u64));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
ctx.datamatrix.compute(&zabbix_data);
|
||||
clear(canvas);
|
||||
let mut max = 0;
|
||||
|
||||
for (i, j) in ctx.datamatrix.layout.iter().enumerate() {
|
||||
let p = Pad {
|
||||
x: ((i as i32) % MATRIX_WIDTH),
|
||||
y: ((i as i32) / MATRIX_WIDTH) + 1,
|
||||
};
|
||||
let c = match j.status {
|
||||
canvas[p] = match j.status {
|
||||
5 => Color::RED,
|
||||
4 => Color::from_hue(0.05),
|
||||
3 => Color::from_hue(0.1),
|
||||
2 => Color::from_hue(1.22),
|
||||
_ => 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;
|
||||
if max >= MATRIX_SIZE {
|
||||
break;
|
||||
}
|
||||
if ctx.cfg.sloweffect.unwrap() {
|
||||
sleep(Duration::from_millis(15));
|
||||
}
|
||||
canvas.flush().unwrap();
|
||||
}
|
||||
ctx.hotreload();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
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 msg in poller.iter_for_millis(17).filter(|msg| msg.is_press()) {
|
||||
canvas[msg.pad()] = color;
|
||||
println!("{msg:?}", msg = msg.pad())
|
||||
}
|
||||
let _res = canvas.flush();
|
||||
canvas.flush().unwrap();
|
||||
|
||||
canvas.iter().for_each(|pad| {
|
||||
let surrounding_color = pad
|
||||
@ -134,44 +145,19 @@ fn effect(canvas: &mut CanvasLayout, poller: &mut CanvasLayoutPoller) {
|
||||
canvas[pad] = canvas[pad].mix(surrounding_color, 0.4);
|
||||
});
|
||||
}
|
||||
clear(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
fn clear(canvas: &mut CanvasLayout) {
|
||||
for a in 0..8 {
|
||||
for b in 0..9 {
|
||||
for a in 0..MATRIX_WIDTH {
|
||||
for b in 0..MATRIX_WIDTH + 1 {
|
||||
canvas[Pad { x: a, y: b }] = Color {
|
||||
r: 0f32,
|
||||
g: 0f32,
|
||||
b: 1f32,
|
||||
r: ZERO_COLOR,
|
||||
g: ZERO_COLOR,
|
||||
b: ONE_COLOR,
|
||||
};
|
||||
}
|
||||
}
|
||||
let _res = canvas.flush();
|
||||
canvas.flush().unwrap();
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
}
|
||||
}*/
|
||||
|
@ -1,54 +1,64 @@
|
||||
use crate::config::Config;
|
||||
use serde_json::json;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
//use std::thread::sleep;
|
||||
//use std::time::Duration;
|
||||
|
||||
pub const ZABBIX_API_VERSION: &'static str = "2.0";
|
||||
pub const ZABBIX_API_ID: i32 = 1;
|
||||
|
||||
/// Refresh the user token
|
||||
pub async fn get_zabbix_authtoken(cfg: &mut Config) -> Result<(), reqwest::Error> {
|
||||
pub fn get_zabbix_authtoken(cfg: &mut Config) {
|
||||
let body = build_query_auth_token(&cfg.username, &cfg.password);
|
||||
let resp = reqwest::Client::new()
|
||||
let resp = reqwest::blocking::Client::new()
|
||||
.post(&cfg.server)
|
||||
.json(&body)
|
||||
.send()
|
||||
.await?;
|
||||
let values: JsonValue = resp.json().await?;
|
||||
.send();
|
||||
match resp {
|
||||
Ok(v) => {
|
||||
let values: JsonValue = v.json().unwrap();
|
||||
cfg.authtoken = Some(values["result"].as_str().unwrap().to_string());
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
cfg.authtoken = Some("".to_string());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Fetch Zabbix problems
|
||||
pub async fn get_zabbix_problems(cfg: &Config) -> Result<JsonValue, 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 resp = reqwest::Client::new()
|
||||
let resp = reqwest::blocking::Client::new()
|
||||
.post(&cfg.server)
|
||||
.json(&body)
|
||||
.send()
|
||||
.await?;
|
||||
Ok(resp.json().await?)
|
||||
.send();
|
||||
|
||||
match resp {
|
||||
Ok(v) => v.json(),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if Zabbix is operational
|
||||
/// Undefinitely check that Zabbix works
|
||||
async fn _async_check_zabbix_connection(cfg: &Config) -> Result<bool, reqwest::Error> {
|
||||
/*fn check_zabbix_connection(cfg: &Config) -> bool {
|
||||
let mut res: bool = false;
|
||||
let delay = 5;
|
||||
let timeout = 10;
|
||||
while !res {
|
||||
let req = reqwest::Client::builder()
|
||||
.timeout(Duration::from_secs(timeout))
|
||||
.build()
|
||||
.unwrap();
|
||||
req.get(&cfg.server).send().await?;
|
||||
res = true;
|
||||
println!("Waiting for {delay}", delay = delay);
|
||||
let req = reqwest::blocking::Client::builder().timeout(Duration::from_secs(timeout)).build().unwrap();
|
||||
let resp = req.get(&cfg.server)
|
||||
.send();
|
||||
match resp {
|
||||
Ok(_) => res = true,
|
||||
Err(_) => res = false
|
||||
}
|
||||
println!("Waiting for {delay}", delay=delay);
|
||||
sleep(Duration::from_secs(delay));
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
res
|
||||
}*/
|
||||
|
||||
/// Build the query that fetchs the token
|
||||
fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) -> JsonValue {
|
||||
@ -57,7 +67,7 @@ fn build_query_auth_token(zabbix_username: &String, zabbix_password: &String) ->
|
||||
"jsonrpc": ZABBIX_API_VERSION,
|
||||
"method": zabbix_api_function,
|
||||
"params": {
|
||||
"user": zabbix_username,
|
||||
"username": zabbix_username,
|
||||
"password": zabbix_password
|
||||
},
|
||||
"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
|
||||
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";
|
||||
json!({
|
||||
"jsonrpc": ZABBIX_API_VERSION,
|
||||
@ -85,7 +95,7 @@ fn _build_query_problems(zabbix_token: &String, zabbix_limit: i64) -> JsonValue
|
||||
"auth": zabbix_token,
|
||||
"id": ZABBIX_API_ID
|
||||
})
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Build the query that fetchs triggers
|
||||
fn build_query_triggers(zabbix_token: &String) -> JsonValue {
|
||||
|
@ -1,14 +1,14 @@
|
||||
use serde_json::Value;
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum _ZabbixStatus {
|
||||
_Disaster = 5,
|
||||
_High = 4,
|
||||
_Average = 3,
|
||||
_Warning = 2,
|
||||
_Info = 1,
|
||||
}
|
||||
/*#[derive(Debug, Clone)]
|
||||
pub enum ZabbixStatus {
|
||||
Disaster = 5,
|
||||
High = 4,
|
||||
Average = 3,
|
||||
Warning = 2,
|
||||
Info = 1,
|
||||
}*/
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DataMatrix {
|
||||
@ -26,6 +26,10 @@ impl DataMatrix {
|
||||
let severity = res["priority"].as_str().unwrap().parse::<i64>().unwrap();
|
||||
self.layout.push(ZabbixProblems { status: severity });
|
||||
}
|
||||
// test
|
||||
/*for i in 0..1000 {
|
||||
self.layout.push(ZabbixProblems { status: 5 });
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user