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 {
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 {
backend: self.backend.clone(),
tx: self.tx.clone(),
btx: self.btx.clone(),
+ ntx: self.ntx.clone()
}
}
}
/// 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);
});
});
+ // 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)
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();
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
* 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;
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);
}
}
}
+
+ //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
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 {
*/
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::*;
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,
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,
self.update_note(update);
}
},
+ BroadcastMessage::Notify(event) => {
+ println!("fs notify event");
+ },
_ => {
},
}
});
});
+
+ 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());