Synphonyte / leptos-use

Collection of essential Leptos utilities inspired by React-Use / VueUse
https://leptos-use.rs/
Apache License 2.0
328 stars 72 forks source link

UseWebSocketReturn::ws is None #154

Closed stratecide closed 1 month ago

stratecide commented 2 months ago

I'm trying to get access to the websocket so I can send and receive different kinds of messages. Seeing that UseWebSocketReturn contains Option<WebSocket>, I assumed that was the way to access the raw websocket.

Expected behavior

let UseWebSocketReturn {
    ws,
    ..
} = use_websocket::<WsToClient, ProstCodec>("/pub_api/ws");

tracing::debug!("websocket: {}", ws.is_some());

I expected ws to be Some(WebSocket), so the above code should print "websocket: true".

Actual behavior

Instead, "websocket: false" is printed. In my browser's Network tab I can see that a connection request is made and the server responds with 101 Switching Protocols. So websockets should be supported.

Possible fix

I had a look at the source code for use_websocket_with_options (which is called by use_websocket). It returns

UseWebSocketReturn {
    ...
    ws: ws_ref.get_value(),
    ...
}

before ws_ref gets set. ws_ref gets set later, when open() is called inside a create_effect or by the user.

Maybe ws_ref could be returned directly, without calling "get_value()"? That would change pub ws: Option<WebSocket>, to pub ws: StoredValue<Option<WebSocket>>, in UseWebSocketReturn.

ws.get_value() should then return the websocket once it has been opened for the first time. I have not tested if this works, yet!

maccesch commented 2 months ago

I guess it should be a signal then, so you can easly get it in an effect, right?

stratecide commented 2 months ago

That would also work, yes. So far I check ready_state in an effect and then (try to) send a message:

create_effect(move |_| {
    match ready_state.get() {
        ConnectionReadyState::Open => {
            ws.send(...);
        }
        _ => ()
    }
});
maccesch commented 2 months ago

Why don't you use the send method that is returned? This is the intended way to use this function.

stratecide commented 2 months ago

The kind of data my client sends to the server is different than the data sent by the server to the client. So I have created two enums: One for messages sent from the client to the server and one for messages sent from the server to the client.

The problem with that is that use_websocket forces the use of the same type for sending and receiving, since pub message: Signal<Option<T>>, is used for receiving messages, while SendFn: Fn(&T) + Clone + 'static is used for sending. Both use the same generic type "T".

My problem could be sidestepped by having the send function use a different generic type than the message signal.

Another way to sidestep the problem would be using the same type for sending and receiving. I'd prefer avoiding that since my two enums really have little in common.

maccesch commented 2 months ago

I'll work on supporting different types for sending and receiving

deep-gaurav commented 1 month ago

I also encountered this, I need WebSocket access to get buffered_amount for which there is no signal in use_websocket. I think we can return a signal to websocket or StoredValue itself.

maccesch commented 1 month ago

This is now fixed and released in version 0.13.4

deep-gaurav commented 1 month ago

Thanks!

stratecide commented 1 month ago

I just tested the update and it works perfectly. Thank you :)