Feedback infrastructure
This commit is contained in:
parent
04c8b3a2ee
commit
7fb98a471b
2 changed files with 77 additions and 10 deletions
|
@ -14,6 +14,7 @@ use crate::calendar::CalendarId;
|
||||||
|
|
||||||
mod sync_progress;
|
mod sync_progress;
|
||||||
use sync_progress::SyncProgress;
|
use sync_progress::SyncProgress;
|
||||||
|
pub use sync_progress::FeedbackSender;
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
|
@ -64,22 +65,34 @@ where
|
||||||
/// To be sure `local` accurately mirrors the `remote` source, you can run [`Provider::sync`]
|
/// To be sure `local` accurately mirrors the `remote` source, you can run [`Provider::sync`]
|
||||||
pub fn remote(&self) -> &R { &self.remote }
|
pub fn remote(&self) -> &R { &self.remote }
|
||||||
|
|
||||||
/// Performs a synchronisation between `local` and `remote`.
|
/// Performs a synchronisation between `local` and `remote`, and provide feeedback to the user about the progress.
|
||||||
///
|
///
|
||||||
/// This bidirectional sync applies additions/deletions made on a source to the other source.
|
/// This bidirectional sync applies additions/deletions made on a source to the other source.
|
||||||
/// In case of conflicts (the same item has been modified on both ends since the last sync, `remote` always wins)
|
/// In case of conflicts (the same item has been modified on both ends since the last sync, `remote` always wins)
|
||||||
///
|
///
|
||||||
/// 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_with_feedback(&mut self, feedback_sender: FeedbackSender) -> bool {
|
||||||
let mut result = SyncProgress::new();
|
let mut progress = SyncProgress::new_with_feedback_channel(feedback_sender);
|
||||||
if let Err(err) = self.run_sync(&mut result).await {
|
self.run_sync(&mut progress).await
|
||||||
result.error(&format!("Sync terminated because of an error: {}", err));
|
|
||||||
}
|
|
||||||
result.is_success()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_sync(&mut self, progress: &mut SyncProgress) -> Result<(), Box<dyn Error>> {
|
/// Performs a synchronisation between `local` and `remote`, without giving any feedback.
|
||||||
|
///
|
||||||
|
/// See [sync_with_feedback]
|
||||||
|
pub async fn sync(&mut self) -> bool {
|
||||||
|
let mut progress = SyncProgress::new();
|
||||||
|
self.run_sync(&mut progress).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_sync(&mut self, progress: &mut SyncProgress) -> bool {
|
||||||
|
if let Err(err) = self.run_sync_inner(progress).await {
|
||||||
|
progress.error(&format!("Sync terminated because of an error: {}", err));
|
||||||
|
}
|
||||||
|
progress.is_success()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_sync_inner(&mut self, progress: &mut SyncProgress) -> Result<(), Box<dyn Error>> {
|
||||||
progress.info("Starting a sync.");
|
progress.info("Starting a sync.");
|
||||||
|
|
||||||
let mut handled_calendars = HashSet::new();
|
let mut handled_calendars = HashSet::new();
|
||||||
|
|
|
@ -1,11 +1,65 @@
|
||||||
/// A counter of errors that happen during a sync
|
//! Utilities to track the progression of a sync
|
||||||
|
|
||||||
|
use std::fmt::{Display, Error, Formatter};
|
||||||
|
|
||||||
|
/// An event that happens during a sync
|
||||||
|
pub enum SyncEvent {
|
||||||
|
/// Sync has not started
|
||||||
|
NotStarted,
|
||||||
|
/// Sync has just started but no calendar is handled yet
|
||||||
|
Started,
|
||||||
|
/// Sync is in progress.
|
||||||
|
InProgress{ calendar: String, details: String},
|
||||||
|
/// Sync is finished
|
||||||
|
Finished{ success: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SyncEvent {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||||
|
match self {
|
||||||
|
SyncEvent::NotStarted => write!(f, "Not started"),
|
||||||
|
SyncEvent::Started => write!(f, "Sync has started"),
|
||||||
|
SyncEvent::InProgress{calendar, details} => write!(f, "[{}] {}", calendar, details),
|
||||||
|
SyncEvent::Finished{success} => match success {
|
||||||
|
true => write!(f, "Sync successfully finished"),
|
||||||
|
false => write!(f, "Sync finished with errors"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SyncEvent {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::NotStarted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub type FeedbackSender = tokio::sync::watch::Sender<SyncEvent>;
|
||||||
|
pub type FeedbackReceiver = tokio::sync::watch::Receiver<SyncEvent>;
|
||||||
|
|
||||||
|
pub fn feedback_channel() -> (FeedbackSender, FeedbackReceiver) {
|
||||||
|
tokio::sync::watch::channel(SyncEvent::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// A structure that tracks the progression and the errors that happen during a sync
|
||||||
pub struct SyncProgress {
|
pub struct SyncProgress {
|
||||||
n_errors: u32,
|
n_errors: u32,
|
||||||
|
feedback_channel: Option<FeedbackSender>
|
||||||
}
|
}
|
||||||
impl SyncProgress {
|
impl SyncProgress {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { n_errors: 0 }
|
Self { n_errors: 0, feedback_channel: None }
|
||||||
}
|
}
|
||||||
|
pub fn new_with_feedback_channel(channel: FeedbackSender) -> Self {
|
||||||
|
Self { n_errors: 0, feedback_channel: Some(channel) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn is_success(&self) -> bool {
|
pub fn is_success(&self) -> bool {
|
||||||
self.n_errors == 0
|
self.n_errors == 0
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue