1
0
Fork 0

Even more stuff

This commit is contained in:
Adrian Hedqvist 2023-03-25 22:12:49 +01:00
parent 3189b57a46
commit d076f92764
6 changed files with 205 additions and 73 deletions

119
Cargo.lock generated
View file

@ -393,9 +393,9 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.93"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038"
checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93"
dependencies = [
"cc",
"cxxbridge-flags",
@ -405,9 +405,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.93"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca"
checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b"
dependencies = [
"cc",
"codespan-reporting",
@ -420,15 +420,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.93"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31"
checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb"
[[package]]
name = "cxxbridge-macro"
version = "1.0.93"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f"
checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
dependencies = [
"proc-macro2",
"quote",
@ -486,6 +486,27 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "eyre"
version = "0.6.8"
@ -699,6 +720,18 @@ dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "http"
version = "0.2.9"
@ -844,6 +877,17 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "io-lifetimes"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
dependencies = [
"hermit-abi 0.3.1",
"libc",
"windows-sys",
]
[[package]]
name = "iri-string"
version = "0.7.0"
@ -905,6 +949,12 @@ dependencies = [
"cc",
]
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
version = "0.4.9"
@ -1008,7 +1058,7 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi",
"hermit-abi 0.2.6",
"libc",
]
@ -1213,6 +1263,42 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "procfs"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1de8dacb0873f77e6aefc6d71e044761fcc68060290f5b1089fcdf84626bb69"
dependencies = [
"bitflags",
"byteorder",
"hex",
"lazy_static",
"rustix",
]
[[package]]
name = "prometheus"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c"
dependencies = [
"cfg-if",
"fnv",
"lazy_static",
"libc",
"memchr",
"parking_lot",
"procfs",
"protobuf",
"thiserror",
]
[[package]]
name = "protobuf"
version = "2.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
[[package]]
name = "pulldown-cmark"
version = "0.9.2"
@ -1296,6 +1382,20 @@ version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b"
[[package]]
name = "rustix"
version = "0.36.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.12"
@ -1993,6 +2093,7 @@ dependencies = [
"glob",
"hyper",
"lazy_static",
"prometheus",
"pulldown-cmark",
"regex",
"serde",

View file

@ -15,6 +15,7 @@ glob = "0.3.0"
#grass = { version = "0.12.3", features = ["random"] } # not really needed yet
hyper = { version = "0.14.19", features = ["full"] }
lazy_static = "1.4.0"
prometheus = { version = "0.13.3", features = ["process"] }
pulldown-cmark = "0.9.2"
regex = "1.7.2"
serde = "1.0.144"

View file

@ -1,21 +1,32 @@
use hyper::StatusCode;
use std::sync::Arc;
use tracing::{instrument, log::*};
use axum::{
response::{Html, IntoResponse, Response},
Extension,
};
use hyper::StatusCode;
use lazy_static::lazy_static;
use prometheus::{opts, IntCounterVec};
use std::sync::Arc;
use tracing::{instrument, log::*};
use crate::{State, WebsiteError};
pub mod posts;
lazy_static! {
pub static ref HIT_COUNTER: IntCounterVec =
prometheus::register_int_counter_vec!(opts!("hits", "page hits"), &["page"]).unwrap();
}
#[instrument(skip(state))]
pub async fn index(Extension(state): Extension<Arc<State>>) -> std::result::Result<Html<Vec<u8>>, WebsiteError> {
pub async fn index(
Extension(state): Extension<Arc<State>>,
) -> std::result::Result<Html<Vec<u8>>, WebsiteError> {
let ctx = tera::Context::new();
let res = state.tera.render("index.html", &ctx).map_err(|e| {
error!("Failed rendering index: {}", e);
WebsiteError::NotFound
})?;
HIT_COUNTER.with_label_values(&["/"]);
Ok(Html(res.into()))
}

66
src/handlers/posts.rs Normal file
View file

@ -0,0 +1,66 @@
use std::sync::Arc;
use axum::{extract::Path, response::Html, routing::get, Extension, Router};
use serde_derive::Serialize;
use tracing::{instrument, log::*};
use crate::{
post::{render_post, Post},
State, WebsiteError,
};
use super::HIT_COUNTER;
pub fn router() -> Router {
Router::new()
.route("/", get(index))
.route("/:slug/", get(view))
.fallback_service(tower_http::services::ServeDir::new("./posts"))
}
#[instrument(skip(state))]
pub async fn view(
Path(slug): Path<String>,
Extension(state): Extension<Arc<State>>,
) -> Result<Html<String>, WebsiteError> {
debug!("viewing post: {slug}");
let post = state.posts.get(&slug).ok_or(WebsiteError::NotFound)?;
let res = render_post(&state.tera, post).await?;
HIT_COUNTER.with_label_values(&[&format!("/posts/{}/", slug)]);
Ok(Html(res))
}
#[derive(Serialize)]
struct IndexContext<'a> {
title: &'a str,
posts: Vec<&'a Post>,
}
#[instrument(skip(state))]
pub async fn index(Extension(state): Extension<Arc<State>>) -> Result<Html<String>, WebsiteError> {
let mut posts = state.posts.values().collect::<Vec<&Post>>();
posts.sort_by_key(|p| &p.date);
posts.reverse();
let ctx = IndexContext {
title: "Posts",
posts,
};
let res = match state
.tera
.render("posts_index.html", &tera::Context::from_serialize(ctx)?)
{
Ok(r) => r,
Err(e) => {
error!("failed to render posts index: {}", e);
return Err(e.into());
}
};
HIT_COUNTER.with_label_values(&["/posts/"]);
Ok(Html(res))
}

View file

@ -46,10 +46,7 @@ pub async fn init_app() -> Result<Router> {
let app = Router::new()
.route("/", get(handlers::index))
.nest(
"/posts",
post::router(),
)
.nest("/posts", handlers::posts::router())
.nest_service("/static", tower_http::services::ServeDir::new("./static"))
.route("/.healthcheck", get(healthcheck))
.layer(middleware);

View file

@ -1,6 +1,5 @@
use std::{collections::HashMap, path::Path, sync::Arc};
use std::{collections::HashMap, path::Path};
use axum::{response::Html, routing::get, Extension, Router, extract};
use chrono::{DateTime, FixedOffset};
use glob::glob;
@ -12,7 +11,7 @@ use tokio::fs;
use tracing::{instrument, log::*};
use crate::{State, WebsiteError};
use crate::WebsiteError;
#[derive(Deserialize, Debug, Default)]
pub struct TomlFrontMatter {
@ -41,7 +40,9 @@ impl Post {
slug,
content,
title: fm.title,
date: fm.date.map(|d| DateTime::parse_from_rfc3339(&d.to_string()).expect("bad toml datetime")),
date: fm
.date
.map(|d| DateTime::parse_from_rfc3339(&d.to_string()).expect("bad toml datetime")),
aliases: fm.aliases.unwrap_or_default(),
tags: fm.tags.unwrap_or_default(),
}
@ -96,7 +97,11 @@ pub async fn load_post(slug: &str) -> color_eyre::eyre::Result<Post> {
content_html
});
Ok(Post::new(slug.to_string(), content.unwrap_or_default(), tomlfm))
Ok(Post::new(
slug.to_string(),
content.unwrap_or_default(),
tomlfm,
))
}
#[instrument]
@ -121,62 +126,13 @@ fn parse_frontmatter(
}
#[instrument(skip(tera, post))]
async fn render_post(tera: &tera::Tera, post: &Post) -> Result<String, WebsiteError> {
pub async fn render_post(tera: &tera::Tera, post: &Post) -> Result<String, WebsiteError> {
let mut ctx = tera::Context::new();
ctx.insert("page", &post);
tera.render("post.html", &ctx).map_err(|e| e.into())
}
pub fn router() -> Router
{
Router::new()
.route("/", get(index))
.route("/:slug/", get(view))
.fallback_service(tower_http::services::ServeDir::new("./posts"))
}
#[instrument(skip(state))]
pub async fn view(
extract::Path(slug): extract::Path<String>,
Extension(state): Extension<Arc<State>>,
) -> Result<Html<String>, WebsiteError> {
debug!("viewing post: {slug}");
let post = state
.posts
.get(&slug)
.ok_or(WebsiteError::NotFound)?;
let res = render_post(&state.tera, post).await?;
Ok(Html(res))
}
#[instrument(skip(state))]
pub async fn index(
Extension(state): Extension<Arc<State>>,
) -> Result<Html<String>, WebsiteError> {
let mut ctx = tera::Context::new();
let mut posts = state.posts.values().collect::<Vec<&Post>>();
posts.sort_by_key(|p| &p.date);
posts.reverse();
ctx.insert("page.title", "Posts");
ctx.insert("posts", &posts);
let res = match state.tera.render("posts_index.html", &ctx) {
Ok(r) => r,
Err(e) => {
error!("failed to render posts index: {}", e);
return Err(e.into());
}
};
Ok(Html(res))
}
#[cfg(test)]
mod tests {
use tera::Tera;