From d61e1f6a8e5ad5b7c14b1f9ab3101496f3f9ea00 Mon Sep 17 00:00:00 2001 From: Vika Date: Thu, 22 Jun 2023 20:28:21 +0300 Subject: database: introduce read_feed_with_cursor read_feed_with_cursor allows using an arbitrary string as a cursor, unlike read_feed_with_limit, which uses last post's UID as a cursor. --- kittybox-rs/src/database/file/mod.rs | 12 +++++++++++- kittybox-rs/src/database/memory.rs | 13 ++++++++++++- kittybox-rs/src/database/mod.rs | 10 +++++++++- kittybox-rs/src/frontend/mod.rs | 13 +++++++------ kittybox-rs/templates/src/mf2.rs | 4 ++-- kittybox-rs/templates/src/templates.rs | 4 ++-- 6 files changed, 43 insertions(+), 13 deletions(-) (limited to 'kittybox-rs') diff --git a/kittybox-rs/src/database/file/mod.rs b/kittybox-rs/src/database/file/mod.rs index 531f7b1..a9de63e 100644 --- a/kittybox-rs/src/database/file/mod.rs +++ b/kittybox-rs/src/database/file/mod.rs @@ -499,6 +499,16 @@ impl Storage for FileStorage { } } + async fn read_feed_with_cursor( + &self, + url: &'_ str, + cursor: Option<&'_ str>, + limit: usize, + user: Option<&'_ str> + ) -> Result)>> { + todo!() + } + #[tracing::instrument(skip(self))] async fn read_feed_with_limit( &self, @@ -605,7 +615,7 @@ impl Storage for FileStorage { } #[tracing::instrument(skip(self))] - async fn set_setting, 'a>(&self, user: &'_ str, value: S::Data) -> Result<()> { + async fn set_setting + 'a, 'a>(&self, user: &'a str, value: S::Data) -> Result<()> { let url = axum::http::Uri::try_from(user).expect("Couldn't parse a URL"); let mut path = relative_path::RelativePathBuf::new(); path.push(url.authority().unwrap().to_string()); diff --git a/kittybox-rs/src/database/memory.rs b/kittybox-rs/src/database/memory.rs index 9d79ecc..36e924f 100644 --- a/kittybox-rs/src/database/memory.rs +++ b/kittybox-rs/src/database/memory.rs @@ -238,6 +238,17 @@ impl Storage for MemoryStorage { todo!() } + #[allow(unused_variables)] + async fn read_feed_with_cursor( + &self, + url: &'_ str, + cursor: Option<&'_ str>, + limit: usize, + user: Option<&'_ str> + ) -> Result)>> { + todo!() + } + async fn delete_post(&self, url: &'_ str) -> Result<()> { self.mapping.write().await.remove(url); Ok(()) @@ -249,7 +260,7 @@ impl Storage for MemoryStorage { } #[allow(unused_variables)] - async fn set_setting, 'a>(&self, user: &'_ str, value: S::Data) -> Result<()> { + async fn set_setting + 'a, 'a>(&self, user: &'a str, value: S::Data) -> Result<()> { todo!() } diff --git a/kittybox-rs/src/database/mod.rs b/kittybox-rs/src/database/mod.rs index ea4205c..4b1b348 100644 --- a/kittybox-rs/src/database/mod.rs +++ b/kittybox-rs/src/database/mod.rs @@ -330,6 +330,14 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync { user: &'_ Option, ) -> Result>; + async fn read_feed_with_cursor( + &self, + url: &'_ str, + cursor: Option<&'_ str>, + limit: usize, + user: Option<&'_ str> + ) -> Result)>>; + /// Deletes a post from the database irreversibly. 'nuff said. Must be idempotent. async fn delete_post(&self, url: &'_ str) -> Result<()>; @@ -337,7 +345,7 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync { async fn get_setting, 'a>(&'_ self, user: &'_ str) -> Result; /// Commits a setting to the setting store. - async fn set_setting, 'a>(&self, user: &'_ str, value: S::Data) -> Result<()>; + async fn set_setting + 'a, 'a>(&self, user: &'a str, value: S::Data) -> Result<()>; } #[cfg(test)] diff --git a/kittybox-rs/src/frontend/mod.rs b/kittybox-rs/src/frontend/mod.rs index b90d57c..d677005 100644 --- a/kittybox-rs/src/frontend/mod.rs +++ b/kittybox-rs/src/frontend/mod.rs @@ -79,13 +79,13 @@ async fn get_post_from_database( url: &str, after: Option, user: &Option, -) -> std::result::Result { +) -> std::result::Result<(serde_json::Value, Option), FrontendError> { match db - .read_feed_with_limit(url, &after, POSTS_PER_PAGE, user) + .read_feed_with_cursor(url, after.as_deref(), POSTS_PER_PAGE, user.as_deref()) .await { Ok(result) => match result { - Some(post) => Ok(post), + Some((post, cursor)) => Ok((post, cursor)), None => Err(FrontendError::with_code( StatusCode::NOT_FOUND, "Post not found in the database", @@ -125,7 +125,7 @@ pub async fn homepage( get_post_from_database(&db, &path, None, &user), get_post_from_database(&db, &feed_path, query.after, &user) ) { - Ok((hcard, hfeed)) => { + Ok(((hcard, _), (hfeed, cursor))) => { // Here, we know those operations can't really fail // (or it'll be a transient failure that will show up on // other requests anyway if it's serious...) @@ -155,6 +155,7 @@ pub async fn homepage( content: MainPage { feed: &hfeed, card: &hcard, + cursor: cursor.as_deref(), webring: crate::database::settings::Setting::into_inner(webring) } .to_string(), @@ -219,7 +220,7 @@ pub async fn catchall( .unwrap(); match get_post_from_database(&db, path.as_str(), query.after, &user).await { - Ok(post) => { + Ok((post, cursor)) => { let (blogname, channels) = tokio::join!( db.get_setting::(&host) .map(Result::unwrap_or_default), @@ -240,7 +241,7 @@ pub async fn catchall( user, content: match post.pointer("/type/0").and_then(|i| i.as_str()) { Some("h-entry") => Entry { post: &post }.to_string(), - Some("h-feed") => Feed { feed: &post }.to_string(), + Some("h-feed") => Feed { feed: &post, cursor: cursor.as_deref() }.to_string(), Some("h-card") => VCard { card: &post }.to_string(), unknown => { unimplemented!("Template for MF2-JSON type {:?}", unknown) diff --git a/kittybox-rs/templates/src/mf2.rs b/kittybox-rs/templates/src/mf2.rs index 0e03dc6..7f943d3 100644 --- a/kittybox-rs/templates/src/mf2.rs +++ b/kittybox-rs/templates/src/mf2.rs @@ -344,7 +344,7 @@ markup::define! { @PhotoGallery { photos: food["properties"]["photo"].as_array() } } } - Feed<'a>(feed: &'a serde_json::Value) { + Feed<'a>(feed: &'a serde_json::Value, cursor: Option<&'a str>) { div."h-feed" { div.metadata { @if feed["properties"]["name"][0].is_string() { @@ -359,7 +359,7 @@ markup::define! { @for child in feed["children"].as_array().unwrap() { @match child["type"][0].as_str().unwrap() { "h-entry" => { @Entry { post: child } } - "h-feed" => { @Feed { feed: child } } + "h-feed" => { @Feed { feed: child, cursor: None } } "h-food" => { @Food { food: child } } //"h-event" => { } "h-card" => { @VCard { card: child } } diff --git a/kittybox-rs/templates/src/templates.rs b/kittybox-rs/templates/src/templates.rs index 9826bfc..288669d 100644 --- a/kittybox-rs/templates/src/templates.rs +++ b/kittybox-rs/templates/src/templates.rs @@ -63,7 +63,7 @@ markup::define! { } } } - MainPage<'a>(feed: &'a serde_json::Value, card: &'a serde_json::Value, webring: bool) { + MainPage<'a>(feed: &'a serde_json::Value, card: &'a serde_json::Value, cursor: Option<&'a str>, webring: bool) { .sidebyside { @VCard { card } #dynamicstuff { @@ -90,7 +90,7 @@ markup::define! { } } } - @Feed { feed } + @Feed { feed, cursor: *cursor } } ErrorPage(code: StatusCode, msg: Option) { h1 { @format!("HTTP {code}") } -- cgit 1.4.1