mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-05-11 12:37:34 +02:00
refactor: move fs-watch to fs (#369)
This commit is contained in:
committed by
GitHub
parent
b064718f32
commit
ac76abcebd
@@ -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
@@ -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| {
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
Reference in New Issue
Block a user