Atom feed, GUID for RSS feed
This commit is contained in:
1 parent
aa06d2c5ef
commit
1b4be0862c
13 files changed
+276
-60
No files matched your search
@@ -0,0 +1,82 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use atom_syndication as atom;
|
||||
use axum::{
|
||||
body::Bytes,
|
||||
extract::Extension,
|
||||
};
|
||||
|
||||
use super::response::Atom;
|
||||
use crate::{
|
||||
Config,
|
||||
posts_store::ConcurrentPostsStore,
|
||||
time::unix_epoch,
|
||||
};
|
||||
|
||||
pub async fn handle(
|
||||
Extension(config): Extension<Arc<Config>>,
|
||||
Extension(posts): Extension<ConcurrentPostsStore>,
|
||||
) -> Atom<Bytes> {
|
||||
let (atom_entries, updated) = {
|
||||
let guard = posts.read().await;
|
||||
|
||||
let atom_entries = guard.iter_by_created()
|
||||
.take(config.atom.num_posts)
|
||||
.map(|post| {
|
||||
atom::EntryBuilder::default()
|
||||
.id(format!("urn:uuid:{}", post.uuid()))
|
||||
.title(post.title().to_owned())
|
||||
.updated(post.updated())
|
||||
.links(vec![
|
||||
atom::LinkBuilder::default()
|
||||
.href(format!(
|
||||
"{}://{}/articles/{}",
|
||||
config.self_ref.protocol,
|
||||
config.self_ref.domain,
|
||||
post.id()
|
||||
))
|
||||
.rel("alternate".to_owned())
|
||||
.mime_type(Some("text/html".to_owned()))
|
||||
.build()
|
||||
])
|
||||
.author(atom::PersonBuilder::default()
|
||||
.name(post.author().to_owned())
|
||||
.build())
|
||||
.build()
|
||||
})
|
||||
.collect::<Vec<atom::Entry>>();
|
||||
|
||||
let updated = guard.last_updated()
|
||||
.unwrap_or_else(unix_epoch);
|
||||
|
||||
(atom_entries, updated)
|
||||
};
|
||||
|
||||
Atom(atom::FeedBuilder::default()
|
||||
.id(format!("urn:uuid:{}", *config.namespace_uuid))
|
||||
.title(config.atom.title.clone())
|
||||
.updated(updated)
|
||||
.links(vec![
|
||||
atom::LinkBuilder::default()
|
||||
.href(format!(
|
||||
"{}://{}/atom.xml",
|
||||
config.self_ref.protocol,
|
||||
config.self_ref.domain
|
||||
))
|
||||
.rel("self".to_owned())
|
||||
.build(),
|
||||
atom::LinkBuilder::default()
|
||||
.href(format!(
|
||||
"{}://{}/articles/",
|
||||
config.self_ref.protocol,
|
||||
config.self_ref.domain
|
||||
))
|
||||
.rel("alternate".to_owned())
|
||||
.mime_type(Some("text/html".to_owned()))
|
||||
.build()
|
||||
])
|
||||
.entries(atom_entries)
|
||||
.build()
|
||||
.to_string()
|
||||
.into())
|
||||
}
|
||||
@@ -43,7 +43,7 @@ pub async fn handle(Extension(posts): Extension<ConcurrentPostsStore>) -> Html {
|
||||
ul {
|
||||
@for post in posts.read().await.iter_by_created().rev().take(5) {
|
||||
li {
|
||||
a href={"/articles/" (post.id_str())} { (post.title()) }
|
||||
a href={"/articles/" (post.id())} { (post.title()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod atom;
|
||||
mod contact;
|
||||
mod index;
|
||||
mod post;
|
||||
|
||||
@@ -23,7 +23,7 @@ pub async fn handle(Extension(posts): Extension<ConcurrentPostsStore>) -> Html {
|
||||
ul {
|
||||
@for post in posts.read().await.iter_by_created().rev() {
|
||||
li {
|
||||
a href={"/articles/" (post.id_str())} { (post.title()) }
|
||||
a href={"/articles/" (post.id())} { (post.title()) }
|
||||
span class="quiet" {
|
||||
" — " (post.created().format("%Y/%m/%d"))
|
||||
}
|
||||
|
||||
@@ -6,37 +6,53 @@ use axum::{
|
||||
};
|
||||
|
||||
use super::response::Rss;
|
||||
use crate::{posts_store::ConcurrentPostsStore, Config};
|
||||
use crate::{
|
||||
Config,
|
||||
posts_store::ConcurrentPostsStore,
|
||||
time::unix_epoch,
|
||||
};
|
||||
|
||||
pub async fn handle(
|
||||
Extension(config): Extension<Arc<Config>>,
|
||||
Extension(posts): Extension<ConcurrentPostsStore>,
|
||||
) -> Rss<Bytes> {
|
||||
let rss_items = posts.read()
|
||||
.await
|
||||
.iter_by_created()
|
||||
.take(config.rss.num_posts)
|
||||
.map(|post| {
|
||||
rss::ItemBuilder::default()
|
||||
.title(Some(post.title().to_owned()))
|
||||
.link(Some(format!(
|
||||
"{}://{}/articles/{}",
|
||||
config.rss.protocol,
|
||||
config.rss.domain,
|
||||
post.id()
|
||||
)))
|
||||
.pub_date(Some(post.created().to_rfc2822()))
|
||||
.build()
|
||||
})
|
||||
.collect::<Vec<rss::Item>>();
|
||||
let (rss_items, updated) = {
|
||||
let guard = posts.read().await;
|
||||
|
||||
let rss_items = guard.iter_by_created()
|
||||
.take(config.rss.num_posts)
|
||||
.map(|post| {
|
||||
rss::ItemBuilder::default()
|
||||
.title(Some(post.title().to_owned()))
|
||||
.guid(Some(rss::GuidBuilder::default()
|
||||
.value(post.uuid().to_string())
|
||||
.permalink(false)
|
||||
.build()))
|
||||
.link(Some(format!(
|
||||
"{}://{}/articles/{}",
|
||||
config.self_ref.protocol,
|
||||
config.self_ref.domain,
|
||||
post.id()
|
||||
)))
|
||||
.pub_date(Some(post.created().to_rfc2822()))
|
||||
.build()
|
||||
})
|
||||
.collect::<Vec<rss::Item>>();
|
||||
|
||||
let updated = guard.last_updated()
|
||||
.unwrap_or_else(unix_epoch);
|
||||
|
||||
(rss_items, updated)
|
||||
};
|
||||
|
||||
Rss(rss::ChannelBuilder::default()
|
||||
.title(config.rss.title.clone())
|
||||
.link(format!(
|
||||
"{}://{}",
|
||||
config.rss.protocol, config.rss.domain
|
||||
config.self_ref.protocol, config.self_ref.domain
|
||||
))
|
||||
.ttl(Some(config.rss.ttl.to_string()))
|
||||
.last_build_date(Some(updated.to_rfc2822()))
|
||||
.items(rss_items)
|
||||
.build()
|
||||
.to_string()
|
||||
|
||||
@@ -16,6 +16,7 @@ use crate::{
|
||||
posts_store::ConcurrentPostsStore
|
||||
};
|
||||
use super::{
|
||||
atom,
|
||||
contact,
|
||||
index,
|
||||
post,
|
||||
@@ -26,13 +27,14 @@ use super::{
|
||||
};
|
||||
|
||||
pub fn service(
|
||||
config: Config,
|
||||
config: Arc<Config>,
|
||||
posts_store: ConcurrentPostsStore,
|
||||
) -> Router
|
||||
{
|
||||
Router::new()
|
||||
.route("/", get(index::handle))
|
||||
.route("/rss.xml", get(rss::handle))
|
||||
.route("/atom.xml", get(atom::handle))
|
||||
.route("/contact", get(contact::handle))
|
||||
.route("/articles", get(posts_list::handle))
|
||||
.route("/articles/:post_id", get(post::handle))
|
||||
@@ -40,7 +42,7 @@ pub fn service(
|
||||
.fallback(handle_fallback.into_service())
|
||||
.layer(ConcurrencyLimitLayer::new(config.concurrency_limit))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
.layer(Extension(Arc::new(config)))
|
||||
.layer(Extension(config))
|
||||
.layer(Extension(posts_store))
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user