Compare commits

...

2 commits

Author SHA1 Message Date
Gabriel Simmer dcba9beba2
rss content type
Some checks failed
Fly Deploy / Deploy app (push) Failing after 54s
2023-09-22 11:33:56 +01:00
Gabriel Simmer 8761b57f80
Add /rss endpoint 2023-09-22 11:31:49 +01:00
3 changed files with 193 additions and 2 deletions

132
Cargo.lock generated
View file

@ -199,6 +199,19 @@ dependencies = [
"num-traits",
]
[[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]]
name = "atty"
version = "0.2.14"
@ -377,6 +390,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"num-traits",
]
[[package]]
name = "clap"
version = "2.34.0"
@ -543,6 +565,41 @@ dependencies = [
"typenum",
]
[[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 0.10.0",
"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 = "der"
version = "0.7.8"
@ -554,6 +611,37 @@ dependencies = [
"zeroize",
]
[[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 = "dhall"
version = "0.12.0"
@ -603,6 +691,15 @@ dependencies = [
"subtle",
]
[[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 = "doc-comment"
version = "0.3.3"
@ -1086,6 +1183,12 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.4.0"
@ -1371,6 +1474,12 @@ dependencies = [
"tempfile",
]
[[package]]
name = "never"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
[[package]]
name = "nom"
version = "7.1.3"
@ -1749,6 +1858,7 @@ dependencies = [
"lazy_static 1.4.0",
"maud",
"orgize",
"rss",
"serde",
"serde_dhall",
"sha2",
@ -1758,6 +1868,16 @@ dependencies = [
"tower-http",
]
[[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.32"
@ -1902,6 +2022,18 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rss"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e6c0ea0e621c2a3aa34850ebd711526f0ac7385921f57d2430a47cecc7b9cbc"
dependencies = [
"atom_syndication",
"derive_builder",
"never",
"quick-xml",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"

View file

@ -24,3 +24,4 @@ clap = { version = "4.0", features = ["derive"] }
serde_dhall = "0.12.1"
frontmatter = "0.4.0"
file-format = "0.18.0"
rss = "2.0.6"

View file

@ -27,6 +27,7 @@ use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::Mutex;
use tower_http::services::ServeDir;
use rss::ChannelBuilder;
lazy_static! {
static ref CACHE: Mutex<HashMap<String, CachedPage>> = Mutex::new(HashMap::new());
@ -107,6 +108,7 @@ async fn main() -> Result<(), sqlx::Error> {
let app = Router::new()
.route("/", get(homepage))
.route("/rss", get(rss))
.route("/blog", get(list_blog_posts))
.route("/blog/:post", get(blog_post))
.nest_service("/assets", ServeDir::new("assets"))
@ -123,6 +125,63 @@ async fn main() -> Result<(), sqlx::Error> {
Ok(())
}
async fn rss() -> Result<impl IntoResponse, StatusCode> {
let mut posts: Vec<rss::Item> = Vec::new();
for entry in fs::read_dir("./posts").unwrap() {
let entry = entry.unwrap();
let path = entry.path();
let filename = path.file_name().unwrap().to_str().unwrap();
let ext = path.extension().unwrap().to_str().unwrap();
// strip extension
let fname = filename.replace(&format!(".{}", ext), "");
if ext == "md" || ext == "org" {
// We'll have the date at the beginning of the file
let mut content = File::open(&path).unwrap();
let mut buffer = [0; 100];
content.read(&mut buffer).unwrap();
// Match date data of `date: YYYY-MM-DD` in the first 100 bytes
let metadata = String::from_utf8_lossy(&buffer);
let metadata_lines = metadata.split("\n").collect::<Vec<&str>>();
// dbg!(&metadata);
// Split by --- and get the second element
let date = metadata_lines
.iter()
.find(|&x| x.contains("date:"))
.unwrap_or(&"")
.split(":")
.collect::<Vec<&str>>()[1];
let title = metadata_lines
.iter()
.find(|&x| x.contains("title:"))
.unwrap_or(&"")
.split(":")
.collect::<Vec<&str>>()[1];
let date = date.trim();
dbg!(&date);
let item = rss::ItemBuilder::default()
.title(Some(title.to_owned()))
.link(Some(format!("https://gabrielsimmer.com/blog/{}", fname)))
.pub_date(Some(date.to_owned()))
.build();
posts.push(item);
}
}
let channel = ChannelBuilder::default()
.title("Gabriel Simmer's Blog".to_owned())
.link("https://gabrielsimmer.com/blog".to_owned())
.description("Gabriel Simmer's Blog Posts.".to_owned())
.items(posts)
.build();
return Ok(Response::builder()
.header("content-type", "application/rss+xml")
.status(StatusCode::OK)
.body(Full::from(channel.to_string()))
.unwrap());
}
fn header(page_title: &str) -> Markup {
html! {
(DOCTYPE)
@ -273,7 +332,6 @@ async fn blog_post(Path(post): Path<String>) -> Result<impl IntoResponse, Status
return Ok(Response::builder()
.header("content-type", "text/html")
.header("cache", "hit")
.status(StatusCode::OK)
.body(Full::from(html.into_string()))
.unwrap());