]> uap-core.de Git - note.git/commitdiff
add fs watch to notebook main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 19 Jul 2026 19:26:51 +0000 (21:26 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 19 Jul 2026 19:26:51 +0000 (21:26 +0200)
application/backend/src/backend.rs
application/backend/src/lib.rs
application/backend/src/notify.rs
application/note/src/note.rs
application/note/src/notebook.rs

index 43663309e4104f456c08bebc664d5c376acf56e6..6a3e800ccc77d2dc31cef85e082f2ab2970467cc 100644 (file)
@@ -49,6 +49,7 @@ use entity::notecontent::{Entity as NoteContent};
 use migration::prelude::Utc;
 use crate::lockmanager::LockManager;
 use crate::note::{create_nodename, randomize_nodename};
+use crate::notify::{fs_notify, FSWatch};
 use crate::storage::{*};
 
 pub struct Backend {
@@ -68,7 +69,8 @@ type CmdFuture = Pin<Box<dyn Future<Output = ()> + Send>>;
 pub struct BackendHandle {
     pub backend: Arc<Backend>,
     pub tx: tokio::sync::mpsc::UnboundedSender<CmdFuture>,
-    pub btx: tokio::sync::broadcast::Sender<BroadcastMessage>
+    pub btx: tokio::sync::broadcast::Sender<BroadcastMessage>,
+    pub ntx: tokio::sync::mpsc::UnboundedSender<FSWatch>
 }
 
 impl Clone for BackendHandle {
@@ -77,6 +79,7 @@ impl Clone for BackendHandle {
             backend: self.backend.clone(),
             tx: self.tx.clone(),
             btx: self.btx.clone(),
+            ntx: self.ntx.clone()
         }
     }
 }
@@ -260,6 +263,7 @@ impl Backend {
     /// The handle also contains a broadcast sender/receiver (btx, brx).
     pub fn start(self) -> (BackendHandle, JoinHandle<()>) {
         let (tx, mut rx) = mpsc::unbounded_channel::<CmdFuture>();
+        let (ntx, nrx) = mpsc::unbounded_channel::<FSWatch>();
         let broadcast_tx = self.broadcast.clone();
 
         let backend = Arc::new(self);
@@ -304,10 +308,22 @@ impl Backend {
             });
         });
 
+        // start fs notification
+        let fs_btx = broadcast_tx.clone();
+        let cmd = Box::pin(async move {
+            let ret = fs_notify(nrx, fs_btx).await;
+            if let Err(e) = ret {
+                println!("fs_noitify task failed {:?}", e);
+            }
+        });
+        let _ = tx.send(cmd);
+
+        // create backend handle
         let backend_handle = BackendHandle {
             backend: backend_clone,
             tx: tx,
             btx: broadcast_tx,
+            ntx: ntx,
         };
 
         (backend_handle, join)
@@ -384,6 +400,16 @@ impl BackendHandle {
         let _ = self.tx.send(cmd);
     }
     
+    pub fn get_notebook_local_path<F>(&self, collection_id: i32, callback: F)
+    where F: FnOnce(Result<Option<String>, DbErr>) + Send + 'static {
+        let backend = self.backend.clone();
+        let cmd = Box::pin(async move {
+            let result = get_collection_storage_path(&backend.db, collection_id).await;
+            callback(result);
+        });
+        let _ = self.tx.send(cmd);
+    }
+    
     pub fn get_note_content<F>(&self, note_id: i32, callback: F)
     where F: FnOnce(Result<Option<NoteContentRet>, DbErr>) + Send + 'static {
         let backend = self.backend.clone();
index 862d97d7972f004c426c9a6a703468f0f7759608..4257a2379af305b1b94bf84fb9ee26e91b953342 100644 (file)
@@ -1,5 +1,5 @@
 pub mod backend;
 pub mod lockmanager;
 pub mod storage;
-mod note;
-mod notify;
\ No newline at end of file
+pub mod note;
+pub mod notify;
\ No newline at end of file
index cb9fba6dbb908f3f7820161340fcc3fda0e0155d..c2297b564ccaef28a072bdcde0221a3c641c9840 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 use std::collections::HashMap;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
-use tokio::sync::mpsc;
-use tokio::sync::mpsc::Receiver;
+use tokio::sync::mpsc::{*};
 use crate::backend::BroadcastMessage;
 use std::collections::hash_map::Entry;
 
@@ -38,14 +37,14 @@ pub enum FSWatch {
     Remove(PathBuf),
 }
 
-pub async fn fs_notify(mut rx: Receiver<FSWatch>, btx: tokio::sync::broadcast::Sender<BroadcastMessage>) -> notify::Result<()> {
+pub async fn fs_notify(mut rx: UnboundedReceiver<FSWatch>, btx: tokio::sync::broadcast::Sender<BroadcastMessage>) -> notify::Result<()> {
     let mut path_map = HashMap::<PathBuf, u32>::new();
 
     let mut watcher = RecommendedWatcher::new(
         move |res: Result<Event, notify::Error>| {
             match res {
                 Ok(event) => {
-                    btx.send(BroadcastMessage::Notify(event));
+                    _ = btx.send(BroadcastMessage::Notify(event));
                 },
                 Err(e) => {
                     println!("Notify Error: {:?}", e);
@@ -91,8 +90,36 @@ pub async fn fs_notify(mut rx: Receiver<FSWatch>, btx: tokio::sync::broadcast::S
             }
         }
     }
+    
+    //println!("fs_notify end");
+    Ok(())
+}
 
+pub struct FSPathWatcher {
+    path: Option<PathBuf>,
+    tx: UnboundedSender<FSWatch>
+}
 
-    println!("fs_notify end");
-    Ok(())
+impl<'a> FSPathWatcher {
+    pub fn new(tx: UnboundedSender<FSWatch>) -> Self {
+        FSPathWatcher { path: None, tx }
+    }
+    
+    pub fn watch(&mut self, path: &Path) {
+        self.clear();
+        self.path = Some(path.to_path_buf());
+        let _ = self.tx.send(FSWatch::Add(path.to_path_buf()));
+    }
+    
+    pub fn clear(&mut self) {
+        if let Some(path) = self.path.take() {
+            let _ = self.tx.send(FSWatch::Remove(path));
+        }
+    }
+}
+
+impl<'a> Drop for FSPathWatcher {
+    fn drop(&mut self) {
+        self.clear();
+    }
 }
\ No newline at end of file
index b2a933e10079782ddbfa274d8f29b9af5f27c061..d1c627ebad9dd9d96507ab8399560f7e2ce7d0a9 100644 (file)
@@ -167,7 +167,7 @@ impl Note {
         if let Some(path) = &self.local_path && let Some(lastmodified) = self.local_lastmodified {
             let proxy = doc.doc_proxy();
             self.backend.get_file_metadata(path.as_path(), |result| {
-                proxy.call_mainthread(|doc, note| {
+                proxy.call_mainthread(|_doc, note| {
                     match result {
                         Ok(metadata) => {
                             if let Ok(lm) = metadata.modified() && let Some(lastmodified) = note.local_lastmodified {
index d07e0f5e967bf425c1445db63f04a7efe85be413..2fd1b3da6e2bd7e0d8b30e237203a665325ab600 100644 (file)
  */
 
 use std::any::Any;
+use std::path::Path;
 use std::rc::Rc;
 use std::sync::atomic::AtomicU64;
 use backend::backend::{BackendHandle, BroadcastMessage, NoteId, NoteTitleUpdate, NoteUpdate};
+use backend::notify::FSPathWatcher;
 use ui_rs::{action, ui_actions, UiModel};
 use ui_rs::ui::*;
 
@@ -46,6 +48,7 @@ static INSTANCE_ID: AtomicU64 = AtomicU64::new(1);
 pub struct Notebook {
     pub doc_ref: UiDocRef<Notebook>,
     pub backend: Rc<BackendHandle>,
+    pub fswatch: FSPathWatcher,
     pub instance_id: u64,
     pub broadcast_rx: tokio::sync::broadcast::Receiver<BroadcastMessage>,
     pub collection_id: i32,
@@ -65,6 +68,7 @@ impl Notebook {
         Notebook {
             doc_ref: Default::default(),
             backend: Rc::new(backend.clone()),
+            fswatch: FSPathWatcher::new(backend.ntx.clone()),
             instance_id: INSTANCE_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
             broadcast_rx: backend.btx.subscribe(),
             collection_id: id,
@@ -341,6 +345,9 @@ impl Notebook {
                         self.update_note(update);
                     }
                 },
+                BroadcastMessage::Notify(event) => {
+                    println!("fs notify event");
+                },
                 _ => {
 
                 },
@@ -401,6 +408,23 @@ impl NotebookItem {
                 }
             });
         });
+
+        let proxy = doc.doc_proxy();
+        backend.get_notebook_local_path(self.data.collection_id, |result|{
+            proxy.call_mainthread(|_n, nb| {
+                match result {
+                    Ok(pathstr) => {
+                        if let Some(pathstr) = pathstr {
+                            let path = Path::new(&pathstr);
+                            nb.fswatch.watch(&path);
+                        }
+                    },
+                    Err(err) => {
+                        eprintln!("get_notebook_local_path failed: {}", err);
+                    }
+                }
+            });
+        });
         
         self.model = Some(doc.clone());