aboutsummaryrefslogtreecommitdiff
path: root/src/web.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-05-03 19:34:45 +0200
committermetamuffin <metamuffin@disroot.org>2024-05-03 19:34:45 +0200
commitd60bedc20dc0cc54cb697f3a45e5b222de6f1479 (patch)
treebe310b8ca7075cef3676d4b05ac99f9267692b95 /src/web.rs
downloadstatuspage-d60bedc20dc0cc54cb697f3a45e5b222de6f1479.tar
statuspage-d60bedc20dc0cc54cb697f3a45e5b222de6f1479.tar.bz2
statuspage-d60bedc20dc0cc54cb697f3a45e5b222de6f1479.tar.zst
works
Diffstat (limited to 'src/web.rs')
-rw-r--r--src/web.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/web.rs b/src/web.rs
new file mode 100644
index 0000000..0080697
--- /dev/null
+++ b/src/web.rs
@@ -0,0 +1,86 @@
+use crate::{Check, Config, Service, Success, STATUS};
+use anyhow::Result;
+use axum::response::Html;
+use markup::{doctype, Render};
+use std::{collections::BTreeMap, ops::Deref, sync::Arc, time::Duration};
+
+pub async fn send_html_page(config: Arc<Config>) -> Html<String> {
+ let mut out = String::new();
+ let status = STATUS.read().await;
+ let status = status.deref();
+
+ #[cfg(not(debug_assertions))]
+ let css = include_str!("style.css");
+ #[cfg(debug_assertions)]
+ let css = tokio::fs::read_to_string("src/style.css").await.unwrap();
+
+ markup::new! {
+ @doctype()
+ html {
+ head {
+ meta[charset="UTF-8"];
+ meta[name="viewport", content="width=device-width, initial-scale=1.0"];
+ title { "Status Page" }
+ style { @css }
+ }
+ body {
+ main {
+ h1 { @config.title }
+ @for (i, service) in config.services.iter().enumerate() {
+ @ServiceCard { i, status, service }
+ }
+ }
+ }
+ }
+ }
+ .render(&mut out)
+ .unwrap();
+ Html(out)
+}
+
+markup::define!(
+ ServiceCard<'a>(status: &'a BTreeMap<(usize, usize), Result<Success>>, service: &'a Service, i: usize) {
+ @let any_err = status.range((*i,usize::MIN)..(*i,usize::MAX)).any(|(_,v)|v.is_err());
+ div.service.{if any_err { "error" } else { "ok" }} {
+ h2 { @service.title }
+ div.checks {
+ @for (j, check) in service.checks.iter().enumerate() {
+ @if let Some(status) = status.get(&(*i, j)) {
+ span.name { @check.display() }
+ @match status {
+ Ok(Success { latency, updated }) => {
+ span.status.ok { "Ok" }
+ span.details.ok {
+ "Checked " @format_duration(updated.elapsed().unwrap_or_default()) " ago"
+ @if let Some(latency) = latency { ", took " @format_duration(*latency) } "."
+ }
+ }
+ Err(e) => {
+ span.status.error { "Error" }
+ span.details { @format!("{e}") }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+);
+
+impl Check {
+ pub fn display(&self) -> String {
+ match self {
+ Check::Systemd(_) => "Service".to_string(),
+ Check::Http { title, .. } => title.clone().unwrap_or("HTTP".to_string()),
+ Check::Shell { title, .. } => title.to_owned(),
+ }
+ }
+}
+
+fn format_duration(d: Duration) -> String {
+ if d.as_millis() < 1500 {
+ format!("{}ms", d.as_millis())
+ } else {
+ format!("{}s", d.as_secs())
+ }
+}