nullnet_libconfmon/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use platform::Platform;
use std::fmt::Display;
use std::{future::Future, path::PathBuf};
pub use watcher::{r#impl::Watcher, types::Snapshot};

mod platform;
mod watcher;

/// Represents the different kinds of errors that can occur during configuration monitoring.
#[derive(Debug)]
pub enum ErrorKind {
    ErrorInitializingWatcher,
    ErrorWatchingFile,
    ErrorReadingFile,
    ErrorUnsupportedPlatform,
}

/// A structured error type for `libconfmon`.
///
/// # Fields
/// - `kind`: The specific type of error.
/// - `message`: A detailed message explaining the error.
#[derive(Debug)]
pub struct Error {
    pub kind: ErrorKind,
    pub message: String,
}

impl Display for Error {
    /// Formats the `Error` for display.
    ///
    /// # Format
    /// The output includes the `ErrorKind` and the detailed message:
    /// `[ErrorKind] message`
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{:?}] {}", self.kind, self.message)
    }
}

/// Creates a new `Watcher` to monitor file changes.
///
/// # Parameters
/// - `platform`: The platform for which the watcher is being created (e.g., `"pfsense"` or `"opnsense"`).
/// - `poll_interval`: The interval (in milliseconds) at which files are polled for changes.
/// - `callback`: A closure or function to execute when changes are detected.
///
/// # Returns
/// - `Ok(Watcher<F, Fut>)`: A new instance of the `Watcher` if successfully initialized.
/// - `Err(Error)`: An error if initialization fails.
///
/// # Errors
/// - Returns an error with `ErrorKind::ErrorUnsupportedPlatform` if the platform is not supported.
/// - Returns an error with `ErrorKind::ErrorInitializingWatcher` if the watcher fails to initialize.
///
/// # Example
/// ```rust
/// use nullnet_libconfmon::{make_watcher, Error};
///
/// #[tokio::main]
/// async fn main() -> Result<(), Error> {
///     let watcher = make_watcher("pfsense", 1000, |snapshot| async move {
///         println!("Changes detected in snapshot: {:?}", snapshot);
///     }).await?;
///     Ok(())
/// }
/// ```
pub async fn make_watcher<F, Fut>(
    platform: &str,
    poll_interval: u64,
    callback: F,
) -> Result<Watcher<F, Fut>, Error>
where
    F: Fn(Snapshot) -> Fut,
    Fut: Future<Output = ()>,
{
    let pval = Platform::from_str(platform)?;
    let files = get_files_to_monitor(pval);
    let retval = Watcher::new(files, poll_interval, callback).await?;

    Ok(retval)
}

fn get_files_to_monitor(platform: Platform) -> Vec<PathBuf> {
    match platform {
        Platform::PfSense | Platform::OPNsense => vec![PathBuf::from("/conf/config.xml")],
    }
}