diff --git a/src/handlers.rs b/src/handlers.rs index f8f314d..2a0c71c 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -1,22 +1,18 @@ -use crate::config::*; -use crate::utils::EpochTimestamp; +use crate::{config::*, utils::EpochTimestamp, State}; use actix_web::{ error::ErrorInternalServerError, web::Data, Error as WebError, HttpResponse, Result as WebResult, }; -use reqwest::{Client, Url, UrlError}; - use serde::Serialize; -use std::sync::{Arc, RwLock}; use tera::{Context, Tera}; #[derive(Clone, Serialize, Default, Debug)] pub struct Status { - status: u8, - location: String, - domain: String, - endpoint: String, - error: Option, + pub status: u8, + pub location: String, + pub domain: String, + pub endpoint: String, + pub error: Option, } #[derive(Serialize, Debug)] @@ -27,8 +23,6 @@ pub struct QueryResults { pub statuses: Vec, } -type State = Arc>; - pub fn index(tmpl: Data, state: Data) -> WebResult { let state = state.read().unwrap(); let mut ctx = Context::new(); @@ -44,92 +38,3 @@ pub fn json_endpoint(state: Data) -> HttpResponse { let state = state.read().unwrap(); HttpResponse::Ok().json(&state.statuses) } - -pub fn update_state(state: State) { - let mut new_timestamp = None; - let mut new_statuses = None; - { - let read_state = state.read().unwrap(); - if EpochTimestamp::now() - read_state.last_update >= read_state.refresh_time { - new_timestamp = Some(EpochTimestamp::now()); - new_statuses = Some(update_status(&read_state.config)); - } - } - if new_timestamp.is_some() { - let mut write_state = state.try_write().expect("Could not unlock"); - write_state.last_update = new_timestamp.unwrap(); - write_state.statuses = new_statuses.unwrap(); - } -} - -fn update_status(config: &Config) -> Vec { - let client = Client::new(); - let mut results: Vec = vec![]; - - for website_conf in &config.websites { - for endpoint in &website_conf.endpoints { - results.push(get_result(website_conf, &client, endpoint)); - } - } - - results -} - -fn get_result(website_conf: &WebsiteConfig, client: &Client, endpoint: &EndpointConfig) -> Status { - let (label, path, port, code, body) = get_endpoint_info(endpoint.clone()); - let url = get_url(&website_conf.base, &path, port).expect("reading config"); - let ping_result = client.get(&url).send(); - - match ping_result { - Ok(mut res) => { - let res_body = res.text().expect("could not get body of request"); - let does_code_match = res.status() == code; - let does_body_match = body.is_empty() || res_body == body; - let mut error = None; - - if !does_code_match { - error = Some(format!( - "Status code mismatch: {} != {}.", - res.status().as_u16(), - code - )); - } - - if !does_body_match { - error = Some(if let Some(msg) = error { - format!( - "{} Body mismatch: {} != {}.", - msg, - res_body.len(), - body.len() - ) - } else { - format!("Body mismatch: {} != {}.", res_body.len(), body.len()) - }); - } - - Status { - status: if error.is_some() { 1 } else { 0 }, - location: url, - domain: website_conf.label.clone(), - endpoint: label, - error, - } - } - Err(e) => Status { - status: 2, - location: url, - domain: website_conf.label.clone(), - endpoint: label, - error: Some(format!("{}", e)), - }, - } -} - -fn get_url(base: &String, path: &String, port: Option) -> Result { - let mut url = Url::parse(base)?.join(path)?; - if let Err(e) = url.set_port(port) { - println!("{:?}", e); - } - Ok(url.into_string()) -} diff --git a/src/main.rs b/src/main.rs index ec03694..c10dcea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,11 +10,10 @@ extern crate tera; mod config; mod handlers; +mod updater; mod utils; -use self::config::*; -use self::handlers::*; -use self::utils::EpochTimestamp; +use self::{config::*, handlers::*, updater::update_state, utils::EpochTimestamp}; use actix::System; use actix_web::{middleware::Logger, web::resource, App, HttpServer}; use ron::de::from_str; @@ -23,8 +22,12 @@ use std::{ sync::{Arc, RwLock}, time::Duration, }; -use tokio::prelude::{Future, Stream}; -use tokio::timer::Interval; +use tokio::{ + prelude::{Future, Stream}, + timer::Interval, +}; + +pub type State = Arc>; fn main() { System::run(move || { @@ -36,7 +39,7 @@ fn main() { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let state = Arc::new(RwLock::new(QueryResults { + let state: State = Arc::new(RwLock::new(QueryResults { last_update: EpochTimestamp::now(), refresh_time: config.refresh_time.clone(), config: config.clone(), @@ -60,7 +63,7 @@ fn main() { .start(); tokio::spawn( - Interval::new_interval(Duration::from_millis(5000)) + Interval::new_interval(Duration::from_secs(config.refresh_time)) .for_each(move |_| { let state = Arc::clone(&clone_state); update_state(state); diff --git a/src/updater.rs b/src/updater.rs new file mode 100644 index 0000000..40ef9cb --- /dev/null +++ b/src/updater.rs @@ -0,0 +1,81 @@ +use crate::{config::*, handlers::Status, utils::EpochTimestamp, State}; +use reqwest::{Client, Url, UrlError}; + +pub fn update_state(state: State) { + let new_statuses = { Some(update_status(&state.read().unwrap().config)) }; + let mut write_state = state.try_write().expect("Could not unlock"); + write_state.last_update = EpochTimestamp::now(); + write_state.statuses = new_statuses.unwrap(); +} + +fn update_status(config: &Config) -> Vec { + let client = Client::new(); + let mut results: Vec = vec![]; + + for website_conf in &config.websites { + for endpoint in &website_conf.endpoints { + results.push(get_result(website_conf, &client, endpoint)); + } + } + + results +} + +fn get_result(website_conf: &WebsiteConfig, client: &Client, endpoint: &EndpointConfig) -> Status { + let (label, path, port, code, body) = get_endpoint_info(endpoint.clone()); + let url = get_url(&website_conf.base, &path, port).expect("reading config"); + let ping_result = client.get(&url).send(); + + match ping_result { + Ok(mut res) => { + let res_body = res.text().expect("could not get body of request"); + let does_code_match = res.status() == code; + let does_body_match = body.is_empty() || res_body == body; + let mut error = None; + + if !does_code_match { + error = Some(format!( + "Status code mismatch: {} != {}.", + res.status().as_u16(), + code + )); + } + + if !does_body_match { + error = Some(if let Some(msg) = error { + format!( + "{} Body mismatch: {} != {}.", + msg, + res_body.len(), + body.len() + ) + } else { + format!("Body mismatch: {} != {}.", res_body.len(), body.len()) + }); + } + + Status { + status: if error.is_some() { 1 } else { 0 }, + location: url, + domain: website_conf.label.clone(), + endpoint: label, + error, + } + } + Err(e) => Status { + status: 2, + location: url, + domain: website_conf.label.clone(), + endpoint: label, + error: Some(format!("{}", e)), + }, + } +} + +fn get_url(base: &String, path: &String, port: Option) -> Result { + let mut url = Url::parse(base)?.join(path)?; + if let Err(e) = url.set_port(port) { + println!("{:?}", e); + } + Ok(url.into_string()) +}