diff --git a/Cargo.lock b/Cargo.lock index 7301ef5..9b7c7c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,20 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", +] + +[[package]] +name = "atom_syndication" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571832dcff775e26562e8e6930cd483de5587301d40d3a3b85d532b6383e15a7" +dependencies = [ + "chrono", + "derive_builder", + "diligent-date-parser", + "never", + "quick-xml", ] [[package]] @@ -198,7 +211,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -330,7 +343,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -351,6 +364,81 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "diligent-date-parser" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6cf7fe294274a222363f84bcb63cdea762979a0443b4cf1f4f8fd17c86b1182" +dependencies = [ + "chrono", +] + [[package]] name = "either" version = "1.9.0" @@ -372,7 +460,16 @@ source = "git+https://github.com/RGBCube/embed-rs#7c2eb614db7947d5f12c02685c9740 dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", ] [[package]] @@ -632,6 +729,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "indexmap" version = "2.1.0" @@ -739,7 +842,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -795,6 +898,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "never" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" + [[package]] name = "num-traits" version = "0.2.17" @@ -888,7 +997,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -946,6 +1055,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "encoding_rs", + "memchr", +] + [[package]] name = "quote" version = "1.0.35" @@ -993,6 +1112,18 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rss" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b2c77eb4450d7d5f98df52c381cd6c4e19b75dad9209a9530b85a44510219a" +dependencies = [ + "atom_syndication", + "derive_builder", + "never", + "quick-xml", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1047,7 +1178,7 @@ checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -1134,6 +1265,7 @@ dependencies = [ "mime_guess", "minify-js", "pulldown-cmark", + "rss", "serde", "serde_yaml", "tokio", @@ -1172,6 +1304,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.48" @@ -1225,7 +1368,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -1408,7 +1551,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1430,7 +1573,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1639,5 +1782,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] diff --git a/Cargo.toml b/Cargo.toml index c13dcea..031f4a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ maud = { git = "https://github.com/lambda-fairy/maud", features = [ "a mime_guess = "2.0.4" minify-js = "0.6.0" pulldown-cmark = "0.9.3" +rss = "2.0.7" serde = { version = "1.0.195", features = [ "derive" ] } serde_yaml = "0.9.30" tokio = { version = "1.35.1", features = [ "full" ] } diff --git a/src/page/text/mod.rs b/src/page/text/mod.rs index 7c93e9a..1a0b77a 100644 --- a/src/page/text/mod.rs +++ b/src/page/text/mod.rs @@ -1,6 +1,6 @@ use chrono::{ Datelike, - Local, + Utc, }; use maud::{ html, @@ -39,7 +39,7 @@ pub fn create(title: Option<&str>, page: Page, body: &Markup) -> Markup { footer { "Copyright © " - (Local::now().year()) + (Utc::now().year()) " RGBCube" } } diff --git a/src/routes/blog.rs b/src/routes/blog.rs index 0526ed4..e17030c 100644 --- a/src/routes/blog.rs +++ b/src/routes/blog.rs @@ -3,15 +3,28 @@ use std::sync::LazyLock; use axum::{ body::Body, extract::Path, - http::Response, + http::{ + header::CONTENT_TYPE, + Response, + }, response::IntoResponse, }; +use bytes::Bytes; +use chrono::{ + Datelike, + Utc, +}; use indexmap::IndexMap; use itertools::Itertools; use maud::{ html, Markup, }; +use rss::{ + CategoryBuilder, + ChannelBuilder, + ItemBuilder, +}; use super::markdown::{ Metadata, @@ -22,6 +35,7 @@ use crate::{ page::{ text, Page, + MANIFEST, }, }; @@ -82,3 +96,47 @@ pub async fn entry_handler(Path(entry): Path) -> Response { not_found::handler().await.into_response() } } + +static FEED: LazyLock = LazyLock::new(|| { + let url = MANIFEST.package.as_ref().unwrap().homepage().unwrap(); + + let items = ENTRIES.iter().map(|(path, (metadata, body))| { + ItemBuilder::default() + .link(Some(format!("{url}{path}"))) + .title(Some(metadata.title.clone())) + .description(metadata.description.clone()) + .author(Some("contact@rgbcu.be".to_string())) + .categories( + metadata + .tags + .as_ref() + .unwrap() + .iter() + .map(|tag| CategoryBuilder::default().name(tag.clone()).build()) + .collect_vec(), + ) + .pub_date(metadata.date.map(|date| date.to_rfc2822())) + .content(Some(body.clone().into_string())) + .build() + }); + + let channel = ChannelBuilder::default() + .title("RGBCube's Blog".to_string()) + .link(format!("{url}blog")) + .description( + "The webpage where RGBCube puts his schizophrenic rambling about software and all the \ + likes" + .to_string(), + ) + .copyright(Some(format!("Copyright © {} RGBCube", Utc::now().year()))) + .language(Some("en-us".to_string())) + .webmaster(Some("contact@rgbcu.be".to_string())) + .items(items.collect_vec()) + .build(); + + Bytes::from(channel.to_string().into_bytes()) +}); + +pub async fn feed_handler() -> impl IntoResponse { + ([(CONTENT_TYPE, "application/xml")], Bytes::clone(&*FEED)) +} diff --git a/src/routes/markdown.rs b/src/routes/markdown.rs index dd9291f..0e67609 100644 --- a/src/routes/markdown.rs +++ b/src/routes/markdown.rs @@ -3,7 +3,10 @@ use std::{ sync::LazyLock, }; -use chrono::NaiveDate; +use chrono::{ + DateTime, + Utc, +}; use maud::Markup; use serde::Deserialize; @@ -12,7 +15,8 @@ use crate::markdown; #[derive(Deserialize, Debug)] pub struct Metadata { pub title: String, - pub date: Option, + pub description: Option, + pub date: Option>, pub tags: Option>, } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index f6c4dcc..97cc7a4 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -13,5 +13,6 @@ pub fn router() -> Router { .route("/", get(index::handler)) .route("/blog", get(blog::index_handler)) .route("/blog/:entry", get(blog::entry_handler)) + .route("/feed", get(blog::feed_handler)) .route("/*path", get(assets::handler)) }