// Copyright 2019-2023 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher}; use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer}; use serde::Deserialize; use tauri::{ Manager, Resource, ResourceId, Runtime, Webview, ipc::{Channel, CommandScope, GlobalScope}, path::BaseDirectory, }; use std::time::Duration; use crate::{ SafeFilePath, commands::{CommandResult, resolve_path}, scope::Entry, }; #[allow(unused)] enum WatcherKind { Debouncer(Debouncer), Watcher(RecommendedWatcher), } impl Resource for WatcherKind {} #[derive(Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WatchOptions { base_dir: Option, #[serde(default)] recursive: bool, delay_ms: Option, } #[tauri::command] pub fn watch( webview: Webview, paths: Vec, options: WatchOptions, on_event: Channel, global_scope: GlobalScope, command_scope: CommandScope, ) -> CommandResult { let resolved_paths = paths .into_iter() .map(|path| { resolve_path( "watch", &webview, &global_scope, &command_scope, path, options.base_dir, ) }) .collect::>>()?; let recursive_mode = if options.recursive { RecursiveMode::Recursive } else { RecursiveMode::NonRecursive }; let watcher_kind = if let Some(delay) = options.delay_ms { let mut debouncer = new_debouncer( Duration::from_millis(delay), None, move |events: Result, Vec>| match events { Ok(events) => { for event in events { let _ = on_event.send(event.event); } } // TODO(v3): report the errors to the webview Err(errors) => { for error in errors { log::error!("file watcher error: {error}"); } } }, )?; for path in &resolved_paths { debouncer.watch(path, recursive_mode)?; } WatcherKind::Debouncer(debouncer) } else { let mut watcher = RecommendedWatcher::new( move |event: notify::Result| match event { Ok(event) => { let _ = on_event.send(event); } // TODO(v3): report the errors to the webview Err(error) => log::error!("file watcher error: {error}"), }, Config::default(), )?; for path in &resolved_paths { watcher.watch(path, recursive_mode)?; } WatcherKind::Watcher(watcher) }; let rid = webview.resources_table().add(watcher_kind); Ok(rid) }