From 65e7961c8d54fae0bf168f6a0942c3c472c64875 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sun, 19 Jul 2026 16:44:29 +0200 Subject: [PATCH] add fs_notify --- Cargo.lock | 126 ++++++++++++++++++++++++++++- application/backend/Cargo.toml | 3 +- application/backend/src/backend.rs | 2 + application/backend/src/lib.rs | 3 +- application/backend/src/notify.rs | 98 ++++++++++++++++++++++ 5 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 application/backend/src/notify.rs diff --git a/Cargo.lock b/Cargo.lock index d7e56a9..d63a028 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,6 +327,7 @@ dependencies = [ "dav-rs", "entity", "migration", + "notify", "rand 0.10.2", "sea-orm", "tokio", @@ -1274,6 +1275,26 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "inotify" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "153be1941a183ec9ccd095ddbe17a8b8d435ef6c76e9e02451b933c3999af2c8" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" +dependencies = [ + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1307,6 +1328,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kqueue" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" +dependencies = [ + "bitflags", + "libc", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1495,6 +1536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.61.2", ] @@ -1540,6 +1582,35 @@ dependencies = [ "ui-rs", ] +[[package]] +name = "notify" +version = "9.0.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b44b771d4dd781ef14c84078693e67495da6b47f609f72e8a4da8420a861240e" +dependencies = [ + "bitflags", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "objc2-core-foundation", + "objc2-core-services", + "walkdir", + "windows-sys 0.61.2", + "xxhash-rust", +] + +[[package]] +name = "notify-types" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1611,6 +1682,25 @@ dependencies = [ "libm", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-core-services" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583300ad934cba24ff5292aee751ecc070f7ca6b39a574cc21b7b5e588e06a0b" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -2128,6 +2218,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.29" @@ -2793,7 +2892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -3110,6 +3209,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3203,6 +3312,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3373,6 +3491,12 @@ dependencies = [ "tap", ] +[[package]] +name = "xxhash-rust" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985eec839aaf2a1270af8f4ebcf63cf9401cfd90f0902f97c28d9f104ffbde72" + [[package]] name = "yansi" version = "1.0.1" diff --git a/application/backend/Cargo.toml b/application/backend/Cargo.toml index 3dcc054..b797265 100644 --- a/application/backend/Cargo.toml +++ b/application/backend/Cargo.toml @@ -9,4 +9,5 @@ entity = { path = "../../entity" } migration = { path = "../../migration" } sea-orm = { version = "2.0.0-rc", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-native-tls", "macros" ] } tokio = { version = "1.52.1", features = ["rt-multi-thread"] } -rand = "0.10.2" \ No newline at end of file +rand = "0.10.2" +notify = "9.0.0-rc.4" \ No newline at end of file diff --git a/application/backend/src/backend.rs b/application/backend/src/backend.rs index d7aec62..4366330 100644 --- a/application/backend/src/backend.rs +++ b/application/backend/src/backend.rs @@ -35,6 +35,7 @@ use tokio::runtime::Runtime; use std::sync::{Arc}; use std::thread::JoinHandle; use std::time::SystemTime; +use notify::Event; use tokio::fs; use tokio::sync::{broadcast, mpsc}; use tokio::sync::broadcast::error::SendError; @@ -85,6 +86,7 @@ pub enum BroadcastMessage { NotebookStructureUpdate(Vec), NoteTitleUpdate(NoteTitleUpdate), NoteUpdate(NoteUpdate), + Notify(Event) } #[derive(Clone, PartialEq, Eq)] diff --git a/application/backend/src/lib.rs b/application/backend/src/lib.rs index 4eed8cd..862d97d 100644 --- a/application/backend/src/lib.rs +++ b/application/backend/src/lib.rs @@ -1,4 +1,5 @@ pub mod backend; pub mod lockmanager; pub mod storage; -mod note; \ No newline at end of file +mod note; +mod notify; \ No newline at end of file diff --git a/application/backend/src/notify.rs b/application/backend/src/notify.rs new file mode 100644 index 0000000..cb9fba6 --- /dev/null +++ b/application/backend/src/notify.rs @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2026 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +use std::collections::HashMap; +use std::path::PathBuf; +use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher}; +use tokio::sync::mpsc; +use tokio::sync::mpsc::Receiver; +use crate::backend::BroadcastMessage; +use std::collections::hash_map::Entry; + +pub enum FSWatch { + Add(PathBuf), + Remove(PathBuf), +} + +pub async fn fs_notify(mut rx: Receiver, btx: tokio::sync::broadcast::Sender) -> notify::Result<()> { + let mut path_map = HashMap::::new(); + + let mut watcher = RecommendedWatcher::new( + move |res: Result| { + match res { + Ok(event) => { + btx.send(BroadcastMessage::Notify(event)); + }, + Err(e) => { + println!("Notify Error: {:?}", e); + } + } + }, + Config::default(), + )?; + + while let Some(fsw) = rx.recv().await { + match fsw { + FSWatch::Add(path) => { + match path_map.entry(path.clone()) { + Entry::Occupied(mut entry) => { + *entry.get_mut() += 1; + } + Entry::Vacant(entry) => { + watcher.watch(&path, RecursiveMode::NonRecursive)?; + entry.insert(1); + } + } + } + + FSWatch::Remove(path) => { + match path_map.entry(path.clone()) { + Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + + if *count > 1 { + *count -= 1; + } else { + watcher.unwatch(&path)?; + entry.remove(); + } + } + + Entry::Vacant(_) => { + // Remove without matching Add. + // Ignore or log, depending on your needs. + eprintln!("Attempted to remove unwatched path: {:?}", path); + } + } + } + } + } + + + println!("fs_notify end"); + Ok(()) +} \ No newline at end of file -- 2.52.0