Single-binary self-hosted uptime monitoring and status pages on Rust axum: HTTP probes, Lighthouse audits, SEO crawler, and PDF reports.
axumdockerrustself-hostedsqlitestatus-pageuptime-monitoringvite
1use axum::{
2 extract::State,
3 response::{IntoResponse, Redirect, Response},
4 routing::get,
5 Router,
6};
7use tower_cookies::Cookies;
8
9use crate::render::render;
10use crate::routes::auth::is_authenticated;
11use crate::AppState;
12
13pub fn router() -> Router<AppState> {
14 Router::new()
15 .route("/", get(home))
16 .route("/changelog", get(changelog))
17}
18
19pub async fn home(State(state): State<AppState>, cookies: Cookies) -> Response {
20 let authed = is_authenticated(&cookies, &state);
21 if authed {
22 return Redirect::to("/properties").into_response();
23 }
24 let totals: (i64, i64, Option<i64>) = sqlx::query_as(
25 "SELECT \
26 (SELECT COUNT(*) FROM checks), \
27 (SELECT COUNT(*) FROM properties), \
28 (SELECT MIN(created_at) FROM checks)",
29 )
30 .fetch_one(&state.pool)
31 .await
32 .unwrap_or((0, 0, None));
33
34 let first = totals.2.and_then(|ms| {
35 chrono::DateTime::<chrono::Utc>::from_timestamp_millis(ms)
36 .map(|d| d.format("%b %-d, %Y").to_string())
37 });
38
39 let extra = minijinja::context! {
40 page => minijinja::context! {
41 title => "Home",
42 description => "Self-hosted uptime monitoring with status pages.",
43 },
44 title => "Home",
45 description => "Self-hosted uptime monitoring with status pages.",
46 total_statuses => totals.0,
47 total_properties => totals.1,
48 first_status_created_at => first,
49 };
50 render(&state, "pages/home.html", "/", authed, extra)
51}
52
53pub async fn changelog(State(state): State<AppState>, cookies: Cookies) -> Response {
54 let authed = is_authenticated(&cookies, &state);
55 let extra = minijinja::context! {
56 page => minijinja::context! {
57 title => "Changelog",
58 description => "An ongoing changelog and upcoming list of features for Status.",
59 },
60 title => "Changelog",
61 description => "An ongoing changelog and upcoming list of features for Status.",
62 };
63 render(&state, "pages/changelog.html", "/changelog", authed, extra)
64}