vstorage 0.7.0

Common API for various icalendar/vcard storages.
Documentation
// Copyright 2024-2025 Hugo Osvaldo Barrera
//
// SPDX-License-Identifier: EUPL-1.2

//! Monitor a storage for changes as they occur.
use std::time::Duration;

use futures_util::future::BoxFuture;
use log::debug;
use tokio::time::{Interval, MissedTickBehavior};

use crate::Href;

/// Monitors a storage for live events.
///
/// Implementations shall yield [`Event::General`] if:
///
/// - The underlying storage does not support monitoring for individual changes. In this case, the
///   event should be returned every `interval`.
/// - There is a possibility that some events are lost (e.g.: due to having to reconnect, or a
///   buffer overflow).
///
/// Monitors MUST yield events for changes that have occurred since the last access to this
/// storage. If this is unknown (e.g.: no state is preserved between executions), an
/// [`Event::General`] must be emitted immediately upon the first call to
/// [`StorageMonitor::next_event`].
///
/// # See also
///
/// - [[`Storage::monitor`][crate::base::Storage::monitor]
pub trait StorageMonitor: Send {
    /// Return the next event on this storage.
    ///
    /// Returns a future which resolves the next change event.
    ///
    /// # Cancel safety
    ///
    /// Implementations MUST be cancel safe. If the returned future is dropped before completion, the
    /// next call MUST return the following event without dropping any events.
    // TODO: backends might return more than one event at a time, so this should return a Vec<Event>
    fn next_event(&mut self) -> BoxFuture<'_, Event>;
}

/// Event yielded when monitoring a storage.
///
/// Returned by [`StorageMonitor::next_event`]
#[derive(Debug, PartialEq)]
pub enum Event {
    /// No details are known; only that something has changed.
    ///
    /// Indicates that a storage provided insufficient granularity and needs to be rescanned.
    /// Example situations are a buffer being full, a stateful connection was dropped or the
    /// storage does not provide gradual events.
    General,
    /// Details of the specific are known.
    Specific(SpecificEvent),
}

/// Specific event on a given resource or collection.
///
/// See also: [`Event`].
#[derive(Debug, PartialEq)]
pub struct SpecificEvent {
    /// The location of the resource.
    pub href: Href,
    /// The type of event that occurred on the resource.
    pub kind: EventKind,
}

/// Kind of event.
///
/// See: [`SpecificEvent`]
#[derive(Debug, PartialEq)]
pub enum EventKind {
    /// A new element was created or an existing one was modified.
    Change,
    /// A previously seen element has been deleted.
    Delete,
    // /// A property has changed.
    // Property { name: String },
    // Unknown,
}

/// Fallback monitor for storages that don't implement one.
pub struct IntervalMonitor {
    timer: Interval,
}

impl IntervalMonitor {
    /// Create a new monitor with a given interval.
    #[must_use]
    pub fn new(interval: Duration) -> IntervalMonitor {
        let mut timer = tokio::time::interval(interval);
        timer.set_missed_tick_behavior(MissedTickBehavior::Delay);
        IntervalMonitor { timer }
    }
}

impl StorageMonitor for IntervalMonitor {
    fn next_event(&mut self) -> BoxFuture<'_, Event> {
        Box::pin(async {
            self.timer.tick().await;
            debug!("Interval timer ticked");
            Event::General
        })
    }
}