diff --git a/src/cache.rs b/src/cache.rs index 6f210ea..c6a222d 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -7,8 +7,10 @@ use std::error::Error; use serde::{Deserialize, Serialize}; use async_trait::async_trait; use url::Url; +use chrono::{DateTime, Utc}; use crate::traits::CalDavSource; +use crate::traits::SyncSlave; use crate::Calendar; @@ -21,6 +23,7 @@ pub struct Cache { #[derive(Default, Debug, PartialEq, Serialize, Deserialize)] struct CachedData { calendars: Vec, + last_sync: Option>, } impl Cache { @@ -108,7 +111,15 @@ impl CalDavSource for Cache { } } +impl SyncSlave for Cache { + fn get_last_sync(&self) -> Option> { + self.data.last_sync + } + fn update_last_sync(&mut self, timepoint: Option>) { + self.data.last_sync = Some(timepoint.unwrap_or_else(|| Utc::now())); + } +} #[cfg(test)] mod tests { diff --git a/src/provider.rs b/src/provider.rs index 6171e03..bbfe1df 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -5,39 +5,42 @@ use std::error::Error; use chrono::{DateTime, Utc}; use crate::traits::CalDavSource; +use crate::traits::SyncSlave; use crate::Calendar; use crate::Item; use crate::item::ItemId; +/// A data source that combines two `CalDavSources` (usually a server and a local cache), which is able to sync both sources. pub struct Provider where S: CalDavSource, - L: CalDavSource, + L: CalDavSource + SyncSlave, { /// The remote server server: S, /// The local cache local: L, - - /// The last time the provider successfully synchronized both sources - last_sync: DateTime, } impl Provider where S: CalDavSource, - L: CalDavSource, + L: CalDavSource + SyncSlave, { - /// Create a provider that will merge both sources - pub fn new(server: S, local: L, last_sync: DateTime) -> Self { - Self { server, local, last_sync } + pub fn new(server: S, local: L) -> Self { + Self { server, local } } pub fn server(&self) -> &S { &self.server } pub fn local(&self) -> &L { &self.local } + /// Returns the last time the `local` source has been synced + pub fn last_sync_timestamp(&self) -> Option> { + self.local.get_last_sync() + } pub async fn sync(&mut self) -> Result<(), Box> { + let last_sync = self.local.get_last_sync(); let cals_server = self.server.get_calendars_mut().await?; for cal_server in cals_server { @@ -49,9 +52,15 @@ where Some(cal) => cal, }; - let server_mod = cal_server.get_tasks_modified_since(Some(self.last_sync)); - let server_del = cal_server.get_items_deleted_since(self.last_sync); - let local_del = cal_local.get_items_deleted_since(self.last_sync); + let server_mod = cal_server.get_tasks_modified_since(last_sync); + let server_del = match last_sync { + Some(date) => cal_server.get_items_deleted_since(date), + None => Vec::new(), + }; + let local_del = match last_sync { + Some(date) => cal_local.get_items_deleted_since(date), + None => Vec::new(), + }; // Pull remote changes from the server let mut tasks_to_add_to_local = Vec::new(); @@ -72,7 +81,7 @@ where // Push local changes to the server - let local_mod = cal_local.get_tasks_modified_since(Some(self.last_sync)); + let local_mod = cal_local.get_tasks_modified_since(last_sync); let mut tasks_to_add_to_server = Vec::new(); let mut tasks_id_to_remove_from_server = Vec::new(); @@ -96,6 +105,8 @@ where move_to_calendar(&mut tasks_to_add_to_server, cal_server); } + self.local.update_last_sync(None); + Ok(()) } } diff --git a/src/traits.rs b/src/traits.rs index 9d09050..9938a33 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -2,6 +2,7 @@ use std::error::Error; use async_trait::async_trait; use url::Url; +use chrono::{DateTime, Utc}; use crate::Calendar; @@ -25,3 +26,11 @@ pub trait CalDavSource { async fn get_calendar_mut(&mut self, url: Url) -> Option<&mut Calendar>; } + +pub trait SyncSlave { + /// Returns the last time this source successfully synced from a master source (e.g. from a server) + /// (or None in case it has never been synchronized) + fn get_last_sync(&self) -> Option>; + /// Update the last sync timestamp to now, or to a custom time in case `timepoint` is `Some` + fn update_last_sync(&mut self, timepoint: Option>); +} diff --git a/tests/sync.rs b/tests/sync.rs index 2107511..d1d3da2 100644 --- a/tests/sync.rs +++ b/tests/sync.rs @@ -162,5 +162,5 @@ async fn populate_test_provider() -> Provider { let task_o = Item::Task(Task::new("task O (new from local)".into(), Utc::now())); cal_local.add_item(task_o); - Provider::new(server, local, last_sync) + Provider::new(server, local) }