use crate::{ config::*, handlers::{EndpointStatus, StatusGroup}, State, }; use chrono::prelude::Utc; use reqwest::{Client, RedirectPolicy, Url, UrlError}; 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(); } pub fn update_status(config: &Config) -> Vec { let mut results: Vec = Vec::with_capacity(config.websites.len()); for website_conf in &config.websites { let mut group = Vec::with_capacity(website_conf.endpoints.len()); for endpoint in &website_conf.endpoints { let mut client_builder = Client::builder().timeout(Some(Duration::from_secs(5))); if let Some(false) = endpoint.follow_redirects { client_builder = client_builder.redirect(RedirectPolicy::none()); } let client = client_builder.build().unwrap(); group.push(get_result(website_conf, &client, endpoint)); } results.push(StatusGroup { label: website_conf.label.clone(), endpoints: group, }); } results } fn get_result( website_conf: &WebsiteConfig, client: &Client, endpoint: &EndpointConfig, ) -> EndpointStatus { 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()) }); } if error.is_some() { EndpointStatus::warn(url, label, error) } else { EndpointStatus::ok(url, label) } } Err(e) => { if let Some(true) = endpoint.should_err { EndpointStatus::ok(url, label) } else { EndpointStatus::error(url, label, Some(format!("{}", e))) } } } } fn get_url(base: &Option, path: &String, port: Option) -> Result { let mut url = if let Some(base) = base { Url::parse(base)?.join(path)? } else { Url::parse(path)? }; if let Err(e) = url.set_port(port) { println!("{:?}", e); } Ok(url.into_string()) }