aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 01333c9d2b2a1add029a7da0a504d60281f6a5fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use color_eyre::eyre::Result;
use hyper::{header::CONTENT_TYPE, Body, Response};
use prometheus::{Encoder, TextEncoder};
use std::sync::Arc;
use warp::{path, Filter};

pub mod app;
pub mod handlers;
pub mod post;
pub mod signalboost;

use app::State;

const APPLICATION_NAME: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

fn with_state(
    state: Arc<State>,
) -> impl Filter<Extract = (Arc<State>,), Error = std::convert::Infallible> + Clone {
    warp::any().map(move || state.clone())
}

#[tokio::main]
async fn main() -> Result<()> {
    color_eyre::install()?;
    let _ = kankyo::init();
    tracing_subscriber::fmt::init();
    log::info!("starting up commit {}", env!("GITHUB_SHA"));

    let state = Arc::new(app::init(
        std::env::var("CONFIG_FNAME")
            .unwrap_or("./config.dhall".into())
            .as_str()
            .into(),
    ).await?);

    let healthcheck = warp::get().and(warp::path(".within").and(warp::path("health")).map(|| "OK"));

    let base = warp::path!("blog" / ..);
    let blog_index = base
        .and(warp::path::end())
        .and(with_state(state.clone()))
        .and_then(handlers::blog::index);
    let series = base
        .and(warp::path!("series").and(with_state(state.clone()).and_then(handlers::blog::series)));
    let series_view = base.and(
        warp::path!("series" / String)
            .and(with_state(state.clone()))
            .and(warp::get())
            .and_then(handlers::blog::series_view),
    );
    let post_view = base.and(
        warp::path!(String)
            .and(with_state(state.clone()))
            .and(warp::get())
            .and_then(handlers::blog::post_view),
    );

    let gallery_base = warp::path!("gallery" / ..);
    let gallery_index = gallery_base
        .and(warp::path::end())
        .and(with_state(state.clone()))
        .and_then(handlers::gallery::index);
    let gallery_post_view = gallery_base.and(
        warp::path!(String)
            .and(with_state(state.clone()))
            .and(warp::get())
            .and_then(handlers::gallery::post_view),
    );

    let talk_base = warp::path!("talks" / ..);
    let talk_index = talk_base
        .and(warp::path::end())
        .and(with_state(state.clone()))
        .and_then(handlers::talks::index);
    let talk_post_view = talk_base.and(
        warp::path!(String)
            .and(with_state(state.clone()))
            .and(warp::get())
            .and_then(handlers::talks::post_view),
    );

    let index = warp::get().and(path::end().and_then(handlers::index));
    let contact = warp::path!("contact").and_then(handlers::contact);
    let feeds = warp::path!("feeds").and_then(handlers::feeds);
    let resume = warp::path!("resume")
        .and(with_state(state.clone()))
        .and_then(handlers::resume);
    let signalboost = warp::path!("signalboost")
        .and(with_state(state.clone()))
        .and_then(handlers::signalboost);
    let patrons = warp::path!("patrons")
        .and(with_state(state.clone()))
        .and_then(handlers::patrons);

    let files = warp::path("static").and(warp::fs::dir("./static"));
    let css = warp::path("css").and(warp::fs::dir("./css"));
    let sw = warp::path("sw.js").and(warp::fs::file("./static/js/sw.js"));
    let robots = warp::path("robots.txt").and(warp::fs::file("./static/robots.txt"));
    let favicon = warp::path("favicon.ico").and(warp::fs::file("./static/favicon/favicon.ico"));

    let jsonfeed = warp::path("blog.json")
        .and(with_state(state.clone()))
        .and_then(handlers::feeds::jsonfeed);
    let atom = warp::path("blog.atom")
        .and(with_state(state.clone()))
        .and_then(handlers::feeds::atom);
    let rss = warp::path("blog.rss")
        .and(with_state(state.clone()))
        .and_then(handlers::feeds::rss);
    let sitemap = warp::path("sitemap.xml")
        .and(with_state(state.clone()))
        .and_then(handlers::feeds::sitemap);

    let go_vanity_jsonfeed = warp::path("jsonfeed")
        .and(warp::any().map(move || "christine.website/jsonfeed"))
        .and(warp::any().map(move || "https://tulpa.dev/Xe/jsonfeed"))
        .and_then(go_vanity::gitea);

    let metrics_endpoint = warp::path("metrics").and(warp::path::end()).map(move || {
        let encoder = TextEncoder::new();
        let metric_families = prometheus::gather();
        let mut buffer = vec![];
        encoder.encode(&metric_families, &mut buffer).unwrap();
        Response::builder()
            .status(200)
            .header(CONTENT_TYPE, encoder.format_type())
            .body(Body::from(buffer))
            .unwrap()
    });

    let site = index
        .or(contact.or(feeds).or(resume.or(signalboost)).or(patrons))
        .or(blog_index.or(series.or(series_view).or(post_view)))
        .or(gallery_index.or(gallery_post_view))
        .or(talk_index.or(talk_post_view))
        .or(jsonfeed.or(atom).or(rss.or(sitemap)))
        .or(files.or(css).or(favicon).or(sw.or(robots)))
        .or(healthcheck.or(metrics_endpoint).or(go_vanity_jsonfeed))
        .map(|reply| {
            warp::reply::with_header(
                reply,
                "X-Hacker",
                "If you are reading this, check out /signalboost to find people for your team",
            )
        })
        .map(|reply| warp::reply::with_header(reply, "X-Clacks-Overhead", "GNU Ashlynn"))
        .with(warp::log(APPLICATION_NAME))
        .recover(handlers::rejection);

    warp::serve(site).run(([0, 0, 0, 0], 3030)).await;

    Ok(())
}

include!(concat!(env!("OUT_DIR"), "/templates.rs"));