#using state inside of tauri::async_runtime::spawn

18 messages · Page 1 of 1 (latest)

spare dome
#

I am trying to write a "start_timer" command, one that starts a loop and updates state on each tick of the loop:

#[tauri::command]
async fn start_timer(
    state: tauri::State<'_, Mutex<AppState>>,
    app_handle: tauri::AppHandle,
) -> Result<(), String> {
    {
        let mut state = state.lock().await;
        state.is_active = true;
    }

    // Spawn a new asynchronous task for the timer
    tauri::async_runtime::spawn(async move {
        let mut interval = interval(Duration::from_secs(1));
        loop {
            interval.tick().await;
            let state_handle = app_handle.state::<Mutex<AppState>>();
            let mut state = state_handle.lock().await;
            if !state.is_active {
                break;
            }
            if state.remaining_time > 0 {
                state.remaining_time -= 1;
            } else {
                state.is_active = false;
                break;
            }
        }
    });

    Ok(())
}

This compiles, but it has a runtime error when invoked:

thread 'tokio-runtime-worker' panicked at C:\Users\quinn\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tauri-1.8.0\src\state.rs:51:7:
state not managed for field `state` on command `start_timer`. You must call `.manage()` before using this command
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I've tried various things (eg. using arc) but none seem to work or compile.

tough ledge
#

i had this exact issue with the web server we discussed in general. the issue was that i had to move my webserver state into the .manage() part of the tauri setup:

    Builder::default()
        .manage(Mutex::new(AppState::default()))
        .setup(|app| {
            // Additional setup if needed
            Ok(())
        })
``` this was not required in v1 but in v2 it is. after doing that my error went away
spare dome
#

my .manage line looks looks like this:

        .manage(AppState::new())
#

maybe i need to wrap it in a mutex?

spare dome
#

I am trying to have a command that when executed in js returns immediately but also keeps running the loop

teal cargo
spare dome
#

right. I don't want the spawn to block/await

teal cargo
#

I think events maybe apt for your requirement

#

Events are fire and forget so you can spawn the async process and have that in the background. The Tauri commands are more geared towards api like access to the backend

spare dome
#

ooooooh. yes that makes a lot more sense

#

Is it possible to access the tauri state object within an event handler?

#

basically, i'm trying to do this:

  • have tauri, not js, manage the timer loop / state of the timer
  • have the timer persist/keep running if the main window is closed
teal cargo
spare dome
#

do the state fields themselves need to be wrapped in a arc/mutex?

teal cargo
spare dome
#

yeah that makes sense

teal cargo
# spare dome do the state fields themselves need to be wrapped in a arc/mutex?

Depends on how much granular control you need. If you have a global arc and mutex then your state cannot be manipulated by parallel processes which manipulate different parts of the state itself.
So if you had a state A composed of B and C then you will have to wait for locking on A when trying to manipulate either B or C. So a process may be only accessing B but it will also lock C.

The other implementation is more granular with A not being a arc + mutex state but B and C are arc + mutex. In this approach you could manipulate B and C simultaneously

Keep in mind I am also still learning rust.

spare dome
#

same, i am very much a rust beginner lol. i'll refactor to use events instead of commands and see how far i get with that. thanks for your help!