Compare commits

...

2 Commits

Author SHA1 Message Date
Edward Shen 82b944a748
implemented rtt threshold i guess 2019-05-03 00:40:34 -04:00
Edward Shen 816a6daed1
query results knows how to update itself 2019-05-03 00:12:09 -04:00
5 changed files with 47 additions and 25 deletions

View File

@ -35,7 +35,8 @@
endpoints:[
(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: "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")
]
),

View File

@ -9,6 +9,7 @@ pub struct EndpointConfig {
pub body: Option<String>,
pub body_hash: Option<String>,
pub follow_redirects: Option<bool>,
pub max_rtt: Option<i64>,
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::{
error::ErrorInternalServerError, web::Data, Error as WebError, HttpResponse,
Result as WebResult,
@ -63,6 +63,34 @@ pub struct QueryResults {
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> {
let state = state.read().unwrap();
let mut ctx = Context::new();

View File

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

View File

@ -13,10 +13,8 @@ use std::time::Duration;
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.timestamp = Utc::now();
write_state.timestamp_str = Utc::now().format("%Y-%m-%d %H:%M:%S").to_string();
write_state.groups = new_statuses.unwrap();
let mut state = state.try_write().expect("Could not unlock");
state.update(new_statuses.unwrap());
}
pub fn update_status(config: &Config) -> Vec<StatusGroup> {
@ -70,7 +68,7 @@ fn get_result(
error = append_err_msg(
error,
format!(
"Status code mismatch: {} != {}.",
"Status code mismatch: {} != {}",
res.status().as_u16(),
code
),
@ -86,12 +84,17 @@ fn get_result(
} else if !body.is_empty() && res_body != body {
error = append_err_msg(
error,
format!("Body mismatch: {} != {}.", res_body.len(), body.len()),
format!("Body mismatch: {} != {}", res_body.len(), body.len()),
);
}
if rtt.num_seconds() >= 2 {
error = append_err_msg(error, format!("RTT too long: {}", rtt_string));
if let Some(max_rtt) = endpoint.max_rtt {
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() {
@ -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> {
// 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(e) => format!("{} {}", e, to_append),
Some(e) => format!("{}\n{}", e, to_append),
None => to_append,
})
}