1
0
mirror of https://github.com/pcvolkmer/checkbar.git synced 2025-04-19 19:16:50 +00:00

Extract checks into modules

This commit is contained in:
Paul-Christian Volkmer 2022-12-27 19:09:50 +01:00
parent 774a843005
commit 1d7b163035
6 changed files with 240 additions and 163 deletions

45
src/checker/actuator.rs Normal file
View File

@ -0,0 +1,45 @@
use crate::checker::{CheckResult, CheckState};
use crate::config::CheckConfig;
use serde::Deserialize;
#[derive(Deserialize)]
struct ActuatorResponse {
status: String,
}
pub struct Checker<'a> {
check_config: &'a CheckConfig,
}
impl Checker<'_> {
pub fn new(check_config: &CheckConfig) -> Checker {
Checker { check_config }
}
pub async fn check(&self) -> CheckResult {
let state = match reqwest::get(self.check_config.url.as_str()).await {
Ok(r) => {
if r.status().is_success() {
match r.json::<ActuatorResponse>().await {
Ok(ar) => {
if ar.status == "UP" {
CheckState::Up
} else {
CheckState::Warn
}
}
_ => CheckState::Warn,
}
} else {
CheckState::Warn
}
}
Err(_) => CheckState::Down,
};
CheckResult {
name: self.check_config.name.to_string(),
state,
}
}
}

30
src/checker/http.rs Normal file
View File

@ -0,0 +1,30 @@
use crate::checker::{CheckResult, CheckState};
use crate::config::CheckConfig;
pub struct Checker<'a> {
check_config: &'a CheckConfig,
}
impl Checker<'_> {
pub fn new(check_config: &CheckConfig) -> Checker {
Checker { check_config }
}
pub async fn check(&self) -> CheckResult {
let state = match reqwest::get(self.check_config.url.as_str()).await {
Ok(r) => {
if r.status().is_success() {
CheckState::Up
} else {
CheckState::Warn
}
}
Err(_) => CheckState::Down,
};
CheckResult {
name: self.check_config.name.to_string(),
state,
}
}
}

51
src/checker/mod.rs Normal file
View File

@ -0,0 +1,51 @@
mod actuator;
mod http;
mod tcp;
pub use crate::checker::actuator::Checker as ActuatorChecker;
pub use crate::checker::http::Checker as HttpChecker;
pub use crate::checker::tcp::Checker as TcpChecker;
use crate::config;
use crate::config::get_config;
use serde_json::json;
use std::fmt::{Display, Formatter, Result};
pub struct CheckResult {
pub name: String,
pub state: CheckState,
}
impl Display for CheckResult {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let color_config = match get_config().colors {
Some(color_config) => color_config,
None => config::ColorConfig {
up: String::from("#00FF00"),
warn: String::from("#FFFF00"),
down: String::from("#FF0000"),
},
};
let color = match &self.state {
CheckState::Up => color_config.up,
CheckState::Warn => color_config.warn,
CheckState::Down => color_config.down,
};
write!(
f,
"{}",
json!({
"full_text": self.name,
"name": self.name,
"separator_block_width": 16,
"color": color
})
)
}
}
pub enum CheckState {
Up,
Warn,
Down,
}

43
src/checker/tcp.rs Normal file
View File

@ -0,0 +1,43 @@
use std::str::FromStr;
use reqwest::Url;
use tokio::net::TcpStream;
use crate::checker::{CheckResult, CheckState};
use crate::config::CheckConfig;
pub struct Checker<'a> {
check_config: &'a CheckConfig,
}
impl Checker<'_> {
pub fn new(check_config: &CheckConfig) -> Checker {
Checker { check_config }
}
pub async fn check(&self) -> CheckResult {
if let Ok(url) = Url::from_str(self.check_config.url.as_str()) {
if url.scheme() == "tcp" && url.host_str().is_some() && url.port().is_some() {
let state = match TcpStream::connect(format!(
"{}:{}",
url.host_str().unwrap(),
url.port().unwrap()
))
.await
{
Ok(_) => CheckState::Up,
_ => CheckState::Down,
};
return CheckResult {
name: self.check_config.name.to_string(),
state,
};
}
}
CheckResult {
name: self.check_config.name.to_string(),
state: CheckState::Down,
}
}
}

59
src/config.rs Normal file
View File

@ -0,0 +1,59 @@
use serde::Deserialize;
use std::{env, fs};
#[derive(Deserialize)]
pub struct Config {
pub interval: Option<u64>,
pub colors: Option<ColorConfig>,
pub checks: Vec<CheckConfig>,
}
#[derive(Deserialize)]
pub struct ColorConfig {
pub up: String,
pub warn: String,
pub down: String,
}
#[derive(Deserialize)]
pub struct CheckConfig {
pub name: String,
pub url: String,
pub check_type: Option<CheckType>,
pub click_cmd: Option<String>,
}
#[derive(Deserialize, PartialEq, Eq)]
pub enum CheckType {
Http,
Actuator,
Tcp,
}
fn get_config_file() -> String {
match env::args().nth(1) {
Some(config_file) => config_file,
None => format!(
"{}/.checkbar.toml",
dirs::home_dir().unwrap().to_str().unwrap_or("")
),
}
}
pub fn get_config() -> Config {
match fs::read_to_string(get_config_file()) {
Ok(config) => match toml::from_str(config.as_str()) {
Ok(config) => config,
Err(_e) => Config {
interval: None,
colors: None,
checks: vec![],
},
},
Err(_) => Config {
interval: None,
colors: None,
checks: vec![],
},
}
}

View File

@ -1,48 +1,15 @@
use reqwest::Url; mod checker;
mod config;
use std::process;
use std::time::Duration;
use serde::Deserialize; use serde::Deserialize;
use serde_json::json; use serde_json::json;
use std::env;
use std::fmt::{Display, Formatter, Result};
use std::fs;
use std::process;
use std::str::FromStr;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::task; use tokio::task;
#[derive(Deserialize)] use crate::checker::{ActuatorChecker, CheckResult, HttpChecker, TcpChecker};
struct Config { use crate::config::{get_config, CheckConfig, CheckType};
interval: Option<u64>,
colors: Option<ColorConfig>,
checks: Vec<CheckConfig>,
}
#[derive(Deserialize)]
struct ColorConfig {
up: String,
warn: String,
down: String,
}
#[derive(Deserialize)]
struct CheckConfig {
name: String,
url: String,
check_type: Option<CheckType>,
click_cmd: Option<String>,
}
#[derive(Deserialize, PartialEq)]
enum CheckType {
Http,
Actuator,
Tcp,
}
#[derive(Deserialize)]
struct ActuatorResponse {
status: String,
}
#[derive(Deserialize)] #[derive(Deserialize)]
struct ClickEvent { struct ClickEvent {
@ -50,101 +17,11 @@ struct ClickEvent {
button: u8, button: u8,
} }
struct CheckResult {
name: String,
state: CheckState,
}
impl Display for CheckResult {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let color_config = match get_config().colors {
Some(color_config) => color_config,
None => ColorConfig {
up: String::from("#00FF00"),
warn: String::from("#FFFF00"),
down: String::from("#FF0000"),
},
};
let color = match &self.state {
CheckState::Up => color_config.up,
CheckState::Warn => color_config.warn,
CheckState::Down => color_config.down,
};
write!(
f,
"{}",
json!({
"full_text": self.name,
"name": self.name,
"separator_block_width": 16,
"color": color
})
)
}
}
enum CheckState {
Up,
Warn,
Down,
}
async fn check_host(check_config: &CheckConfig) -> CheckResult { async fn check_host(check_config: &CheckConfig) -> CheckResult {
if check_config.check_type == Some(CheckType::Tcp) {
if let Ok(url) = Url::from_str(check_config.url.as_str()) {
if url.scheme() == "tcp" {
if url.host_str().is_some() && url.port().is_some() {
let state = match TcpStream::connect(format!(
"{}:{}",
url.host_str().unwrap(),
url.port().unwrap()
))
.await
{
Ok(_) => CheckState::Up,
_ => CheckState::Down,
};
return CheckResult {
name: check_config.name.to_string(),
state,
};
}
}
}
return CheckResult {
name: check_config.name.to_string(),
state: CheckState::Down,
};
}
let state = match reqwest::get(check_config.url.as_str()).await {
Ok(r) => {
if r.status().is_success() {
match check_config.check_type { match check_config.check_type {
Some(CheckType::Actuator) => match r.json::<ActuatorResponse>().await { Some(CheckType::Actuator) => ActuatorChecker::new(check_config).check().await,
Ok(ar) => { Some(CheckType::Tcp) => TcpChecker::new(check_config).check().await,
if ar.status == "UP" { _ => HttpChecker::new(check_config).check().await,
CheckState::Up
} else {
CheckState::Warn
}
}
_ => CheckState::Warn,
},
// Default: HTTP
_ => CheckState::Up,
}
} else {
CheckState::Warn
}
}
Err(_) => CheckState::Down,
};
CheckResult {
name: check_config.name.to_string(),
state,
} }
} }
@ -163,34 +40,6 @@ async fn print_states(check_configs: &[CheckConfig]) {
println!("{}],", entries.join(",")); println!("{}],", entries.join(","));
} }
fn get_config_file() -> String {
match env::args().nth(1) {
Some(config_file) => config_file,
None => format!(
"{}/.checkbar.toml",
dirs::home_dir().unwrap().to_str().unwrap_or("")
),
}
}
fn get_config() -> Config {
match fs::read_to_string(get_config_file()) {
Ok(config) => match toml::from_str(config.as_str()) {
Ok(config) => config,
Err(_e) => Config {
interval: None,
colors: None,
checks: vec![],
},
},
Err(_) => Config {
interval: None,
colors: None,
checks: vec![],
},
}
}
async fn get_click_cmd(name: String) -> Option<String> { async fn get_click_cmd(name: String) -> Option<String> {
for check in get_config().checks { for check in get_config().checks {
if check.name == name { if check.name == name {