Compare commits
2 commits
01757eb4da
...
ddab660945
Author | SHA1 | Date | |
---|---|---|---|
ddab660945 | |||
39d932c949 |
5 changed files with 52 additions and 28 deletions
|
@ -35,6 +35,7 @@
|
||||||
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: "Here's an error:", endpoint: "https://some-invalid-website.arpa")
|
(label: "Here's an error:", endpoint: "https://some-invalid-website.arpa")
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|
|
@ -68,10 +68,11 @@
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<h3>{{ status.endpoint }}</h3>
|
<h3>{{ status.endpoint }}</h3>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<a href="{{ status.location }}" target="_blank">{{ status.location }}</a>
|
{% if status.status != 2 %}<p>{{ status.rtt }}</p>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
<a href="{{ status.location }}" target="_blank">{{ status.location }}</a>
|
||||||
{% if status.error %}<p class="error-msg">{{ status.error }}</p>{% endif %}
|
{% if status.error %}<p class="error-msg">{{ status.error }}</p>{% endif %}
|
||||||
</main>
|
</main>
|
||||||
</section>
|
</section>
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
|
|
|
@ -12,24 +12,27 @@ pub struct EndpointStatus {
|
||||||
pub status: u8,
|
pub status: u8,
|
||||||
pub location: String,
|
pub location: String,
|
||||||
pub endpoint: String,
|
pub endpoint: String,
|
||||||
|
pub rtt: Option<String>,
|
||||||
pub error: Option<String>,
|
pub error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EndpointStatus {
|
impl EndpointStatus {
|
||||||
pub fn ok(location: String, endpoint: String) -> Self {
|
pub fn ok(location: String, endpoint: String, rtt: String) -> Self {
|
||||||
EndpointStatus {
|
EndpointStatus {
|
||||||
status: 0,
|
status: 0,
|
||||||
location,
|
location,
|
||||||
endpoint,
|
endpoint,
|
||||||
|
rtt: Some(rtt),
|
||||||
error: None,
|
error: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn warn(location: String, endpoint: String, error: Option<String>) -> Self {
|
pub fn warn(location: String, endpoint: String, rtt: String, error: Option<String>) -> Self {
|
||||||
EndpointStatus {
|
EndpointStatus {
|
||||||
status: 1,
|
status: 1,
|
||||||
location,
|
location,
|
||||||
endpoint,
|
endpoint,
|
||||||
|
rtt: Some(rtt),
|
||||||
error,
|
error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +42,7 @@ impl EndpointStatus {
|
||||||
status: 2,
|
status: 2,
|
||||||
location,
|
location,
|
||||||
endpoint,
|
endpoint,
|
||||||
|
rtt: None,
|
||||||
error,
|
error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
extern crate actix;
|
extern crate actix;
|
||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
handlers::{EndpointStatus, StatusGroup},
|
handlers::{EndpointStatus, StatusGroup},
|
||||||
State,
|
State,
|
||||||
};
|
};
|
||||||
use chrono::prelude::Utc;
|
use chrono::Utc;
|
||||||
use reqwest::{Client, RedirectPolicy, Url, UrlError};
|
use reqwest::{Client, RedirectPolicy, Url, UrlError};
|
||||||
use ring::{
|
use ring::{
|
||||||
digest::{digest, SHA256},
|
digest::{digest, SHA256},
|
||||||
|
@ -51,7 +51,15 @@ fn get_result(
|
||||||
) -> EndpointStatus {
|
) -> EndpointStatus {
|
||||||
let (label, path, port, code, body) = get_endpoint_info(endpoint.clone());
|
let (label, path, port, code, body) = get_endpoint_info(endpoint.clone());
|
||||||
let url = get_url(&website_conf.base, &path, port).expect("reading config");
|
let url = get_url(&website_conf.base, &path, port).expect("reading config");
|
||||||
|
|
||||||
|
let ping_start = Utc::now();
|
||||||
let ping_result = client.get(&url).send();
|
let ping_result = client.get(&url).send();
|
||||||
|
let rtt = Utc::now() - ping_start;
|
||||||
|
let rtt_string = if rtt.num_seconds() > 0 {
|
||||||
|
format!("{}s", rtt.num_milliseconds() as f64 / 1000.)
|
||||||
|
} else {
|
||||||
|
format!("{}ms", rtt.num_milliseconds())
|
||||||
|
};
|
||||||
|
|
||||||
match ping_result {
|
match ping_result {
|
||||||
Ok(mut res) => {
|
Ok(mut res) => {
|
||||||
|
@ -59,45 +67,42 @@ fn get_result(
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
|
|
||||||
if res.status() != code {
|
if res.status() != code {
|
||||||
error = Some(format!(
|
error = append_err_msg(
|
||||||
"Status code mismatch: {} != {}.",
|
error,
|
||||||
res.status().as_u16(),
|
format!(
|
||||||
code
|
"Status code mismatch: {} != {}.",
|
||||||
));
|
res.status().as_u16(),
|
||||||
|
code
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(expected_hash) = &endpoint.body_hash {
|
if let Some(expected_hash) = &endpoint.body_hash {
|
||||||
let expected = from_hex(expected_hash).unwrap();
|
let expected = from_hex(expected_hash).unwrap();
|
||||||
let actual = digest(&SHA256, String::from(res_body).as_bytes());
|
let actual = digest(&SHA256, String::from(res_body).as_bytes());
|
||||||
if &expected != &actual.as_ref() {
|
if &expected != &actual.as_ref() {
|
||||||
error = Some(if let Some(msg) = error {
|
error = append_err_msg(error, String::from("Body hash mismatch."));
|
||||||
format!("{} Body hash mismatch.", msg)
|
|
||||||
} else {
|
|
||||||
String::from("Body hash mismatch.")
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if !body.is_empty() && res_body != body {
|
} else if !body.is_empty() && res_body != body {
|
||||||
error = Some(if let Some(msg) = error {
|
error = append_err_msg(
|
||||||
format!(
|
error,
|
||||||
"{} Body mismatch: {} != {}.",
|
format!("Body mismatch: {} != {}.", res_body.len(), body.len()),
|
||||||
msg,
|
);
|
||||||
res_body.len(),
|
}
|
||||||
body.len()
|
|
||||||
)
|
if rtt.num_seconds() >= 2 {
|
||||||
} else {
|
error = append_err_msg(error, format!("RTT too long: {}", rtt_string));
|
||||||
format!("Body mismatch: {} != {}.", res_body.len(), body.len())
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if error.is_some() {
|
if error.is_some() {
|
||||||
EndpointStatus::warn(url, label, error)
|
EndpointStatus::warn(url, label, rtt_string, error)
|
||||||
} else {
|
} else {
|
||||||
EndpointStatus::ok(url, label)
|
EndpointStatus::ok(url, label, rtt_string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let Some(true) = endpoint.should_err {
|
if let Some(true) = endpoint.should_err {
|
||||||
EndpointStatus::ok(url, label)
|
EndpointStatus::ok(url, label, rtt_string)
|
||||||
} else {
|
} else {
|
||||||
EndpointStatus::error(url, label, Some(format!("{}", e)))
|
EndpointStatus::error(url, label, Some(format!("{}", e)))
|
||||||
}
|
}
|
||||||
|
@ -116,3 +121,14 @@ fn get_url(base: &Option<String>, path: &String, port: Option<u16>) -> Result<St
|
||||||
}
|
}
|
||||||
Ok(url.into_string())
|
Ok(url.into_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(e) => format!("{} {}", e, to_append),
|
||||||
|
None => to_append,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue