Renamed SyncResult -> SyncProgress

This commit is contained in:
daladim 2021-10-08 23:05:02 +02:00
parent f7ec5d29be
commit 04c8b3a2ee
2 changed files with 51 additions and 51 deletions

View file

@ -13,7 +13,7 @@ use crate::item::SyncStatus;
use crate::calendar::CalendarId; use crate::calendar::CalendarId;
mod sync_progress; mod sync_progress;
use sync_progress::SyncResult; use sync_progress::SyncProgress;
/// A data source that combines two `CalDavSource`s, which is able to sync both sources. /// A data source that combines two `CalDavSource`s, which is able to sync both sources.
/// ///
@ -72,15 +72,15 @@ where
/// It returns whether the sync was totally successful (details about errors are logged using the `log::*` macros). /// It returns whether the sync was totally successful (details about errors are logged using the `log::*` macros).
/// In case errors happened, the sync might have been partially executed, and you can safely run this function again, since it has been designed to gracefully recover from errors. /// In case errors happened, the sync might have been partially executed, and you can safely run this function again, since it has been designed to gracefully recover from errors.
pub async fn sync(&mut self) -> bool { pub async fn sync(&mut self) -> bool {
let mut result = SyncResult::new(); let mut result = SyncProgress::new();
if let Err(err) = self.run_sync(&mut result).await { if let Err(err) = self.run_sync(&mut result).await {
result.error(&format!("Sync terminated because of an error: {}", err)); result.error(&format!("Sync terminated because of an error: {}", err));
} }
result.is_success() result.is_success()
} }
async fn run_sync(&mut self, result: &mut SyncResult) -> Result<(), Box<dyn Error>> { async fn run_sync(&mut self, progress: &mut SyncProgress) -> Result<(), Box<dyn Error>> {
result.info("Starting a sync."); progress.info("Starting a sync.");
let mut handled_calendars = HashSet::new(); let mut handled_calendars = HashSet::new();
@ -89,14 +89,14 @@ where
for (cal_id, cal_remote) in cals_remote { for (cal_id, cal_remote) in cals_remote {
let counterpart = match self.get_or_insert_local_counterpart_calendar(&cal_id, cal_remote.clone()).await { let counterpart = match self.get_or_insert_local_counterpart_calendar(&cal_id, cal_remote.clone()).await {
Err(err) => { Err(err) => {
result.warn(&format!("Unable to get or insert local counterpart calendar for {} ({}). Skipping this time", cal_id, err)); progress.warn(&format!("Unable to get or insert local counterpart calendar for {} ({}). Skipping this time", cal_id, err));
continue; continue;
}, },
Ok(arc) => arc, Ok(arc) => arc,
}; };
if let Err(err) = Self::sync_calendar_pair(counterpart, cal_remote, result).await { if let Err(err) = Self::sync_calendar_pair(counterpart, cal_remote, progress).await {
result.warn(&format!("Unable to sync calendar {}: {}, skipping this time.", cal_id, err)); progress.warn(&format!("Unable to sync calendar {}: {}, skipping this time.", cal_id, err));
continue; continue;
} }
handled_calendars.insert(cal_id); handled_calendars.insert(cal_id);
@ -111,14 +111,14 @@ where
let counterpart = match self.get_or_insert_remote_counterpart_calendar(&cal_id, cal_local.clone()).await { let counterpart = match self.get_or_insert_remote_counterpart_calendar(&cal_id, cal_local.clone()).await {
Err(err) => { Err(err) => {
result.warn(&format!("Unable to get or insert remote counterpart calendar for {} ({}). Skipping this time", cal_id, err)); progress.warn(&format!("Unable to get or insert remote counterpart calendar for {} ({}). Skipping this time", cal_id, err));
continue; continue;
}, },
Ok(arc) => arc, Ok(arc) => arc,
}; };
if let Err(err) = Self::sync_calendar_pair(cal_local, counterpart, result).await { if let Err(err) = Self::sync_calendar_pair(cal_local, counterpart, progress).await {
result.warn(&format!("Unable to sync calendar {}: {}, skipping this time.", cal_id, err)); progress.warn(&format!("Unable to sync calendar {}: {}, skipping this time.", cal_id, err));
continue; continue;
} }
} }
@ -135,12 +135,12 @@ where
} }
async fn sync_calendar_pair(cal_local: Arc<Mutex<T>>, cal_remote: Arc<Mutex<U>>, result: &mut SyncResult) -> Result<(), Box<dyn Error>> { async fn sync_calendar_pair(cal_local: Arc<Mutex<T>>, cal_remote: Arc<Mutex<U>>, progress: &mut SyncProgress) -> Result<(), Box<dyn Error>> {
let mut cal_remote = cal_remote.lock().unwrap(); let mut cal_remote = cal_remote.lock().unwrap();
let mut cal_local = cal_local.lock().unwrap(); let mut cal_local = cal_local.lock().unwrap();
// Step 1 - find the differences // Step 1 - find the differences
result.debug("Finding the differences to sync..."); progress.debug("Finding the differences to sync...");
let mut local_del = HashSet::new(); let mut local_del = HashSet::new();
let mut remote_del = HashSet::new(); let mut remote_del = HashSet::new();
let mut local_changes = HashSet::new(); let mut local_changes = HashSet::new();
@ -151,49 +151,49 @@ where
let remote_items = cal_remote.get_item_version_tags().await?; let remote_items = cal_remote.get_item_version_tags().await?;
let mut local_items_to_handle = cal_local.get_item_ids().await?; let mut local_items_to_handle = cal_local.get_item_ids().await?;
for (id, remote_tag) in remote_items { for (id, remote_tag) in remote_items {
result.trace(&format!("***** Considering remote item {}...", id)); progress.trace(&format!("***** Considering remote item {}...", id));
match cal_local.get_item_by_id(&id).await { match cal_local.get_item_by_id(&id).await {
None => { None => {
// This was created on the remote // This was created on the remote
result.debug(&format!("* {} is a remote addition", id)); progress.debug(&format!("* {} is a remote addition", id));
remote_additions.insert(id); remote_additions.insert(id);
}, },
Some(local_item) => { Some(local_item) => {
if local_items_to_handle.remove(&id) == false { if local_items_to_handle.remove(&id) == false {
result.error(&format!("Inconsistent state: missing task {} from the local tasks", id)); progress.error(&format!("Inconsistent state: missing task {} from the local tasks", id));
} }
match local_item.sync_status() { match local_item.sync_status() {
SyncStatus::NotSynced => { SyncStatus::NotSynced => {
result.error(&format!("ID reuse between remote and local sources ({}). Ignoring this item in the sync", id)); progress.error(&format!("ID reuse between remote and local sources ({}). Ignoring this item in the sync", id));
continue; continue;
}, },
SyncStatus::Synced(local_tag) => { SyncStatus::Synced(local_tag) => {
if &remote_tag != local_tag { if &remote_tag != local_tag {
// This has been modified on the remote // This has been modified on the remote
result.debug(&format!("* {} is a remote change", id)); progress.debug(&format!("* {} is a remote change", id));
remote_changes.insert(id); remote_changes.insert(id);
} }
}, },
SyncStatus::LocallyModified(local_tag) => { SyncStatus::LocallyModified(local_tag) => {
if &remote_tag == local_tag { if &remote_tag == local_tag {
// This has been changed locally // This has been changed locally
result.debug(&format!("* {} is a local change", id)); progress.debug(&format!("* {} is a local change", id));
local_changes.insert(id); local_changes.insert(id);
} else { } else {
result.info(&format!("Conflict: task {} has been modified in both sources. Using the remote version.", id)); progress.info(&format!("Conflict: task {} has been modified in both sources. Using the remote version.", id));
result.debug(&format!("* {} is considered a remote change", id)); progress.debug(&format!("* {} is considered a remote change", id));
remote_changes.insert(id); remote_changes.insert(id);
} }
}, },
SyncStatus::LocallyDeleted(local_tag) => { SyncStatus::LocallyDeleted(local_tag) => {
if &remote_tag == local_tag { if &remote_tag == local_tag {
// This has been locally deleted // This has been locally deleted
result.debug(&format!("* {} is a local deletion", id)); progress.debug(&format!("* {} is a local deletion", id));
local_del.insert(id); local_del.insert(id);
} else { } else {
result.info(&format!("Conflict: task {} has been locally deleted and remotely modified. Reverting to the remote version.", id)); progress.info(&format!("Conflict: task {} has been locally deleted and remotely modified. Reverting to the remote version.", id));
result.debug(&format!("* {} is a considered a remote change", id)); progress.debug(&format!("* {} is a considered a remote change", id));
remote_changes.insert(id); remote_changes.insert(id);
} }
}, },
@ -204,10 +204,10 @@ where
// Also iterate on the local tasks that are not on the remote // Also iterate on the local tasks that are not on the remote
for id in local_items_to_handle { for id in local_items_to_handle {
result.trace(&format!("##### Considering local item {}...", id)); progress.trace(&format!("##### Considering local item {}...", id));
let local_item = match cal_local.get_item_by_id(&id).await { let local_item = match cal_local.get_item_by_id(&id).await {
None => { None => {
result.error(&format!("Inconsistent state: missing task {} from the local tasks", id)); progress.error(&format!("Inconsistent state: missing task {} from the local tasks", id));
continue; continue;
}, },
Some(item) => item, Some(item) => item,
@ -216,21 +216,21 @@ where
match local_item.sync_status() { match local_item.sync_status() {
SyncStatus::Synced(_) => { SyncStatus::Synced(_) => {
// This item has been removed from the remote // This item has been removed from the remote
result.debug(&format!("# {} is a deletion from the server", id)); progress.debug(&format!("# {} is a deletion from the server", id));
remote_del.insert(id); remote_del.insert(id);
}, },
SyncStatus::NotSynced => { SyncStatus::NotSynced => {
// This item has just been locally created // This item has just been locally created
result.debug(&format!("# {} has been locally created", id)); progress.debug(&format!("# {} has been locally created", id));
local_additions.insert(id); local_additions.insert(id);
}, },
SyncStatus::LocallyDeleted(_) => { SyncStatus::LocallyDeleted(_) => {
// This item has been deleted from both sources // This item has been deleted from both sources
result.debug(&format!("# {} has been deleted from both sources", id)); progress.debug(&format!("# {} has been deleted from both sources", id));
remote_del.insert(id); remote_del.insert(id);
}, },
SyncStatus::LocallyModified(_) => { SyncStatus::LocallyModified(_) => {
result.info(&format!("Conflict: item {} has been deleted from the server and locally modified. Deleting the local copy", id)); progress.info(&format!("Conflict: item {} has been deleted from the server and locally modified. Deleting the local copy", id));
remote_del.insert(id); remote_del.insert(id);
}, },
} }
@ -238,44 +238,44 @@ where
// Step 2 - commit changes // Step 2 - commit changes
result.trace("Committing changes..."); progress.trace("Committing changes...");
for id_del in local_del { for id_del in local_del {
result.debug(&format!("> Pushing local deletion {} to the server", id_del)); progress.debug(&format!("> Pushing local deletion {} to the server", id_del));
match cal_remote.delete_item(&id_del).await { match cal_remote.delete_item(&id_del).await {
Err(err) => { Err(err) => {
result.warn(&format!("Unable to delete remote item {}: {}", id_del, err)); progress.warn(&format!("Unable to delete remote item {}: {}", id_del, err));
}, },
Ok(()) => { Ok(()) => {
// Change the local copy from "marked to deletion" to "actually deleted" // Change the local copy from "marked to deletion" to "actually deleted"
if let Err(err) = cal_local.immediately_delete_item(&id_del).await { if let Err(err) = cal_local.immediately_delete_item(&id_del).await {
result.error(&format!("Unable to permanently delete local item {}: {}", id_del, err)); progress.error(&format!("Unable to permanently delete local item {}: {}", id_del, err));
} }
}, },
} }
} }
for id_del in remote_del { for id_del in remote_del {
result.debug(&format!("> Applying remote deletion {} locally", id_del)); progress.debug(&format!("> Applying remote deletion {} locally", id_del));
if let Err(err) = cal_local.immediately_delete_item(&id_del).await { if let Err(err) = cal_local.immediately_delete_item(&id_del).await {
result.warn(&format!("Unable to delete local item {}: {}", id_del, err)); progress.warn(&format!("Unable to delete local item {}: {}", id_del, err));
} }
} }
for id_add in remote_additions { for id_add in remote_additions {
result.debug(&format!("> Applying remote addition {} locally", id_add)); progress.debug(&format!("> Applying remote addition {} locally", id_add));
match cal_remote.get_item_by_id(&id_add).await { match cal_remote.get_item_by_id(&id_add).await {
Err(err) => { Err(err) => {
result.warn(&format!("Unable to get remote item {}: {}. Skipping it.", id_add, err)); progress.warn(&format!("Unable to get remote item {}: {}. Skipping it.", id_add, err));
continue; continue;
}, },
Ok(item) => match item { Ok(item) => match item {
None => { None => {
result.error(&format!("Inconsistency: new item {} has vanished from the remote end", id_add)); progress.error(&format!("Inconsistency: new item {} has vanished from the remote end", id_add));
continue; continue;
}, },
Some(new_item) => { Some(new_item) => {
if let Err(err) = cal_local.add_item(new_item.clone()).await { if let Err(err) = cal_local.add_item(new_item.clone()).await {
result.error(&format!("Not able to add item {} to local calendar: {}", id_add, err)); progress.error(&format!("Not able to add item {} to local calendar: {}", id_add, err));
} }
}, },
}, },
@ -283,20 +283,20 @@ where
} }
for id_change in remote_changes { for id_change in remote_changes {
result.debug(&format!("> Applying remote change {} locally", id_change)); progress.debug(&format!("> Applying remote change {} locally", id_change));
match cal_remote.get_item_by_id(&id_change).await { match cal_remote.get_item_by_id(&id_change).await {
Err(err) => { Err(err) => {
result.warn(&format!("Unable to get remote item {}: {}. Skipping it", id_change, err)); progress.warn(&format!("Unable to get remote item {}: {}. Skipping it", id_change, err));
continue; continue;
}, },
Ok(item) => match item { Ok(item) => match item {
None => { None => {
result.error(&format!("Inconsistency: modified item {} has vanished from the remote end", id_change)); progress.error(&format!("Inconsistency: modified item {} has vanished from the remote end", id_change));
continue; continue;
}, },
Some(item) => { Some(item) => {
if let Err(err) = cal_local.update_item(item.clone()).await { if let Err(err) = cal_local.update_item(item.clone()).await {
result.error(&format!("Unable to update item {} in local calendar: {}", id_change, err)); progress.error(&format!("Unable to update item {} in local calendar: {}", id_change, err));
} }
}, },
} }
@ -305,15 +305,15 @@ where
for id_add in local_additions { for id_add in local_additions {
result.debug(&format!("> Pushing local addition {} to the server", id_add)); progress.debug(&format!("> Pushing local addition {} to the server", id_add));
match cal_local.get_item_by_id_mut(&id_add).await { match cal_local.get_item_by_id_mut(&id_add).await {
None => { None => {
result.error(&format!("Inconsistency: created item {} has been marked for upload but is locally missing", id_add)); progress.error(&format!("Inconsistency: created item {} has been marked for upload but is locally missing", id_add));
continue; continue;
}, },
Some(item) => { Some(item) => {
match cal_remote.add_item(item.clone()).await { match cal_remote.add_item(item.clone()).await {
Err(err) => result.error(&format!("Unable to add item {} to remote calendar: {}", id_add, err)), Err(err) => progress.error(&format!("Unable to add item {} to remote calendar: {}", id_add, err)),
Ok(new_ss) => { Ok(new_ss) => {
// Update local sync status // Update local sync status
item.set_sync_status(new_ss); item.set_sync_status(new_ss);
@ -324,15 +324,15 @@ where
} }
for id_change in local_changes { for id_change in local_changes {
result.debug(&format!("> Pushing local change {} to the server", id_change)); progress.debug(&format!("> Pushing local change {} to the server", id_change));
match cal_local.get_item_by_id_mut(&id_change).await { match cal_local.get_item_by_id_mut(&id_change).await {
None => { None => {
result.error(&format!("Inconsistency: modified item {} has been marked for upload but is locally missing", id_change)); progress.error(&format!("Inconsistency: modified item {} has been marked for upload but is locally missing", id_change));
continue; continue;
}, },
Some(item) => { Some(item) => {
match cal_remote.update_item(item.clone()).await { match cal_remote.update_item(item.clone()).await {
Err(err) => result.error(&format!("Unable to update item {} in remote calendar: {}", id_change, err)), Err(err) => progress.error(&format!("Unable to update item {} in remote calendar: {}", id_change, err)),
Ok(new_ss) => { Ok(new_ss) => {
// Update local sync status // Update local sync status
item.set_sync_status(new_ss); item.set_sync_status(new_ss);

View file

@ -1,8 +1,8 @@
/// A counter of errors that happen during a sync /// A counter of errors that happen during a sync
pub struct SyncResult { pub struct SyncProgress {
n_errors: u32, n_errors: u32,
} }
impl SyncResult { impl SyncProgress {
pub fn new() -> Self { pub fn new() -> Self {
Self { n_errors: 0 } Self { n_errors: 0 }
} }