I am trying to build this app where I have a command that starts a thread that publishes many messages to RabbitMQ, and then emits an event once it is done publishing.
I have a managed ConnectionMutex
struct using tauri
's state API, and I am also getting the window handle to emit events.
the code looks like the following:
use tauri::async_runtime::Mutex;
pub struct ConnectionMutex(pub Mutex<Option<RabbitMqConnection>>);
#[tauri::command]
pub async fn publish_message(
connection_mutex: tauri::State<'_, ConnectionMutex>,
window: tauri::Window,
) -> Result<(), String> {
tauri::async_runtime::spawn(async move {
let lock = connection_mutex
.0
.try_lock()
.map_err(|_| String::from("cannot change connection while it is being used"))
.unwrap();
let conn = lock.as_ref().ok_or("no rabbitmq connection").unwrap();
let _ = rabbitmq::publishing::publish(
&conn.target,
&conn.channel,
window,
)
.await;
});
Ok(())
}
I get a compiler error saying: borrowed data escapes outside of function
. this error makes sense to me, I understand why this would not be safe because the rust borrow checker could no longer track the borrowed variable and will be unable to free it at the correct time.
However, I have no idea the correct way to achieve this kind of stuff in Rust.
I also tried setting the lifetime of the State
variable to static,like this:
#[tauri::command]
pub async fn publish_message(
connection_mutex: tauri::State<'static, ConnectionMutex>,
window: tauri::Window,
) -> Result<(), String>
but I get a different error: __tauri_message__ does not live long enough
A common approach is to wrap the Mutex
in Arc
so that you can safely share references to the underlying Mutex
across async
tasks. (See also the example in the docs).
So your ConnectionMutex
could look like:
pub struct ConnectionMutex(pub Arc<Mutex<Option<RabbitMqConnection>>>);
Then, when you want to pass the connection when you spawn an async
task, you first clone()
the ConnectionMutex
to give the task it's own copy of the reference.
#[tauri::command]
pub async fn publish_message(
connection_mutex: tauri::State<'_, ConnectionMutex>,
window: tauri::Window,
) -> Result<(), String> {
let connection = Arc::clone(&connection_mutex.0);
tauri::async_runtime::spawn(async move {
let lock = connection
.try_lock()
.map_err(|_| String::from("cannot change connection while it is being used"))
.unwrap();
let conn = lock.as_ref().ok_or("no rabbitmq connection").unwrap();
let _ = rabbitmq::publishing::publish(
&conn.target,
&conn.channel,
window,
)
.await;
});
Ok(())
}