Search code examples
rustrust-rockettauri

How to emit a Tauri window event from rocket request


I hope this is not too obscure.

I am playing around with Tauri where I want to expose a web based control panel for the app. By going to a url on the local network, eg http://192.168.1.101:8000/some-action, it will send a window message to the Tauri app running on that machine. Imagine a dashboard app in an office where users on the network can control how the app behaves via a web url.

Here is my rust code so far:

// use rocket runtime
#[rocket::main]
async fn main() {
    tauri::Builder::default()
        .setup(|app| {

            let window = app.get_window("main").unwrap();

            #[get("/")]
            fn index() {
                // this is where I want to emit the window event if possible
                //window.emit("from-rust", format!("message")).expect("failed to emit");
            }
            
            // mount the rocket instance
            tauri::async_runtime::spawn(async move {
                let _rocket = rocket::build()
                    .mount("/", routes![index])
                    .launch().await;
                });
            
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

I am able to run the rocket server, however, I can't work out how to send the window event from the rocket request handler function.

Any suggestions or insights would be very much appreciated.


Solution

  • fn items are not allowed to capture their environment. But since #[get(...)] is only allowed to be used on fn you can't use it.

    You can just implement the required traits for a custom struct yourself though.

    use async_trait::async_trait;
    use rocket::http::Method;
    use rocket::route::{Handler, Outcome};
    use rocket::{Data, Request, Route};
    use tauri::{Manager, generate_context};
    
    #[derive(Clone)]
    struct WindowHandler {
        window: tauri::Window,
    }
    
    impl WindowHandler {
        fn new(window: tauri::Window) -> Self {
            Self { window }
        }
    }
    
    #[async_trait]
    impl Handler for WindowHandler {
        async fn handle<'r>(&self, request: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> {
            self.window
                .emit("from-rust", format!("message"))
                .expect("failed to emit");
            todo!()
        }
    }
    impl From<WindowHandler> for Vec<Route> {
        fn from(value: WindowHandler) -> Self {
            vec![Route::new(Method::Get, "/", value)]
        }
    }
    
    #[rocket::main]
    async fn main() {
        tauri::Builder::default()
            .setup(|app| {
                let window = app.get_window("main").unwrap();
    
                let index = WindowHandler::new(window);
                // mount the rocket instance
                tauri::async_runtime::spawn(async move {
                    let _rocket = rocket::build().mount("/", index).launch().await;
                });
                Ok(())
            })
            .run(generate_context!())
            .expect("error while running tauri application");
    }
    

    Or another possibility is to use a global WINDOW: OnceLock<Window> like this:

    #![feature(once_cell)]
    use std::sync::OnceLock;
    
    use rocket::{get, routes};
    use tauri::{Manager, generate_context, Window};
    
    static WINDOW: OnceLock<Window> = OnceLock::new();
    #[rocket::main]
    async fn main() {
        tauri::Builder::default()
            .setup(|app| {
                let window = app.get_window("main").unwrap();
    
                _ = WINDOW.set(window);
    
                #[get("/")]
                fn index() {
                    WINDOW.get().expect("window is available").emit("from-rust", format!("message")).expect("failed to emit");
                }
                // mount the rocket instance
                tauri::async_runtime::spawn(async move {
                    let _rocket = rocket::build().mount("/", routes![index]).launch().await;
                });
                Ok(())
            })
            .run(generate_context!())
            .expect("error while running tauri application");
    }