endstat/src/updater.rs

126 lines
3.9 KiB
Rust
Raw Permalink Normal View History

2019-05-01 20:59:55 +00:00
use crate::{
config::*,
2019-05-03 20:30:56 +00:00
results::{Endpoint, StatusGroup},
2019-05-01 20:59:55 +00:00
State,
};
2019-05-02 22:47:59 +00:00
use chrono::Utc;
2019-05-01 21:24:18 +00:00
use reqwest::{Client, RedirectPolicy, Url, UrlError};
2019-05-02 07:21:18 +00:00
use ring::{
digest::{digest, SHA256},
test::from_hex,
};
2019-05-01 22:02:38 +00:00
use std::time::Duration;
2019-05-01 18:13:46 +00:00
pub fn update_state(state: State) {
let new_statuses = { Some(update_status(&state.read().unwrap().config)) };
let mut state = state.try_write().expect("Could not unlock");
state.update(new_statuses.unwrap());
2019-05-01 18:13:46 +00:00
}
2019-05-01 20:59:55 +00:00
pub fn update_status(config: &Config) -> Vec<StatusGroup> {
let mut results: Vec<StatusGroup> = Vec::with_capacity(config.websites.len());
2019-05-01 18:13:46 +00:00
for website_conf in &config.websites {
2019-05-01 20:59:55 +00:00
let mut group = Vec::with_capacity(website_conf.endpoints.len());
2019-05-01 18:13:46 +00:00
for endpoint in &website_conf.endpoints {
2019-05-01 22:02:38 +00:00
let mut client_builder = Client::builder().timeout(Some(Duration::from_secs(5)));
2019-05-01 21:24:18 +00:00
if let Some(false) = endpoint.follow_redirects {
client_builder = client_builder.redirect(RedirectPolicy::none());
}
let client = client_builder.build().unwrap();
2019-05-01 20:59:55 +00:00
group.push(get_result(website_conf, &client, endpoint));
2019-05-01 18:13:46 +00:00
}
2019-05-01 20:59:55 +00:00
results.push(StatusGroup {
label: website_conf.label.clone(),
endpoints: group,
});
2019-05-01 18:13:46 +00:00
}
results
}
2019-05-01 20:59:55 +00:00
fn get_result(
website_conf: &WebsiteConfig,
client: &Client,
endpoint: &EndpointConfig,
2019-05-03 20:30:56 +00:00
) -> Endpoint {
2019-05-01 18:13:46 +00:00
let (label, path, port, code, body) = get_endpoint_info(endpoint.clone());
let url = get_url(&website_conf.base, &path, port).expect("reading config");
2019-05-03 00:30:02 +00:00
2019-05-02 22:47:59 +00:00
let ping_start = Utc::now();
2019-05-01 18:13:46 +00:00
let ping_result = client.get(&url).send();
2019-05-03 00:30:02 +00:00
let rtt = Utc::now() - ping_start;
let rtt_string = if rtt.num_seconds() > 0 {
format!("{}s", rtt.num_milliseconds() as f64 / 1000.)
2019-05-02 22:47:59 +00:00
} else {
2019-05-03 00:30:02 +00:00
format!("{}ms", rtt.num_milliseconds())
2019-05-02 22:47:59 +00:00
};
2019-05-03 00:30:02 +00:00
2019-05-01 18:13:46 +00:00
match ping_result {
Ok(mut res) => {
let res_body = res.text().expect("could not get body of request");
let mut errors = vec![];
2019-05-01 18:13:46 +00:00
2019-05-02 07:21:18 +00:00
if res.status() != code {
errors.push(format!(
"Status code mismatch: {} != {}",
res.status().as_u16(),
code
));
2019-05-01 18:13:46 +00:00
}
2019-05-02 07:21:18 +00:00
if let Some(expected_hash) = &endpoint.body_hash {
let expected = from_hex(expected_hash).unwrap();
2019-11-09 22:25:42 +00:00
let actual = digest(&SHA256, res_body.as_bytes());
if expected != actual.as_ref() {
errors.push(String::from("Body hash mismatch."));
2019-05-02 07:21:18 +00:00
}
} else if !body.is_empty() && res_body != body {
errors.push(format!(
"Body mismatch: {} != {}",
res_body.len(),
body.len()
));
2019-05-03 00:30:02 +00:00
}
2019-05-03 04:40:34 +00:00
if let Some(max_rtt) = endpoint.max_rtt {
if rtt.num_milliseconds() > max_rtt {
errors.push(format!(
"RTT too long: {} > {}s",
rtt_string,
max_rtt as f64 / 1000.
));
2019-05-03 04:40:34 +00:00
}
2019-05-01 18:13:46 +00:00
}
if !errors.is_empty() {
2019-05-03 20:30:56 +00:00
Endpoint::warn(url, label, rtt_string, errors)
} else {
2019-05-03 20:30:56 +00:00
Endpoint::ok(url, label, rtt_string)
2019-05-01 18:13:46 +00:00
}
}
Err(e) => {
if let Some(true) = endpoint.should_err {
2019-05-03 20:30:56 +00:00
Endpoint::ok(url, label, rtt_string)
} else {
2019-05-03 20:30:56 +00:00
Endpoint::error(url, label, vec![format!("{}", e)])
}
}
2019-05-01 18:13:46 +00:00
}
}
2019-11-09 22:25:42 +00:00
fn get_url(base: &Option<String>, path: &str, port: Option<u16>) -> Result<String, UrlError> {
2019-05-01 21:16:54 +00:00
let mut url = if let Some(base) = base {
Url::parse(base)?.join(path)?
} else {
Url::parse(path)?
};
2019-05-01 18:13:46 +00:00
if let Err(e) = url.set_port(port) {
println!("{:?}", e);
}
Ok(url.into_string())
}