refactor: move fs-watch to fs (#369)

This commit is contained in:
Lucas Fernandes Nogueira
2023-05-17 22:50:45 -03:00
committed by GitHub
parent b064718f32
commit ac76abcebd
22 changed files with 52 additions and 1689 deletions
+4
View File
@@ -13,6 +13,10 @@ pub enum Error {
/// Invalid glob pattern.
#[error("invalid glob pattern: {0}")]
GlobPattern(#[from] glob::PatternError),
/// Watcher error.
#[cfg(feature = "watch")]
#[error(transparent)]
Watch(#[from] notify::Error),
}
impl Serialize for Error {
+11 -1
View File
@@ -12,6 +12,8 @@ mod commands;
mod config;
mod error;
mod scope;
#[cfg(feature = "watch")]
mod watcher;
pub use config::Config;
pub use error::Error;
@@ -47,7 +49,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<Config>> {
commands::remove_file,
commands::rename_file,
commands::exists,
commands::metadata
commands::metadata,
#[cfg(feature = "watch")]
watcher::watch,
#[cfg(feature = "watch")]
watcher::unwatch
])
.setup(|app: &tauri::AppHandle<R>, api| {
let default_scope = FsScope::default();
@@ -58,6 +64,10 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<Config>> {
.map(|c| &c.scope)
.unwrap_or(&default_scope),
)?);
#[cfg(feature = "watch")]
app.manage(watcher::WatcherCollection::default());
Ok(())
})
.on_event(|app, event| {
+113
View File
@@ -0,0 +1,113 @@
use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
use notify_debouncer_mini::{new_debouncer, DebounceEventResult, Debouncer};
use serde::Deserialize;
use tauri::{api::ipc::Channel, command, Runtime, State};
use crate::Result;
use std::{
collections::HashMap,
path::PathBuf,
sync::{
mpsc::{channel, Receiver},
Mutex,
},
thread::spawn,
time::Duration,
};
type Id = u32;
#[derive(Default)]
pub struct WatcherCollection(Mutex<HashMap<Id, (WatcherKind, Vec<PathBuf>)>>);
enum WatcherKind {
Debouncer(Debouncer<RecommendedWatcher>),
Watcher(RecommendedWatcher),
}
fn watch_raw<R: Runtime>(on_event: Channel<R>, rx: Receiver<notify::Result<Event>>) {
spawn(move || {
while let Ok(event) = rx.recv() {
if let Ok(event) = event {
// TODO: Should errors be emitted too?
let _ = on_event.send(&event);
}
}
});
}
fn watch_debounced<R: Runtime>(on_event: Channel<R>, rx: Receiver<DebounceEventResult>) {
spawn(move || {
while let Ok(event) = rx.recv() {
if let Ok(event) = event {
// TODO: Should errors be emitted too?
let _ = on_event.send(&event);
}
}
});
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WatchOptions {
delay_ms: Option<u64>,
recursive: bool,
}
#[command]
pub async fn watch<R: Runtime>(
watchers: State<'_, WatcherCollection>,
id: Id,
paths: Vec<PathBuf>,
options: WatchOptions,
on_event: Channel<R>,
) -> Result<()> {
let mode = if options.recursive {
RecursiveMode::Recursive
} else {
RecursiveMode::NonRecursive
};
let watcher = if let Some(delay) = options.delay_ms {
let (tx, rx) = channel();
let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?;
let watcher = debouncer.watcher();
for path in &paths {
watcher.watch(path, mode)?;
}
watch_debounced(on_event, rx);
WatcherKind::Debouncer(debouncer)
} else {
let (tx, rx) = channel();
let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
for path in &paths {
watcher.watch(path, mode)?;
}
watch_raw(on_event, rx);
WatcherKind::Watcher(watcher)
};
watchers.0.lock().unwrap().insert(id, (watcher, paths));
Ok(())
}
#[command]
pub async fn unwatch(watchers: State<'_, WatcherCollection>, id: Id) -> Result<()> {
if let Some((watcher, paths)) = watchers.0.lock().unwrap().remove(&id) {
match watcher {
WatcherKind::Debouncer(mut debouncer) => {
for path in paths {
debouncer.watcher().unwatch(&path)?
}
}
WatcherKind::Watcher(mut watcher) => {
for path in paths {
watcher.unwatch(&path)?
}
}
};
}
Ok(())
}