kitchen_fridge/provider/
sync_progress.rs

1//! Utilities to track the progression of a sync
2
3use std::fmt::{Display, Error, Formatter};
4
5/// An event that happens during a sync
6#[derive(Clone, Debug)]
7pub enum SyncEvent {
8    /// Sync has not started
9    NotStarted,
10    /// Sync has just started but no calendar is handled yet
11    Started,
12    /// Sync is in progress.
13    InProgress{ calendar: String, items_done_already: usize, details: String},
14    /// Sync is finished
15    Finished{ success: bool },
16}
17
18impl Display for SyncEvent {
19    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
20        match self {
21            SyncEvent::NotStarted => write!(f, "Not started"),
22            SyncEvent::Started => write!(f, "Sync has started..."),
23            SyncEvent::InProgress{calendar, items_done_already, details} => write!(f, "{} [{}/?] {}...", calendar, items_done_already, details),
24            SyncEvent::Finished{success} => match success {
25                true => write!(f, "Sync successfully finished"),
26                false => write!(f, "Sync finished with errors"),
27            }
28        }
29    }
30}
31
32impl Default for SyncEvent {
33    fn default() -> Self {
34        Self::NotStarted
35    }
36}
37
38
39
40/// See [`feedback_channel`]
41pub type FeedbackSender = tokio::sync::watch::Sender<SyncEvent>;
42/// See [`feedback_channel`]
43pub type FeedbackReceiver = tokio::sync::watch::Receiver<SyncEvent>;
44
45/// Create a feeback channel, that can be used to retrieve the current progress of a sync operation
46pub fn feedback_channel() -> (FeedbackSender, FeedbackReceiver) {
47    tokio::sync::watch::channel(SyncEvent::default())
48}
49
50
51
52
53/// A structure that tracks the progression and the errors that happen during a sync
54pub struct SyncProgress {
55    n_errors: u32,
56    feedback_channel: Option<FeedbackSender>,
57    counter: usize,
58}
59impl SyncProgress {
60    pub fn new() -> Self {
61        Self { n_errors: 0, feedback_channel: None, counter: 0 }
62    }
63    pub fn new_with_feedback_channel(channel: FeedbackSender) -> Self {
64        Self { n_errors: 0, feedback_channel: Some(channel), counter: 0 }
65    }
66
67    /// Reset the user-info counter
68    pub fn reset_counter(&mut self) {
69        self.counter = 0;
70    }
71    /// Increments the user-info counter.
72    pub fn increment_counter(&mut self, increment: usize) {
73        self.counter += increment;
74    }
75    /// Retrieves the current user-info counter.
76    /// This counts "arbitrary things", that's provided as a convenience but it is not used internally
77    /// (e.g. that can be used to keep track of the items handled for the current calendar)
78    pub fn counter(&self) -> usize {
79        self.counter
80    }
81
82
83
84    pub fn is_success(&self) -> bool {
85        self.n_errors == 0
86    }
87
88    /// Log an error
89    pub fn error(&mut self, text: &str) {
90        log::error!("{}", text);
91        self.n_errors += 1;
92    }
93    /// Log a warning
94    pub fn warn(&mut self, text: &str) {
95        log::warn!("{}", text);
96        self.n_errors += 1;
97    }
98    /// Log an info
99    pub fn info(&mut self, text: &str) {
100        log::info!("{}", text);
101    }
102    /// Log a debug message
103    pub fn debug(&mut self, text: &str) {
104        log::debug!("{}", text);
105    }
106    /// Log a trace message
107    pub fn trace(&mut self, text: &str) {
108        log::trace!("{}", text);
109    }
110    /// Send an event as a feedback to the listener (if any).
111    pub fn feedback(&mut self, event: SyncEvent) {
112        self.feedback_channel
113            .as_ref()
114            .map(|sender| {
115                sender.send(event)
116            });
117    }
118}