3

I'm tring to use hotwatch to monitor folders for backups.

If any changes happen, expect to emit an event to frontend to update pages.

Then i found that it's not able to access AppHandle or Window in regular struct.

I have tried using lifetime, but as Tauri: accessing-an-apphandle-in-commands mention, it seems there's no way to mantain a long enough life time.

pub struct MonitorHandler<'a> {
    pub watcher: Hotwatch;
    pub app_handler: Option<&'a AppHandle>
}

impl MonitorHandler<'_> {
    pub fn initialize_app_handler(&mut self, handler: AppHandle) {
        self.app_handler = Some(&handler);
    }
    
    pub fn append_target(path: &str) {
        self.watcher.watch(path, |event| {
            self.app_handler.emit_all("update");
        })
    }
}

// whitch shows error
89 |     pub fn initialize_app_handler(&mut self, handler: AppHandle) {
   |                                   --------- has type `&mut MonitorHandler<'1>`
90 |         self.app_handler = Some(&handler);
   |         ------------------------^^^^^^^^-
   |         |                       |
   |         |                       borrowed value does not live long enough
   |         assignment requires that `handler` is borrowed for `'1`
...
93 |     }
   |     - `handler` dropped here while still borrowed

I have tried add app handle when setup, but it still not work, and with the same life time problem.

// main.rs
...
fn main() {
    let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
    let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor }));
    
    let context = tauri::generate_context!();
    tauri::Builder::default()
                .manage(store)
                .setup(|app| {
                       store.0.lock().unwrap().initialize_app_handler(app.app_handle());
                })
                .invoke_handler(tauri::generate_handler![
                    initialize_app_handler
                ])
                .run(context)
                .expect("error while running tauri application");
}

// which will occurs
   |
40 |   let store = MonitorHandler(Mutex::new(MonitorHandler {
   |       ----- move occurs because `store` has type `MonitorHandler<'_>`, which does not implement the `Copy` trait
...
51 |     .manage(store)
   |             ----- value moved here
52 |     .setup(|app| {
   |            ^^^^^^^^^^ value used here after move
53 |       store.0.lock().unwrap().initialize_app_handler(app.app_handle());
   |       ------- use occurs due to use in closure

I'm not familiar with rust and tauri, so is there some way to access the AppHandle or Window in my situation? or i have to do this in another way?

Here's my origin code

// handler.rs
// in this case, whether it's AppHandle or Window, the program will just stuck and not able to anything
pub struct MonitorHandler {
    pub watcher: Hotwatch;
    pub app_handler: Option<AppHandle>
}

impl MonitorHandler {
    pub fn initialize_app_handler(&mut self, handler: AppHandle) {
        self.app_handler = Some(handler.clone());
    }
}

pub struct MonitorHandler(pub Mutex<MonitorHandler>);

// main.rs
use hotwatch::Hotwatch;
use tauri::{ Manager, AppHandle };
use crate::handler::MonitorHandler;

#[tauri::command]
pub fn initialize_app_handler(monitor: State<MonitorHandler>, app_handler: AppHandle) -> bool {
    monitor.0.lock().unwrap().initialize_app_handler(app_handler);
    true
}

fn main() {
    let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
    let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor }));
    
    let context = tauri::generate_context!();
    tauri::Builder::default()
                .manage(store)
                .setup()
                .invoke_handler(tauri::generate_handler![
                    initialize_app_handler
                ])
                .run(context)
                .expect("error while running tauri application");
}

Hellagur
  • 93
  • 7

1 Answers1

1

The reason it get stuck is that the lock action cause a dead lock in the AppHandle since the stored sturct is assigned to the instance of the AppHandle.

How to solve the problem is simple, greet thanks for @FabianLars, here's the discussion Is there some way for backend to emit event actively?

To be brief, just initialize the struct and manage it in setup, like this

// handler.rs
pub struct MonitorHandler {
    pub watcher: Hotwatch;
    pub app_handler: AppHandle
}

impl MonitorHandler {
    pub fn do_something(&self) {
        // do something
        self.app_handler.emit_all("events", some_payload { ... });
    }
}

pub struct MonitorHandler(pub Mutex<MonitorHandler>);
// main.rs
use hotwatch::Hotwatch;
use tauri::{ Manager, AppHandle };
use crate::handler::MonitorHandler;

fn main() {
    // let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
    // let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor }));
    
    let context = tauri::generate_context!();
    tauri::Builder::default()
                .setup(move |app| {
                   let monitor = Hotwatch::new().expect("failed to initialize monitor_handler");
                   let struct_app_handle = app.handle().clone();
                   let store = MonitorHandler(Mutex::new(MonitorHandler{ watcher: monitor, app_handler: struct_app_handle }));

                   app.manage(store);
                })
                .invoke_handler(tauri::generate_handler![
                    initialize_app_handler
                ])
                .run(context)
                .expect("error while running tauri application");
}
mrouleau
  • 19
  • 3
Hellagur
  • 93
  • 7