substrate_core/watcher_port.rs
1//! WatcherPort — debounced filesystem watch events.
2//!
3//! Core defines the port contract; `file-watcher` wraps the `notify` crate
4//! (inotify / FSEvents / ReadDirectoryChangesW) with a debounced stream.
5
6use std::path::{Path, PathBuf};
7use std::time::Duration;
8
9use async_trait::async_trait;
10use serde::{Deserialize, Serialize};
11use uuid::Uuid;
12
13use crate::error::Result;
14
15/// Kind of filesystem change observed by a watcher.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17pub enum WatchEventKind {
18 /// A path was created.
19 Create,
20 /// A path was modified.
21 Modify,
22 /// A path was removed.
23 Remove,
24 /// Any other/normalized event kind.
25 Other,
26}
27
28/// A single debounced watch notification.
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30pub struct WatchEvent {
31 /// Affected path.
32 pub path: PathBuf,
33 /// Normalized event kind.
34 pub kind: WatchEventKind,
35}
36
37/// Subscription handle returned by [`WatcherPort::watch`].
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39pub struct WatchHandle {
40 /// Adapter-local subscription id.
41 pub id: Uuid,
42}
43
44/// Filesystem watch port with debounced event delivery.
45#[async_trait]
46pub trait WatcherPort: Send + Sync {
47 /// Begin watching `path` (non-recursive) with `debounce_ms` coalescing.
48 async fn watch(&self, path: &Path, debounce_ms: u64) -> Result<WatchHandle>;
49
50 /// Receive the next debounced event, waiting up to `timeout`.
51 async fn recv_event(
52 &self,
53 handle: &WatchHandle,
54 timeout: Duration,
55 ) -> Result<Option<WatchEvent>>;
56
57 /// Stop watching and release resources for `handle`.
58 async fn unwatch(&self, handle: &WatchHandle) -> Result<()>;
59}