From 9d497f0aaf0f54268d86a2f15abad7789fe33b80 Mon Sep 17 00:00:00 2001 From: Jacob Babich Date: Wed, 29 Nov 2023 13:30:51 -0500 Subject: [PATCH] implement an Atom RSS feed --- Cargo.lock | 2 ++ Cargo.toml | 6 ++-- src/routes/notifications/mod.rs | 57 ++++++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74bff86..f6997a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,7 +184,9 @@ version = "0.1.0" dependencies = [ "atom_syndication", "axum", + "bytes", "error-stack", + "mime", "redb", "serde", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 01ef8c8..33ca823 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,11 @@ version = "0.1.0" edition = "2021" [dependencies] -atom_syndication = "0.12.2" -axum = { version = "0.7.1", default-features = false, features = ["json", "tokio", "http2"] } +atom_syndication = { version = "0.12.2" } +axum = { version = "0.7.1", default-features = false, features = ["json", "tokio", "http2", "http1"] } +bytes = "1.5.0" error-stack = "0.4.1" +mime = "0.3.17" redb = "1.4.0" serde = { version = "1.0.193", features = ["derive"] } thiserror = "1.0.50" diff --git a/src/routes/notifications/mod.rs b/src/routes/notifications/mod.rs index 68d0101..7feab90 100644 --- a/src/routes/notifications/mod.rs +++ b/src/routes/notifications/mod.rs @@ -1,13 +1,60 @@ -use axum::{extract::State, response::IntoResponse, Router}; +use atom_syndication::{Feed, FeedBuilder}; +use axum::{ + extract::State, + http::{header, HeaderValue, StatusCode}, + response::{IntoResponse, Response}, + Router, +}; +use bytes::{BufMut, BytesMut}; use crate::AppState; -#[tracing::instrument(level = "trace")] -async fn get(state: State) -> impl IntoResponse { - "Hi, getter!" +#[derive(Debug)] +struct Atom(Feed); + +impl IntoResponse for Atom { + fn into_response(self) -> Response { + let buf = BytesMut::with_capacity(128).writer(); + match self.0.write_to(buf) { + Ok(buf) => ( + [( + header::CONTENT_TYPE, + HeaderValue::from_static("application/xml"), + )], + buf.into_inner().freeze(), + ) + .into_response(), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), + )], + err.to_string(), + ) + .into_response(), + } + } } -#[tracing::instrument(level = "trace")] +impl From for Atom { + fn from(inner: Feed) -> Self { + Self(inner) + } +} + +#[tracing::instrument(level = "trace", ret)] +async fn get(state: State) -> impl IntoResponse { + let feed = FeedBuilder::default() + .title("My Notifications") + .subtitle(Some("Originally from my smartphone".into())) + .icon(Some("https://katniss.top/favicon.png".into())) + .build(); + + Atom(feed) +} + +#[tracing::instrument(level = "trace", ret)] async fn post(state: State) -> impl IntoResponse { "Hi, poster!" }