diff --git a/Cargo.lock b/Cargo.lock index a045b3b..f535fca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,9 +353,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -514,13 +514,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -674,9 +674,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -856,9 +856,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -928,13 +928,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -979,9 +979,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "libm" @@ -1078,7 +1078,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1213,7 +1213,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1360,9 +1360,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1497,16 +1497,16 @@ checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" [[package]] name = "rustix" -version = "0.36.11" +version = "0.36.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +checksum = "e0af200a3324fa5bcd922e84e9b55a298ea9f431a489f01961acdebc6e908f25" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1794,7 +1794,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2119,9 +2119,9 @@ checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "uuid" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "5b55a3fef2a1e3b3a00ce878640918820d3c51081576ac657d23af9fc7928fdb" dependencies = [ "getrandom", ] @@ -2285,11 +2285,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.46.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", ] [[package]] @@ -2298,7 +2298,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] @@ -2307,13 +2316,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -2322,42 +2346,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winnow" version = "0.4.1" @@ -2388,9 +2454,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.7+zstd.1.5.4" +version = "2.0.8+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" dependencies = [ "cc", "libc", diff --git a/src/feed.rs b/src/feed.rs index e111e12..b8f07af 100644 --- a/src/feed.rs +++ b/src/feed.rs @@ -3,43 +3,62 @@ use serde_derive::Serialize; use tera::Tera; use tracing::instrument; -use crate::{post::Post, tag::Tag}; +use crate::{post::Post, tag::Tag, AppState}; #[derive(Serialize)] struct FeedContext<'a> { feed_url: &'a str, + base_url: &'a str, last_updated: &'a str, tag: Option<&'a Tag>, posts: &'a [&'a Post], } -#[instrument(skip(posts, tera))] -pub fn render_atom_feed(posts: &[&Post], tera: &Tera) -> Result { +#[instrument(skip(state))] +pub fn render_atom_feed(state: &AppState) -> Result { + let mut posts: Vec<_> = state.posts.values().filter(|p| p.is_published()).collect(); + + posts.sort_by_key(|p| &p.date); + posts.reverse(); + posts.truncate(10); + let updated = posts.iter().map(|p| p.updated.or(p.date)).max().flatten(); let feed = FeedContext { - feed_url: "https://tollyx.net/atom.xml", + feed_url: &format!("{}/atom.xml", state.base_url), + base_url: &state.base_url, last_updated: &updated.map_or_else(String::default, |d| d.to_rfc3339()), tag: None, - posts, + posts: &posts, }; let ctx = tera::Context::from_serialize(&feed)?; - Ok(tera.render("atom.xml", &ctx)?) + Ok(state.tera.render("atom.xml", &ctx)?) } -#[instrument(skip(tag, posts, tera))] -pub fn render_atom_tag_feed(tag: &Tag, posts: &[&Post], tera: &Tera) -> Result { +#[instrument(skip(tag, state))] +pub fn render_atom_tag_feed(tag: &Tag, state: &AppState) -> Result { + let mut posts: Vec<_> = state + .posts + .values() + .filter(|p| p.is_published() && p.tags.contains(&tag.slug)) + .collect(); + + posts.sort_by_key(|p| &p.date); + posts.reverse(); + posts.truncate(10); + let updated = posts.iter().map(|p| p.updated.or(p.date)).max().flatten(); let slug = &tag.slug; let feed = FeedContext { - feed_url: &format!("https://tollyx.net/tags/{slug}/atom.xml"), + feed_url: &format!("{}/tags/{}/atom.xml", state.base_url, slug), + base_url: &state.base_url, last_updated: &updated.map_or_else(String::default, |d| d.to_rfc3339()), tag: Some(tag), - posts, + posts: &posts, }; let ctx = tera::Context::from_serialize(&feed)?; - Ok(tera.render("atom.xml", &ctx)?) + Ok(state.tera.render("atom.xml", &ctx)?) } diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 77fb197..737700e 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -92,6 +92,10 @@ pub async fn metrics_middleware(request: Request, next: Next) -> Respon HIT_COUNTER .with_label_values(&[&path, &method, response.status().as_str()]) .inc(); + } else if response.status() == StatusCode::NOT_FOUND { + HIT_COUNTER + .with_label_values(&["not found", &method, response.status().as_str()]) + .inc(); } response @@ -105,7 +109,11 @@ impl IntoResponse for WebsiteError { (StatusCode::NOT_FOUND, ()).into_response() } WebsiteError::InternalError(e) => { - error!("internal error: {e}"); + if let Some(s) = e.source() { + error!("internal error: {}: {}", e, s); + } else { + error!("internal error: {}", e); + } (StatusCode::INTERNAL_SERVER_ERROR, ()).into_response() } } diff --git a/src/handlers/posts.rs b/src/handlers/posts.rs index 3b5ce9d..d660e82 100644 --- a/src/handlers/posts.rs +++ b/src/handlers/posts.rs @@ -60,6 +60,7 @@ pub async fn index(State(state): State>) -> Result, W let mut c = tera::Context::new(); c.insert("page", &ctx); c.insert("posts", &posts); + c.insert("base_url", &state.base_url); let res = state.tera.render("posts_index.html", &c)?; @@ -77,7 +78,7 @@ pub async fn view( return Err(WebsiteError::NotFound); } - let res = render_post(&state.tera, post).await?; + let res = render_post(&state, post).await?; Ok(Html(res)) } @@ -92,7 +93,7 @@ pub async fn feed(State(state): State>) -> Result, @@ -52,9 +53,9 @@ async fn main() -> Result<()> { .make_span_with(make_span) .on_response(on_response), ) - .with_state(state); + .with_state(state.clone()); - info!("Now listening at http://localhost:8180"); + info!("Now listening at {}", state.base_url); axum::Server::bind(&"0.0.0.0:8180".parse().unwrap()) .serve(app.into_make_service()) @@ -107,11 +108,32 @@ pub enum WebsiteError { InternalError(Error), } -impl From for WebsiteError -where - E: Into, -{ - fn from(value: E) -> Self { +impl std::error::Error for WebsiteError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + WebsiteError::NotFound => None, + WebsiteError::InternalError(e) => Some(e.as_ref()), + } + } +} + +impl Display for WebsiteError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + WebsiteError::NotFound => write!(f, "Not found"), + _ => write!(f, "Internal error"), + } + } +} + +impl From for WebsiteError { + fn from(value: tera::Error) -> Self { WebsiteError::InternalError(value.into()) } } + +impl From for WebsiteError { + fn from(value: color_eyre::Report) -> Self { + WebsiteError::InternalError(value) + } +} diff --git a/src/post.rs b/src/post.rs index ce6d4d6..47e1b06 100644 --- a/src/post.rs +++ b/src/post.rs @@ -11,7 +11,7 @@ use tokio::fs; use tracing::{instrument, log::*}; -use crate::WebsiteError; +use crate::{AppState, WebsiteError}; #[derive(Deserialize, Debug, Default)] pub struct TomlFrontMatter { @@ -138,25 +138,31 @@ fn parse_frontmatter( }) } -#[instrument(skip(tera, post))] -pub async fn render_post(tera: &tera::Tera, post: &Post) -> Result { +#[instrument(skip(state, post))] +pub async fn render_post(state: &AppState, post: &Post) -> Result { let mut ctx = tera::Context::new(); ctx.insert("page", &post); + ctx.insert("base_url", &state.base_url); - tera.render("post.html", &ctx).map_err(|e| e.into()) + state.tera.render("post.html", &ctx).map_err(|e| e.into()) } #[cfg(test)] mod tests { use tera::Tera; + use crate::AppState; + #[tokio::test] async fn render_all_posts() { - let tera = Tera::new("templates/**/*").unwrap(); - let posts = super::load_all().await.unwrap(); - - for (_slug, post) in posts { - super::render_post(&tera, &post).await.unwrap(); + let state = AppState { + base_url: "localhost:8180".into(), + posts: super::load_all().await.unwrap(), + tera: Tera::new("templates/**/*").unwrap(), + ..Default::default() + }; + for post in state.posts.values() { + super::render_post(&state, post).await.unwrap(); } } } diff --git a/templates/atom.xml b/templates/atom.xml index bec96eb..0cd0708 100644 --- a/templates/atom.xml +++ b/templates/atom.xml @@ -6,11 +6,11 @@ tollyx's corner of the web {% if tag -%} - + {%- else -%} - + {%- endif %} - tollyx-website + tollyx-website {{ last_updated | date(format="%+") }} {{ feed_url | safe }} {%- for post in posts %} @@ -21,7 +21,7 @@ tollyx - + {{ post.slug | safe }} {{ post.content }} diff --git a/templates/partials/head.html b/templates/partials/head.html index b9d49fe..387f686 100644 --- a/templates/partials/head.html +++ b/templates/partials/head.html @@ -2,9 +2,9 @@ - + {% if tag_slug -%} - + {%- endif %} @@ -17,14 +17,14 @@ {%- else -%} {%- endif %} - + {% if page.title -%} - {{ page.title }} | tollyx.net + {{ page.title }} | tollyx.net {%- else -%} - tollyx.net + tollyx.net {%- endif %} \ No newline at end of file