From 330877c8c587b2790aec9c0e5d0115899f155a6b Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sat, 15 Mar 2025 20:20:38 +0100 Subject: [PATCH] refactor: moved knowledge of subscription change time to store --- src/db/repository/subscription.rs | 52 ++++++++++++++------ src/gpodder/mod.rs | 6 +-- src/gpodder/models.rs | 5 ++ src/gpodder/repository.rs | 26 ++++++++-- src/server/gpodder/advanced/subscriptions.rs | 4 +- src/server/gpodder/simple/subscriptions.rs | 4 +- 6 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/db/repository/subscription.rs b/src/db/repository/subscription.rs index 6ab8fe5..5448380 100644 --- a/src/db/repository/subscription.rs +++ b/src/db/repository/subscription.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use chrono::DateTime; use diesel::prelude::*; use super::SqliteRepository; @@ -8,24 +9,39 @@ use crate::{ gpodder, }; +impl From<(String, i64)> for gpodder::Subscription { + fn from((url, ts): (String, i64)) -> Self { + Self { + url, + time_changed: DateTime::from_timestamp(ts, 0).unwrap(), + } + } +} + impl gpodder::SubscriptionRepository for SqliteRepository { fn subscriptions_for_user( &self, user: &gpodder::User, - ) -> Result, gpodder::AuthErr> { + ) -> Result, gpodder::AuthErr> { Ok(device_subscriptions::table .inner_join(devices::table) .filter(devices::user_id.eq(user.id)) - .select(device_subscriptions::podcast_url) + .select(( + device_subscriptions::podcast_url, + device_subscriptions::time_changed, + )) .distinct() - .get_results(&mut self.pool.get()?)?) + .get_results::<(String, i64)>(&mut self.pool.get()?)? + .into_iter() + .map(Into::into) + .collect()) } fn subscriptions_for_device( &self, user: &gpodder::User, device_id: &str, - ) -> Result, gpodder::AuthErr> { + ) -> Result, gpodder::AuthErr> { Ok(device_subscriptions::table .inner_join(devices::table) .filter( @@ -33,8 +49,14 @@ impl gpodder::SubscriptionRepository for SqliteRepository { .eq(user.id) .and(devices::device_id.eq(device_id)), ) - .select(device_subscriptions::podcast_url) - .get_results(&mut self.pool.get()?)?) + .select(( + device_subscriptions::podcast_url, + device_subscriptions::time_changed, + )) + .get_results::<(String, i64)>(&mut self.pool.get()?)? + .into_iter() + .map(Into::into) + .collect()) } fn set_subscriptions_for_device( @@ -230,7 +252,7 @@ impl gpodder::SubscriptionRepository for SqliteRepository { user: &gpodder::User, device_id: &str, since: chrono::DateTime, - ) -> Result<(chrono::DateTime, Vec, Vec), gpodder::AuthErr> { + ) -> Result<(Vec, Vec), gpodder::AuthErr> { let since = since.timestamp(); let (mut added, mut removed) = (Vec::new(), Vec::new()); @@ -245,20 +267,22 @@ impl gpodder::SubscriptionRepository for SqliteRepository { ) .select(db::DeviceSubscription::as_select()); - let mut max_time: chrono::DateTime = chrono::DateTime::::MIN_UTC; - for sub in query.load_iter(&mut self.pool.get()?)? { let sub = sub?; if sub.deleted { - removed.push(sub.podcast_url); + removed.push(gpodder::Subscription { + url: sub.podcast_url, + time_changed: DateTime::from_timestamp(sub.time_changed, 0).unwrap(), + }); } else { - added.push(sub.podcast_url); + added.push(gpodder::Subscription { + url: sub.podcast_url, + time_changed: DateTime::from_timestamp(sub.time_changed, 0).unwrap(), + }); } - - max_time = max_time.max(chrono::DateTime::from_timestamp(sub.time_changed, 0).unwrap()); } - Ok((max_time, added, removed)) + Ok((added, removed)) } } diff --git a/src/gpodder/mod.rs b/src/gpodder/mod.rs index 0e89cb9..8336de1 100644 --- a/src/gpodder/mod.rs +++ b/src/gpodder/mod.rs @@ -74,10 +74,10 @@ pub trait SubscriptionRepository { &self, user: &User, device_id: &str, - ) -> Result, AuthErr>; + ) -> Result, AuthErr>; /// Return all subscriptions for a given user - fn subscriptions_for_user(&self, user: &User) -> Result, AuthErr>; + fn subscriptions_for_user(&self, user: &User) -> Result, AuthErr>; /// Replace the list of subscriptions for a device with the given list fn set_subscriptions_for_device( @@ -104,7 +104,7 @@ pub trait SubscriptionRepository { user: &User, device_id: &str, since: DateTime, - ) -> Result<(DateTime, Vec, Vec), AuthErr>; + ) -> Result<(Vec, Vec), AuthErr>; } pub trait EpisodeActionRepository { diff --git a/src/gpodder/models.rs b/src/gpodder/models.rs index 3bbf229..b68e73b 100644 --- a/src/gpodder/models.rs +++ b/src/gpodder/models.rs @@ -52,3 +52,8 @@ pub struct Session { pub last_seen: DateTime, pub user: User, } + +pub struct Subscription { + pub url: String, + pub time_changed: DateTime, +} diff --git a/src/gpodder/repository.rs b/src/gpodder/repository.rs index 9913c9d..411f9cf 100644 --- a/src/gpodder/repository.rs +++ b/src/gpodder/repository.rs @@ -86,11 +86,14 @@ impl GpodderRepository { &self, user: &models::User, device_id: &str, - ) -> Result, AuthErr> { + ) -> Result, AuthErr> { self.store.subscriptions_for_device(user, device_id) } - pub fn subscriptions_for_user(&self, user: &models::User) -> Result, AuthErr> { + pub fn subscriptions_for_user( + &self, + user: &models::User, + ) -> Result, AuthErr> { self.store.subscriptions_for_user(user) } @@ -128,11 +131,26 @@ impl GpodderRepository { user: &models::User, device_id: &str, since: DateTime, - ) -> Result<(DateTime, Vec, Vec), AuthErr> { - let (max_time_changed, added, removed) = self + ) -> Result< + ( + DateTime, + Vec, + Vec, + ), + AuthErr, + > { + let now = chrono::Utc::now(); + + let (added, removed) = self .store .subscription_updates_for_device(user, device_id, since)?; + let max_time_changed = added + .iter() + .chain(removed.iter()) + .map(|s| s.time_changed) + .max() + .unwrap_or(now); Ok((max_time_changed + TimeDelta::seconds(1), added, removed)) } diff --git a/src/server/gpodder/advanced/subscriptions.rs b/src/server/gpodder/advanced/subscriptions.rs index dbb8d28..e5691e1 100644 --- a/src/server/gpodder/advanced/subscriptions.rs +++ b/src/server/gpodder/advanced/subscriptions.rs @@ -85,8 +85,8 @@ pub async fn get_subscription_changes( .unwrap() .map(|(next_time_changed, add, remove)| { Json(SubscriptionDeltaResponse { - add, - remove, + add: add.into_iter().map(|s| s.url).collect(), + remove: remove.into_iter().map(|s| s.url).collect(), timestamp: next_time_changed.timestamp(), }) })?) diff --git a/src/server/gpodder/simple/subscriptions.rs b/src/server/gpodder/simple/subscriptions.rs index 4f6266f..6e9227c 100644 --- a/src/server/gpodder/simple/subscriptions.rs +++ b/src/server/gpodder/simple/subscriptions.rs @@ -37,7 +37,7 @@ pub async fn get_device_subscriptions( tokio::task::spawn_blocking(move || ctx.store.subscriptions_for_device(&user, &id)) .await .unwrap() - .map(Json)?, + .map(|subs| Json(subs.into_iter().map(|s| s.url).collect()))?, ) } @@ -54,7 +54,7 @@ pub async fn get_user_subscriptions( tokio::task::spawn_blocking(move || ctx.store.subscriptions_for_user(&user)) .await .unwrap() - .map(Json)?, + .map(|subs| Json(subs.into_iter().map(|s| s.url).collect()))?, ) }