Compare commits

..

2 commits

5 changed files with 47 additions and 25 deletions

View file

@ -35,7 +35,8 @@
endpoints:[ endpoints:[
(label: "The code doesn't match!", endpoint: "http://example.com/", code: 204), (label: "The code doesn't match!", endpoint: "http://example.com/", code: 204),
(label: "The body doesn't match!", endpoint: "http://example.com/", body: "asdf"), (label: "The body doesn't match!", endpoint: "http://example.com/", body: "asdf"),
(label: "Slow reponse time", endpoint: "http://slowwly.robertomurray.co.uk/delay/2000/url/"), (label: "Slow reponse time", endpoint: "http://slowwly.robertomurray.co.uk/delay/2000/url/", max_rtt: 1337),
(label: "Plethora of issues!", endpoint: "http://slowwly.robertomurray.co.uk/delay/1000/url/", body: "asdf", code: 418, max_rtt: 50),
(label: "Here's an error:", endpoint: "https://some-invalid-website.arpa") (label: "Here's an error:", endpoint: "https://some-invalid-website.arpa")
] ]
), ),

View file

@ -9,6 +9,7 @@ pub struct EndpointConfig {
pub body: Option<String>, pub body: Option<String>,
pub body_hash: Option<String>, pub body_hash: Option<String>,
pub follow_redirects: Option<bool>, pub follow_redirects: Option<bool>,
pub max_rtt: Option<i64>,
pub should_err: Option<bool>, pub should_err: Option<bool>,
} }

View file

@ -1,4 +1,4 @@
use crate::{config::*, State}; use crate::{config::*, updater::update_status, State};
use actix_web::{ use actix_web::{
error::ErrorInternalServerError, web::Data, Error as WebError, HttpResponse, error::ErrorInternalServerError, web::Data, Error as WebError, HttpResponse,
Result as WebResult, Result as WebResult,
@ -63,6 +63,34 @@ pub struct QueryResults {
pub groups: Vec<StatusGroup>, pub groups: Vec<StatusGroup>,
} }
impl QueryResults {
pub fn new(config: Config) -> Self {
let time = Utc::now();
QueryResults {
timestamp: time,
timestamp_str: Self::format_timestamp(time),
refresh_time: config.refresh_time,
config: config.clone(),
groups: update_status(&config),
}
}
pub fn update(&mut self, updated_groups: Vec<StatusGroup>) {
self.update_timestamp();
self.groups = updated_groups;
}
fn update_timestamp(&mut self) {
let current_time = Utc::now();
self.timestamp = current_time;
self.timestamp_str = Self::format_timestamp(current_time);
}
fn format_timestamp(timestamp: DateTime<Utc>) -> String {
timestamp.format("%Y-%m-%d %H:%M:%S").to_string()
}
}
pub fn index(tmpl: Data<Tera>, state: Data<State>) -> WebResult<HttpResponse, WebError> { pub fn index(tmpl: Data<Tera>, state: Data<State>) -> WebResult<HttpResponse, WebError> {
let state = state.read().unwrap(); let state = state.read().unwrap();
let mut ctx = Context::new(); let mut ctx = Context::new();

View file

@ -19,7 +19,6 @@ mod updater;
use self::{config::*, handlers::*, updater::*}; use self::{config::*, handlers::*, updater::*};
use actix::System; use actix::System;
use actix_web::{middleware::Logger, web::resource, App, HttpServer}; use actix_web::{middleware::Logger, web::resource, App, HttpServer};
use chrono::prelude::*;
use ron::de::from_str; use ron::de::from_str;
use std::{ use std::{
env::var, env::var,
@ -35,24 +34,18 @@ use tokio::{
pub type State = Arc<RwLock<QueryResults>>; pub type State = Arc<RwLock<QueryResults>>;
fn main() { fn main() {
System::run(move || { System::run(|| {
let conf_file_loc = let conf_file_loc =
var("ENDSTAT_CONF").unwrap_or_else(|_| String::from("./config/endstat_conf.ron")); var("ENDSTAT_CONF").unwrap_or_else(|_| String::from("./config/endstat_conf.ron"));
let config = from_str::<Config>( let config = from_str::<Config>(
&read_to_string(&conf_file_loc).expect(&format!("finding {}", conf_file_loc)), &read_to_string(&conf_file_loc).expect(&format!("finding {}", conf_file_loc)),
) )
.unwrap(); .unwrap();
let bind_addr = config.bind_address.clone(); let bind_addr = &config.bind_address;
std::env::set_var("RUST_LOG", "actix_web=info"); std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init(); env_logger::init();
let state: State = Arc::new(RwLock::new(QueryResults { let state = Arc::new(RwLock::new(QueryResults::new(config.clone())));
timestamp: Utc::now(),
timestamp_str: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(),
refresh_time: config.refresh_time.clone(),
config: config.clone(),
groups: update_status(&config),
}));
let clone_state = Arc::clone(&state); let clone_state = Arc::clone(&state);

View file

@ -13,10 +13,8 @@ use std::time::Duration;
pub fn update_state(state: State) { pub fn update_state(state: State) {
let new_statuses = { Some(update_status(&state.read().unwrap().config)) }; let new_statuses = { Some(update_status(&state.read().unwrap().config)) };
let mut write_state = state.try_write().expect("Could not unlock"); let mut state = state.try_write().expect("Could not unlock");
write_state.timestamp = Utc::now(); state.update(new_statuses.unwrap());
write_state.timestamp_str = Utc::now().format("%Y-%m-%d %H:%M:%S").to_string();
write_state.groups = new_statuses.unwrap();
} }
pub fn update_status(config: &Config) -> Vec<StatusGroup> { pub fn update_status(config: &Config) -> Vec<StatusGroup> {
@ -70,7 +68,7 @@ fn get_result(
error = append_err_msg( error = append_err_msg(
error, error,
format!( format!(
"Status code mismatch: {} != {}.", "Status code mismatch: {} != {}",
res.status().as_u16(), res.status().as_u16(),
code code
), ),
@ -86,12 +84,17 @@ fn get_result(
} else if !body.is_empty() && res_body != body { } else if !body.is_empty() && res_body != body {
error = append_err_msg( error = append_err_msg(
error, error,
format!("Body mismatch: {} != {}.", res_body.len(), body.len()), format!("Body mismatch: {} != {}", res_body.len(), body.len()),
); );
} }
if rtt.num_seconds() >= 2 { if let Some(max_rtt) = endpoint.max_rtt {
error = append_err_msg(error, format!("RTT too long: {}", rtt_string)); if rtt.num_milliseconds() > max_rtt {
error = append_err_msg(
error,
format!("RTT too long: {} > {}s", rtt_string, max_rtt as f64 / 1000.),
);
}
} }
if error.is_some() { if error.is_some() {
@ -123,12 +126,8 @@ fn get_url(base: &Option<String>, path: &String, port: Option<u16>) -> Result<St
} }
fn append_err_msg(optional: Option<String>, to_append: String) -> Option<String> { fn append_err_msg(optional: Option<String>, to_append: String) -> Option<String> {
// Turns out Rust doesn't recognize that only one of the FnOnce occurs, so
// as a result both closures want ownership of to_append
// Some(optional.map_or_else(|| to_append, |msg| format!("{} {}", msg, to_append)))
Some(match optional { Some(match optional {
Some(e) => format!("{} {}", e, to_append), Some(e) => format!("{}\n{}", e, to_append),
None => to_append, None => to_append,
}) })
} }