aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2020-07-16 15:32:30 -0400
committerGitHub <noreply@github.com>2020-07-16 15:32:30 -0400
commit385d25c9f96c0acd5d932488e3bd0ed36ceb4dd7 (patch)
treeaf789f7250519b23038a7e5ea0ae7f4f4c1ffdfc /src/main.rs
parent449e934246c82d90dd0aac2644d67f928befeeb4 (diff)
downloadxesite-385d25c9f96c0acd5d932488e3bd0ed36ceb4dd7.tar.xz
xesite-385d25c9f96c0acd5d932488e3bd0ed36ceb4dd7.zip
Rewrite site backend in Rust (#178)
* add shell.nix changes for Rust #176 * set up base crate layout * add first set of dependencies * start adding basic app modules * start html templates * serve index page * add contact and feeds pages * add resume rendering support * resume cleanups * get signalboost page working * rewrite config to be in dhall * more work * basic generic post loading * more tests * initial blog index support * fix routing? * render blogposts * X-Clacks-Overhead * split blog handlers into blog.rs * gallery index * gallery posts * fix hashtags * remove instantpage (it messes up the metrics) * talk support + prometheus * Create rust.yml * Update rust.yml * Update codeql-analysis.yml * add jsonfeed library * jsonfeed support * rss/atom * go mod tidy * atom: add posted date * rss: add publishing date * nix: build rust program * rip out go code * rip out go templates * prepare for serving in docker * create kubernetes deployment * create automagic deployment * build docker images on non-master * more fixes * fix timestamps * fix RSS/Atom/JSONFeed validation errors * add go vanity import redirecting * templates/header: remove this * atom feed: fixes * fix? * fix?? * fix rust tests * Update rust.yml * automatically show snow during the winter * fix dates * show commit link in footer * sitemap support * fix compiler warning * start basic patreon client * integrate kankyo * fix patreon client * add patrons page * remove this * handle patron errors better * fix build * clean up deploy * sort envvars for deploy * remove deps.nix * shell.nix: remove go * update README * fix envvars for tests * nice * blog: add rewrite in rust post * blog/site-update: more words
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..aa5400e
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,154 @@
+use anyhow::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<()> {
+ let _ = kankyo::init();
+ pretty_env_logger::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"));