diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..7ef3875 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,101 @@ +--- +kind: pipeline +type: docker +name: cleanup-before + +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 + 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 + settings: + base_url: https://git.paulbsd.com + api_key: + from_secret: gitea_token + files: "*.tar.gz" + checksum: + - sha256 + - sha512 + title: VERSION + volumes: + - name: build + path: /drone/src/build + 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 diff --git a/Cargo.lock b/Cargo.lock index bdaabb1..c5becba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,6 +248,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.17" @@ -255,6 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -263,12 +279,36 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +[[package]] +name = "futures-executor" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +[[package]] +name = "futures-macro" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.17" @@ -288,12 +328,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", + "futures-channel", "futures-core", "futures-io", + "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", + "proc-macro-hack", + "proc-macro-nested", "slab", ] @@ -434,6 +479,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "ipnet" version = "2.3.1" @@ -475,6 +529,15 @@ version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -627,9 +690,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -674,6 +737,31 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -704,6 +792,18 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + [[package]] name = "proc-macro2" version = "1.0.29" @@ -831,6 +931,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "security-framework" version = "2.3.1" @@ -897,12 +1003,27 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + [[package]] name = "socket2" version = "0.4.1" @@ -991,10 +1112,25 @@ dependencies = [ "memchr", "mio", "num_cpus", + "once_cell", + "parking_lot", "pin-project-lite", + "signal-hook-registry", + "tokio-macros", "winapi", ] +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-native-tls" version = "0.3.0" @@ -1243,9 +1379,11 @@ version = "1.0.0" dependencies = [ "clap", "embedded-graphics", + "futures", "launchy", "nix 0.23.0", "reqwest", "serde", "serde_json", + "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index a388730..cf2e1b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,12 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "2.33.3", features = ["yaml"] } -embedded-graphics = { version = "0.7.1", optional = true } +clap = { version = "2", features = ["yaml"] } +embedded-graphics = { version = "0.7", optional = true } +futures = "*" launchy = { git = "https://github.com/kangalioo/launchy", branch = "master" } -reqwest = { version = "0.11.5", features = ["blocking", "json"] } -serde = { version = "1.0.130", features = ["derive"] } -serde_json = "1.0.68" -nix = "0.23.0" \ No newline at end of file +nix = "0.23" +reqwest = { version = "0.11", features = ["json"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tokio = { version = "1", features = ["full"] } diff --git a/src/config/mod.rs b/src/config/mod.rs index 8817870..96df9ac 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,7 +1,7 @@ use crate::zabbix::api::get_zabbix_authtoken; use crate::zabbix::problems::DataMatrix; use clap::App; -use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; +use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify, InotifyEvent}; use serde::{Deserialize, Serialize}; use serde_json::Error as JsonError; use serde_json::Value as JsonValue; @@ -28,7 +28,7 @@ pub struct Context { } impl Context { - pub fn new() -> Self { + pub async fn new() -> Self { let yaml = load_yaml!("cli.yml"); let cli = App::from_yaml(yaml).get_matches(); @@ -43,7 +43,7 @@ impl Context { }; println!("Loading {configfile} file ...", configfile = ctx.configfile); - ctx.cfg.load(&ctx.configfile); + ctx.cfg.load(&ctx.configfile).await; println!( "Adding inotify watch on {configfile} file ...", @@ -52,30 +52,21 @@ impl Context { ctx.inotify .add_watch(ctx.configfile.as_str(), AddWatchFlags::IN_MODIFY) .unwrap(); - get_zabbix_authtoken(&mut ctx.cfg); + let tokenrefresh = get_zabbix_authtoken(&mut ctx.cfg); + tokenrefresh.await; ctx } - 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 { - self.cfg.load(self.configfile.as_str()); - println!( - "Reloading {cfg}", - cfg = self.configfile - ); - break; - } else { - sleep(Duration::from_millis(waitinc)); - } - i += waitinc; + + pub async fn hotreload(&mut self) { + 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()); } } } @@ -104,7 +95,7 @@ impl<'a> Config { } } - pub fn load(&'a mut self, configfile: &str) { + async fn load(&'a mut self, configfile: &str) { let fileopen: Result; let filemeta = std::fs::metadata(configfile); let fileexists = match filemeta { @@ -130,6 +121,7 @@ impl<'a> Config { Ok(cfg) => { let tmpcfg = Config::new(); Config { +<<<<<<< Updated upstream server: cfg["server"].as_str().unwrap_or(tmpcfg.server.as_str()).to_string(), username: cfg["username"].as_str().unwrap_or(tmpcfg.username.as_str()).to_string(), password: cfg["password"].as_str().unwrap_or(tmpcfg.password.as_str()).to_string(), @@ -137,17 +129,51 @@ impl<'a> Config { sloweffect: Some(cfg["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())), +======= + server: ncfg["server"] + .as_str() + .unwrap_or(&tmpcfg.server.clone()) + .to_string(), + username: ncfg["username"] + .as_str() + .unwrap_or(&tmpcfg.username.clone()) + .to_string(), + password: ncfg["password"] + .as_str() + .unwrap_or(&tmpcfg.password.clone()) + .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())), +>>>>>>> Stashed changes } - }, + } Err(err) => { println!("error occured: '{}'", err); Config::new() } }; +<<<<<<< Updated upstream self.save(&configfile); +======= + *self = newcfg; + if !fileexists || errorreading { + self.save(&configfile).await; + } +>>>>>>> Stashed changes } - pub fn save(&self, configfile: &str) { + async fn save(&self, configfile: &str) { let file = File::create(configfile).unwrap(); serde_json::to_writer_pretty(file, &self).unwrap(); } diff --git a/src/main.rs b/src/main.rs index bb1bdfc..f69992f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,9 +5,7 @@ mod zabbix; #[macro_use] extern crate clap; -use config::Context; - -fn main() { - let mut context = Context::new(); - padcontrol::run(&mut context); +#[tokio::main] +async fn main() { + padcontrol::run().await; } diff --git a/src/padcontrol/mod.rs b/src/padcontrol/mod.rs index 4be2542..22fe54b 100644 --- a/src/padcontrol/mod.rs +++ b/src/padcontrol/mod.rs @@ -1,19 +1,32 @@ use crate::config::Context; -use crate::zabbix::api::get_zabbix_problems; +use crate::zabbix::api::*; use launchy::Color; use launchy::{self, Canvas, CanvasLayout, CanvasLayoutPoller, MsgPollingWrapper, Pad}; +//use std::process::exit; +//use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread::sleep; use std::time::Duration; -pub const MATRIX_WIDTH: i32 = 8; -pub const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH; -pub const REQUEST_TIMEOUT: i32 = 10; +const MATRIX_WIDTH: i32 = 8; +const MATRIX_SIZE: i32 = MATRIX_WIDTH * MATRIX_WIDTH; +const REQUEST_WAITFOR: i32 = 5; +const ZERO_COLOR: f32 = 0.; +const ONE_COLOR: f32 = 1.; -pub fn run(ctx: &mut Context) { +pub async fn run() { + println!("test1 🦀"); + let mut ctx = Context::new().await; + println!("test2 🦀"); + loop { + ctx.hotreload().await; + test(&mut ctx).await; + } + /* + let (send, recv): (Sender, Receiver) = channel(); match ctx.mode.as_str() { - "draw" => { + /*"draw" => { let (mut canvas, mut _poller) = initpad(); - draw(&mut canvas, ctx); + draw(&mut canvas, c); } "input" => { let (mut canvas, mut poller) = initpad(); @@ -21,14 +34,20 @@ pub fn run(ctx: &mut Context) { } "effect" => { let (mut canvas, mut poller) = initpad(); - effect(&mut canvas, &mut poller) - } - "test" => test(ctx), + 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) } - } + }*/ } fn initpad() -> (CanvasLayout<'static>, CanvasLayoutPoller) { @@ -57,35 +76,26 @@ fn input(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(_) => { - println!("Error requesting zabbix service, retrying in {}", REQUEST_TIMEOUT); - sleep(Duration::from_secs(REQUEST_TIMEOUT as u64)); - continue; - } - }; - println!("{}", zabbix_data); - ctx.hotreload(); - } +async fn test(ctx: &mut Context) { + let sec = ctx.cfg.refresh.unwrap(); + let zabbix_data = get_zabbix_problems(&ctx.cfg).await.unwrap(); + println!("{}", zabbix_data); + sleep(Duration::from_secs(sec)); } -pub fn draw(canvas: &mut CanvasLayout, ctx: &mut Context) { +/* +async 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 { Ok(zabbix_data) => zabbix_data, Err(_) => { - println!("Error requesting zabbix service, retrying in {}", REQUEST_TIMEOUT); - sleep(Duration::from_secs(REQUEST_TIMEOUT as u64)); + println!( + "Error requesting zabbix service, retrying in {}", + REQUEST_WAITFOR + ); + sleep(Duration::from_secs(REQUEST_WAITFOR as u64)); continue; } }; @@ -116,7 +126,7 @@ pub fn draw(canvas: &mut CanvasLayout, ctx: &mut Context) { } 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)) { diff --git a/src/zabbix/api.rs b/src/zabbix/api.rs index 23eea28..1c0ee8a 100644 --- a/src/zabbix/api.rs +++ b/src/zabbix/api.rs @@ -1,53 +1,53 @@ -use std::time::Duration; -use std::thread::sleep; 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_ID: i32 = 1; /// 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 resp = reqwest::blocking::Client::new() + let resp = reqwest::Client::new() .post(&cfg.server) .json(&body) .send() - .unwrap(); - - let values: Value = resp.json().unwrap(); + .await?; + let values: JsonValue = resp.json().await?; cfg.authtoken = Some(values["result"].as_str().unwrap().to_string()); + Ok(()) } /// Fetch Zabbix problems -pub fn get_zabbix_problems(cfg: &Config) -> Result { +pub async fn get_zabbix_problems(cfg: &Config) -> Result { 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) .json(&body) - .send(); - - Ok(resp.unwrap().json().unwrap()) + .send() + .await?; + Ok(resp.json().await?) } /// Check if Zabbix is operational /// Undefinitely check that Zabbix works -fn check_zabbix_connection(cfg: &Config) -> bool { +async fn _async_check_zabbix_connection(cfg: &Config) -> Result { let mut res: bool = false; let delay = 5; let timeout = 10; while !res { - 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); + 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); sleep(Duration::from_secs(delay)); } - res + Ok(res) } /// Build the query that fetchs the token @@ -65,7 +65,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) -> Value { +fn _build_query_problems(zabbix_token: &String, zabbix_limit: i64) -> JsonValue { let zabbix_api_function = "problem.get"; json!({ "jsonrpc": ZABBIX_API_VERSION, diff --git a/src/zabbix/problems.rs b/src/zabbix/problems.rs index 19c079a..503f4ff 100644 --- a/src/zabbix/problems.rs +++ b/src/zabbix/problems.rs @@ -2,11 +2,12 @@ use serde_json::Value; use std::fmt::{Display, Formatter, Result}; #[derive(Debug, Clone)] -pub enum ZabbixStatus { - High = 4, - Average = 3, - Warning = 2, - Info = 1, +pub enum _ZabbixStatus { + _Disaster = 5, + _High = 4, + _Average = 3, + _Warning = 2, + _Info = 1, } #[derive(Debug, Clone)]