diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 348a104..33ca360 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -9,12 +9,12 @@ use std::sync::{Arc, Mutex}; use crate::traits::{BaseCalendar, CalDavSource, DavCalendar}; use crate::traits::CompleteCalendar; -use crate::item::SyncStatus; +use crate::item::{ItemId, SyncStatus}; use crate::calendar::CalendarId; -mod sync_progress; +pub mod sync_progress; use sync_progress::SyncProgress; -pub use sync_progress::FeedbackSender; +use sync_progress::{FeedbackSender, SyncEvent}; /// A data source that combines two `CalDavSource`s, which is able to sync both sources. /// @@ -89,11 +89,13 @@ where if let Err(err) = self.run_sync_inner(progress).await { progress.error(&format!("Sync terminated because of an error: {}", err)); } + progress.feedback(SyncEvent::Finished{ success: progress.is_success() }); progress.is_success() } async fn run_sync_inner(&mut self, progress: &mut SyncProgress) -> Result<(), Box> { progress.info("Starting a sync."); + progress.feedback(SyncEvent::Started); let mut handled_calendars = HashSet::new(); @@ -151,6 +153,13 @@ where async fn sync_calendar_pair(cal_local: Arc>, cal_remote: Arc>, progress: &mut SyncProgress) -> Result<(), Box> { let mut cal_remote = cal_remote.lock().unwrap(); let mut cal_local = cal_local.lock().unwrap(); + let cal_name = cal_local.name().to_string(); + + progress.info(&format!("Syncing calendar {}", cal_name)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: "started".to_string() + }); // Step 1 - find the differences progress.debug("Finding the differences to sync..."); @@ -162,6 +171,11 @@ where let mut remote_additions = HashSet::new(); let remote_items = cal_remote.get_item_version_tags().await?; + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: format!("{} remote items", remote_items.len()), + }); + let mut local_items_to_handle = cal_local.get_item_ids().await?; for (id, remote_tag) in remote_items { progress.trace(&format!("***** Considering remote item {}...", id)); @@ -254,6 +268,10 @@ where progress.trace("Committing changes..."); for id_del in local_del { progress.debug(&format!("> Pushing local deletion {} to the server", id_del)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: Self::item_name(&cal_local, &id_del).await, + }); match cal_remote.delete_item(&id_del).await { Err(err) => { progress.warn(&format!("Unable to delete remote item {}: {}", id_del, err)); @@ -269,6 +287,10 @@ where for id_del in remote_del { progress.debug(&format!("> Applying remote deletion {} locally", id_del)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: Self::item_name(&cal_local, &id_del).await, + }); if let Err(err) = cal_local.immediately_delete_item(&id_del).await { progress.warn(&format!("Unable to delete local item {}: {}", id_del, err)); } @@ -276,6 +298,10 @@ where for id_add in remote_additions { progress.debug(&format!("> Applying remote addition {} locally", id_add)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: Self::item_name(&cal_local, &id_add).await, + }); match cal_remote.get_item_by_id(&id_add).await { Err(err) => { progress.warn(&format!("Unable to get remote item {}: {}. Skipping it.", id_add, err)); @@ -297,6 +323,10 @@ where for id_change in remote_changes { progress.debug(&format!("> Applying remote change {} locally", id_change)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: Self::item_name(&cal_local, &id_change).await, + }); match cal_remote.get_item_by_id(&id_change).await { Err(err) => { progress.warn(&format!("Unable to get remote item {}: {}. Skipping it", id_change, err)); @@ -319,6 +349,10 @@ where for id_add in local_additions { progress.debug(&format!("> Pushing local addition {} to the server", id_add)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: Self::item_name(&cal_local, &id_add).await, + }); match cal_local.get_item_by_id_mut(&id_add).await { None => { progress.error(&format!("Inconsistency: created item {} has been marked for upload but is locally missing", id_add)); @@ -338,6 +372,10 @@ where for id_change in local_changes { progress.debug(&format!("> Pushing local change {} to the server", id_change)); + progress.feedback(SyncEvent::InProgress{ + calendar: cal_name.clone(), + details: Self::item_name(&cal_local, &id_change).await, + }); match cal_local.get_item_by_id_mut(&id_change).await { None => { progress.error(&format!("Inconsistency: modified item {} has been marked for upload but is locally missing", id_change)); @@ -357,6 +395,12 @@ where Ok(()) } + + + async fn item_name(cal: &T, id: &ItemId) -> String { + cal.get_item_by_id(id).await.map(|item| item.name()).unwrap_or_default().to_string() + } + } diff --git a/src/provider/sync_progress.rs b/src/provider/sync_progress.rs index 2140bd0..d2a24bf 100644 --- a/src/provider/sync_progress.rs +++ b/src/provider/sync_progress.rs @@ -64,21 +64,34 @@ impl SyncProgress { self.n_errors == 0 } + /// Log an error pub fn error(&mut self, text: &str) { log::error!("{}", text); self.n_errors += 1; } + /// Log a warning pub fn warn(&mut self, text: &str) { log::warn!("{}", text); self.n_errors += 1; } + /// Log an info pub fn info(&mut self, text: &str) { log::info!("{}", text); } + /// Log a debug message pub fn debug(&mut self, text: &str) { log::debug!("{}", text); } + /// Log a trace message pub fn trace(&mut self, text: &str) { log::trace!("{}", text); } + /// Send an event as a feedback to the listener (if any). + pub fn feedback(&mut self, event: SyncEvent) { + self.feedback_channel + .as_ref() + .map(|sender| { + sender.send(event) + }); + } }