How to use websocket in tauri listen event

421 Views Asked by At

I attempted to create a websocket client in tauri to receive information and send it to the front-end application. The websocket cargo is tokio-tungstenite.but i have some problem in listen_gloabl function

Cargo.toml

serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.25.0", features = ["full"] }
tauri = { version = "1.5.2", features = ["system-tray", "dialog-all", "icon-ico"] }
rodio = "0.17.3"
futures-util = { version = "0.3.28", default-features = false, features = ["sink", "std"] }
tokio-tungstenite = "0.20.1"
url = "2.3.1"

main.rs

#[tokio::main]
async fn main() {
 tauri::Builder::default()
        .setup(|app| {
            let app_handle = app.handle();
            tauri::async_runtime::spawn(async move {
                connect_ws_async(&app_handle).await.unwrap();
            });

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
---------------------------------------------------------------------
async fn connect_ws_async(app_handle: &AppHandle) -> Result<()> {
    use url::Url;
    use futures_util::{StreamExt};
    use tokio::io::{AsyncReadExt, AsyncWriteExt};
    use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
    use tokio::sync::Mutex;

    let url = Url::parse("ws://127.0.0.1:8084/ws").expect("bad url!");
     let (mut ws_stream, _) = connect_async(url).await.expect("Failed to connect");
    println!("WebSocket handshake has been successfully completed");

    let (mut write, mut read) = ws_stream.split();

    let mutex_write = Mutex::new(write);
    let mutex_read = Mutex::new(read);

    let handle_write = app_handle.clone();
    let handle_read = app_handle.clone();

    handle_write.listen_global("msg_send", move |event:Event| {
        let msg = event.payload().unwrap();
        block_in_place(move || {
            tauri::async_runtime::block_on(async {
                // use mutex_write to send message
            });
        });
    });

    Ok(())
}

i see the same question in here. but i still have no diea.

1

There are 1 best solutions below

0
On

Not sure why would you want websockets in this configuration, you could perfectly use Tauri's IPC loop for this:

You could use invoke on the frontend side, and listen on both backend and frontend to exchange the events.

If you're not running your own websockets server inside the tauri, then you probably want to just use spawn when you process your event, instead of block_in_place.

tokio::spawn(async move {
  process(socket).await;
});

If you're looking to response from Rust to a websocket client in the frontend, then you can use this:

async fn handle_connection<'a>(app_handle:tauri::AppHandle, raw_stream: TcpStream, addr: SocketAddr) {
    let peer_map:tauri::State<PeerMap> = app_handle.state();
    ...
    let ws_stream = tokio_tungstenite::accept_async(raw_stream)
        .await
        .expect("Error during the websocket handshake occurred");
    println!("WebSocket connection established: {}", addr);

    // Insert the write part of this peer to the peer map.
    let (tx, rx) = unbounded();
    peer_map.lock().unwrap().insert(addr, tx.clone());
    ...
    let broadcast_incoming = incoming.try_for_each(|msg| {
        ...
        let response = format!("Rust received \"{}\"", text);
        tx.unbounded_send(response.as_str().into()).unwrap();

        future::ok(())
    });

    let receive_from_others = rx.map(Ok).forward(outgoing);

    pin_mut!(broadcast_incoming, receive_from_others);
    future::select(broadcast_incoming, receive_from_others).await;

    println!("{} disconnected", &addr);
    peer_map.lock().unwrap().remove(&addr);
}

In the case you are running tungstenite server, then you can follow my other tutorial here