Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to stop a debouncer watcher if it's mut reference? #585

Open
Hellager opened this issue Apr 19, 2024 · 0 comments
Open

How to stop a debouncer watcher if it's mut reference? #585

Hellager opened this issue Apr 19, 2024 · 0 comments

Comments

@Hellager
Copy link

Here's a minimal example code, the question is about function shutdown.

If direct call handler.stop(), it will errors

error[E0507]: cannot move out of `*watcher` which is behind a mutable reference
    |
200 |             watcher.stop();
    |             ^^^^^^^ ------ `*watcher` moved due to this method call
    |             |
    |             move occurs because `*watcher` has type `Debouncer<notify::ReadDirectoryChangesWatcher, FileIdMap>`, whic, which does not implement the `Copy` trait

If the method stop(self) can be stop(&mut self), it will be ok.

So what's the proper way to stop the debouncer watcher if it's mut reference?

use chrono::prelude::*;
use notify::{Error, ReadDirectoryChangesWatcher, RecursiveMode, Watcher};
use notify_debouncer_full::{
    new_debouncer, DebounceEventResult, DebouncedEvent, Debouncer, FileIdMap,
};
use std::{path::Path, time::Duration};
use tokio::{runtime::Handle, sync::mpsc::Receiver};

pub struct NotifyHandler {
    pub notify_watcher: Option<Debouncer<ReadDirectoryChangesWatcher, FileIdMap>>,
    pub receiver: Option<Receiver<Result<Vec<DebouncedEvent>, Vec<Error>>>>,
}

impl NotifyHandler {
    pub async fn initialize_notify_scheduler(&mut self) {
        let (tx, rx) = tokio::sync::mpsc::channel(1);
        let rt = Handle::current();

        let debouncer = new_debouncer(
            Duration::from_secs(3),
            None,
            move |result: DebounceEventResult| {
                let tx = tx.clone();

                println!("calling by notify -> {:?}", &result);
                rt.spawn(async move {
                    if let Err(e) = tx.send(result).await {
                        println!("Error sending event result: {:?}", e);
                    }
                });
            },
        );

        match debouncer {
            Ok(watcher) => {
                println!("Initialize notify watcher success");
                self.notify_watcher = Some(watcher);

                self.receiver = Some(rx);
            }
            Err(error) => {
                println!("{:?}", error);
            }
        }
    }

    pub async fn watch(&mut self, path: &str) -> notify::Result<()> {
        let watch_path = Path::new(path);

        if watch_path.exists() {
            let is_file = watch_path.is_file();
            println!("Valid path {} is file {}", path, is_file);
        } else {
            println!("watch path {:?} not exists", watch_path);
        }

        if let Some(watcher) = self.notify_watcher.as_mut() {
            watcher
                .watcher()
                .watch(watch_path, RecursiveMode::Recursive)?;

            watcher
                .cache()
                .add_root(watch_path, RecursiveMode::Recursive);

            if let Some(mut rx) = self.receiver.take() {
                tokio::spawn(async move {
                    while let Some(res) = rx.recv().await {
                        match res {
                            Ok(events) => {
                                println!("events: {:?}", events);
                            }
                            Err(errors) => {
                                println!("errors: {:?}", errors)
                            }
                        }
                    }
                });
            }
        }

        Ok(())
    }

    pub async fn shutdown(&mut self) -> Result<(), std::io::Error> {
          if let Some(watcher) = self.notify_watcher().await {
                 if let Some(rcv) = self.receiver.as_mut() {
                      rcv.close();
                 }

                 watcher.stop();
           }
           Ok(())
    }
}

#[tokio::main]
async fn main() {
    let mut notifier: NotifyHandler = NotifyHandler {
        notify_watcher: None,
        receiver: None,
    };

    notifier.initialize_notify_scheduler().await;
    notifier.watch("D:\\Temp\\program\\test_md.txt").await.unwrap();

    loop {
        tokio::time::sleep(Duration::from_secs(3)).await;

        let time: DateTime<Local> = Local::now();

        println!(
            "{}: Hello, world!",
            time.format("%Y-%m-%d %H:%M:%S").to_string()
        );

        notifier.shutdown().unwrap();
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant