From 64e521d549056862ca901458ef3a80daf9c4ddf5 Mon Sep 17 00:00:00 2001 From: Yuri Karamian Date: Sat, 25 Jul 2026 17:14:42 +0200 Subject: [PATCH] fix(ios): poll vault changes to avoid file descriptor exhaustion --- src-tauri/src/state.rs | 6 +-- src-tauri/src/vault/watcher.rs | 87 +++++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index 3c3e0de..2ebbe4e 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -1,14 +1,14 @@ use crate::search::SearchIndex; use crate::types::AppConfig; -use notify::RecommendedWatcher; +use crate::vault::watcher::VaultWatcher; use std::sync::atomic::AtomicBool; -use std::sync::Mutex; use std::sync::Arc; +use std::sync::Mutex; pub struct AppState { pub config: Mutex, pub search_index: Mutex>>, - pub watcher: Mutex>, + pub watcher: Mutex>, pub vault_transition: tokio::sync::Mutex<()>, pub importing: AtomicBool, pub syncing: AtomicBool, diff --git a/src-tauri/src/vault/watcher.rs b/src-tauri/src/vault/watcher.rs index cce1544..660a4c2 100644 --- a/src-tauri/src/vault/watcher.rs +++ b/src-tauri/src/vault/watcher.rs @@ -1,4 +1,4 @@ -use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; +use notify::{Config, EventKind, PollWatcher, RecommendedWatcher, RecursiveMode, Watcher}; use std::path::Path; use std::sync::mpsc; use std::time::Duration; @@ -8,14 +8,57 @@ use crate::state::AppState; use crate::types::FileEvent; use crate::vault::operations::helixnotes_dir; -pub fn start_watcher(app: AppHandle, vault_path: String) -> Result { +const IOS_POLL_INTERVAL: Duration = Duration::from_secs(10); +const NATIVE_POLL_INTERVAL: Duration = Duration::from_secs(1); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum WatcherBackend { + Recommended, + Poll, +} + +const fn watcher_backend_for_target(is_ios: bool) -> WatcherBackend { + if is_ios { + WatcherBackend::Poll + } else { + WatcherBackend::Recommended + } +} + +const fn poll_interval_for_backend(backend: WatcherBackend) -> Duration { + match backend { + WatcherBackend::Recommended => NATIVE_POLL_INTERVAL, + WatcherBackend::Poll => IOS_POLL_INTERVAL, + } +} + +pub enum VaultWatcher { + Recommended(RecommendedWatcher), + Poll(PollWatcher), +} + +impl VaultWatcher { + fn watch(&mut self, path: &Path, recursive_mode: RecursiveMode) -> notify::Result<()> { + match self { + Self::Recommended(watcher) => watcher.watch(path, recursive_mode), + Self::Poll(watcher) => watcher.watch(path, recursive_mode), + } + } +} + +pub fn start_watcher(app: AppHandle, vault_path: String) -> Result { let (tx, rx) = mpsc::channel(); - let mut watcher = RecommendedWatcher::new( - tx, - Config::default().with_poll_interval(Duration::from_secs(1)), - ) - .map_err(|e| e.to_string())?; + let backend = watcher_backend_for_target(cfg!(target_os = "ios")); + let config = Config::default().with_poll_interval(poll_interval_for_backend(backend)); + let mut watcher = match backend { + WatcherBackend::Recommended => VaultWatcher::Recommended( + RecommendedWatcher::new(tx, config).map_err(|e| e.to_string())?, + ), + WatcherBackend::Poll => { + VaultWatcher::Poll(PollWatcher::new(tx, config).map_err(|e| e.to_string())?) + } + }; watcher .watch(Path::new(&vault_path), RecursiveMode::Recursive) @@ -80,3 +123,33 @@ pub fn start_watcher(app: AppHandle, vault_path: String) -> Result