diff --git a/example/config.toml b/example/config.toml index cbf20bd..78ad414 100644 --- a/example/config.toml +++ b/example/config.toml @@ -9,6 +9,18 @@ sleep = 1 # * unset or comment to run once # update = 60 +# Run specified commands or scripts before and after each queue iteration +# * `exec` is required +# * `stdout_contains` is optional +# * will panic if `stdout_contains` is defined and does not match expected stdout +# [before] + # exec = "" + # stdout_contains = [""] + +# [after] + # exec = "" + # stdout_contains = [""] + # Channels queue config [channel.test] diff --git a/src/config.rs b/src/config.rs index 654cf57..a5c3620 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,6 +4,12 @@ use channel::Channel; use serde::Deserialize; use std::{collections::HashMap, path::PathBuf}; +#[derive(Deserialize)] +pub struct Command { + pub exec: String, + pub stdout_contains: Option>, +} + #[derive(Deserialize)] pub struct Config { pub channel: HashMap, @@ -15,4 +21,10 @@ pub struct Config { /// Iterator delay in seconds (prevents server abuse) /// * None to run asap pub sleep: Option, + /// Run specified commands or scripts before each queue iteration + /// * will panic if `stdout_contains` is defined and does not match expected stdout + pub before: Option, + /// Run specified commands or scripts after each queue iteration + /// * will panic if `stdout_contains` is defined and does not match expected stdout + pub after: Option, } diff --git a/src/config/channel/item.rs b/src/config/channel/item.rs index 617e4cc..09ee25e 100644 --- a/src/config/channel/item.rs +++ b/src/config/channel/item.rs @@ -1,6 +1,6 @@ use serde::Deserialize; -#[derive(Deserialize, PartialEq, Eq, Hash)] +#[derive(Deserialize)] pub struct Item { pub exec: String, pub stdout_contains: Option>, diff --git a/src/main.rs b/src/main.rs index 60108ae..2902da1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,10 @@ async fn main() { let rp = RustyPipe::new(); loop { + if let Some(ref before) = config.before { + debug!("exec {} before starting queue...", before.exec); + cmd(before) + } info!("begin {} channels update...", config.channel.len()); for (c, channel) in &config.channel { debug!("get `{c}` ({})...", channel.id); @@ -132,7 +136,7 @@ async fn main() { } } else { warn!( - "unexpected exec `{cmd}` for channel `{c}`: `{:?}`", + "unexpected exec result `{cmd}` for channel `{c}`: `{:?}`", response ) } @@ -157,6 +161,10 @@ async fn main() { Err(e) => warn!("can't scrape channel `{c}`: `{e}`"), } } + if let Some(ref after) = config.after { + debug!("exec {} after queue...", after.exec); + cmd(after) + } match update { Some(duration) => { info!( @@ -172,3 +180,26 @@ async fn main() { } } } + +fn cmd(command: &config::Command) { + match Command::new("sh").arg("-c").arg(&command.exec).output() { + Ok(response) => { + if response.status.success() { + if command.stdout_contains.as_ref().is_none_or(|v| { + v.iter() + .all(|s| String::from_utf8_lossy(&response.stdout).contains(s)) + }) { + info!("exec `{}` successful: `{:?}`", command.exec, response) + } else { + panic!( + "unexpected exec result `{}`: `{:?}`", + command.exec, response + ) + } + } else { + panic!("exec `{}` failed: `{:?}`", command.exec, response) + } + } + Err(e) => panic!("can't execute `{}`: `{e}`", command.exec), + } +}