now renders in groups

master
Edward Shen 2019-05-01 16:59:55 -04:00
parent 211a3f9477
commit c83190ada6
Signed by: edward
GPG Key ID: F350507060ED6C90
4 changed files with 57 additions and 36 deletions

View File

@ -8,21 +8,26 @@ use serde::Serialize;
use tera::{Context, Tera};
#[derive(Clone, Serialize, Default, Debug)]
pub struct Status {
pub struct EndpointStatus {
pub status: u8,
pub location: String,
pub domain: String,
pub endpoint: String,
pub error: Option<String>,
}
#[derive(Serialize, Debug)]
pub struct StatusGroup {
pub label: String,
pub endpoints: Vec<EndpointStatus>,
}
#[derive(Serialize, Debug)]
pub struct QueryResults {
pub timestamp: DateTime<Utc>,
pub timestamp_str: String,
pub refresh_time: u64,
pub config: Config,
pub statuses: Vec<Status>,
pub groups: Vec<StatusGroup>,
}
pub fn index(tmpl: Data<Tera>, state: Data<State>) -> WebResult<HttpResponse, WebError> {
@ -38,5 +43,5 @@ pub fn index(tmpl: Data<Tera>, state: Data<State>) -> WebResult<HttpResponse, We
pub fn json_endpoint(state: Data<State>) -> HttpResponse {
let state = state.read().unwrap();
HttpResponse::Ok().json(&state.statuses)
HttpResponse::Ok().json(&*state.groups)
}

View File

@ -45,7 +45,7 @@ fn main() {
timestamp_str: Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(),
refresh_time: config.refresh_time.clone(),
config: config.clone(),
statuses: update_status(&config),
groups: update_status(&config),
}));
let clone_state = Arc::clone(&state);

View File

@ -1,4 +1,8 @@
use crate::{config::*, handlers::Status, State};
use crate::{
config::*,
handlers::{EndpointStatus, StatusGroup},
State,
};
use chrono::prelude::*;
use reqwest::{Client, Url, UrlError};
@ -7,23 +11,33 @@ pub fn update_state(state: State) {
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.statuses = new_statuses.unwrap();
write_state.groups = new_statuses.unwrap();
}
pub fn update_status(config: &Config) -> Vec<Status> {
pub fn update_status(config: &Config) -> Vec<StatusGroup> {
let client = Client::new();
let mut results: Vec<Status> = vec![];
let mut results: Vec<StatusGroup> = 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 {
results.push(get_result(website_conf, &client, endpoint));
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) -> Status {
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();
@ -56,18 +70,16 @@ fn get_result(website_conf: &WebsiteConfig, client: &Client, endpoint: &Endpoint
});
}
Status {
EndpointStatus {
status: if error.is_some() { 1 } else { 0 },
location: url,
domain: website_conf.label.clone(),
endpoint: label,
error,
}
}
Err(e) => Status {
Err(e) => EndpointStatus {
status: 2,
location: url,
domain: website_conf.label.clone(),
endpoint: label,
error: Some(format!("{}", e)),
},

View File

@ -8,17 +8,17 @@
<style>
body {
background-color: #212121;
margin: 0;
color: #fff;
font-family: 'Montserrat', sans-serif;
}
main {
width: 700px;
margin: 0 auto;
margin-top: 5rem;
}
main {
padding: 1rem 0;
}
header {
display: flex;
align-items: flex-end;
@ -28,45 +28,49 @@
section {
display: flex;
align-items: stretch;
justify-content: space-between;
background-color: #424242;
margin: 1rem 0;
padding: 1rem;
border-radius: 1rem;
}
p { margin: 0; }
a {
color: #fff;
text-decoration: none;
}
h1 { display: block; margin: 0; }
h3 { margin-top: 0; }
.indicator {
width: 1rem;
height: 1rem;
border-radius: 1rem;
min-height: 100%;
border-radius: 1rem 0 0 1rem;
margin-right: 1rem;
}
.ok { background-color: green; }
.warn { background-color: yellow; }
.error { background-color: red; }
.ok { background-color: #4ed34e; }
.warn { background-color: #fcfc64; }
.error { background-color: #ff392e; }
.error-msg { font-family: 'Source Code Pro', monospace;}
</style>
</head>
<body>
<main>
<header>
<h1>Status</h1>
<h1>Status Overview</h1>
<p>{{ results.timestamp_str }}</p>
</header>
{% for status in results.statuses -%}
{% for group in results.groups -%}
<h2>{{ group.label }}</h2>
{% for status in group.endpoints -%}
<section>
<div>
<!-- <p>{{ status.domain }}</p> -->
<h3>{{ status.endpoint }}</h3>
<p>{{ status.location }}</p>
{% if status.error %}<p class="error-msg">{{ status.error }}</p>{% endif %}
</div>
<aside class="indicator {% if status.status == 0 %}ok{% elif status.status == 1 %}warn{% else %}error{% endif %}"></aside>
<main>
<h3>{{ status.endpoint }}</h3>
<a href="{{ status.location }}">{{ status.location }}</a>
{% if status.error %}<p class="error-msg">{{ status.error }}</p>{% endif %}
</main>
</section>
{% endfor -%}
</main>
{% endfor -%}
</body>
</html>