najamelan / ws_stream_wasm

Wasm convenience API for WebSockets

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AsyncRead fails to read more than zero bytes

simlay opened this issue · comments

Hi there! Been using this project but want the AsyncRead/AsyncWrite versions. This bug might be in the async_io_stream crate.

Anyway, here's the unit test in tests/ws_io.rs I'm writing that's failing:

#[wasm_bindgen_test]
async fn round_trip_text_asyc_write() {
    let _ = console_log::init_with_level(Level::Trace);

    info!("starting test: round_trip");

    let (_ws, wsio) = WsMeta::connect(URL, None)
        .await
        .expect_throw("Could not create websocket");
    let message = "Hello from browser".to_string();

    let mut stream = wsio.into_io();

    AsyncWriteExt::write(&mut stream, message.clone().as_bytes()).await
        .expect_throw("Failed to write to websocket");

    let mut buf = vec![];
    let count = AsyncReadExt::read(&mut stream, &mut buf).await 
        .expect_throw("Failed to write to websocket");

    assert_eq!(message.as_bytes(), buf);
    assert_eq!(message.len(), count);
}

When I run ./ci/test.bash, it fails with:

failures: 

    ws_io::round_trip_text_asyc_write

test result: FAILED. 9 passed; 1 failed; 0 ignored
console.log div contained:
    panicked at 'assertion failed: `(left == right)`
      left: `[72, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 98, 114, 111, 119, 115, 101, 114]`, 
     right: `[]`', tests/ws_io.rs:214:5

Along with the wasm stack trace.

Anyway, I'm down to help try and fix this but I'm not sure where there's an issue. Thoughts?

I'm wrong and clearly still learning rust. This is a bug in my test.

let buf = vec![0, message.len()] fixed this unit test.

No worries mate, happy the lib serves you. I saw you want to clone WsStream. Be careful, it's not really designed for that. You probably best use one task to deal with the connection or 2, one for the Stream, one for the Sink and if you need to send from elsewhere in your app, send messages in through a channel.

For one cloning the event handlers will probably cause a memory leak. I would have to look into it deeper to see if there are other issues.

For one cloning the event handlers will probably cause a memory leak. I would have to look into it deeper to see if there are other issues.
Interesting.

Yeah. I was thinking it would possibly cause a memory leak. It's not ideal. I just want to split the sink and stream. If I find an elegant way to split them, would you be interested in a PR?

I just want to split the sink and stream.

So the way to split them correctly is by using futures::StreamExt::split. If you want to use AsyncRead/AsyncWrite, first call WsStream::into_io to get those, then call futures::io::AsyncReadExt::split.

Don't hesitate to open issues on here to ask questions if in doubt. Also on the rust user forum or reddit there is always people that can help with general questions about using async utilities. In any case it's worth to read through the docs of the futures lib to familiarize yourself with all the tools it makes available.

I can give some feedback on the code you posted above as well:

let message = "Hello from browser".to_string();

In general the idea of having AsyncRead/AsyncWrite on websockets is to have TCP like connections from the browser. Most appropriate is thus to use binary websocket messages instead of text messages. Of course if you use AsyncRead on both sides, for testing you can send a string through it. But if on one end you want to use Sink/Stream interface and on the other en AsyncRead, you should just send binary websocket messages.

let mut buf = vec![];

Most common way is for people to allocate a simple buffer on the stack. You don't really need to heap allocate here:

let mut buf = [0u8; 1024] for example.

let count = AsyncReadExt::read(&mut stream, &mut buf).await

Just FYI, you can write let count = stream.read(&mut buf).await as long as there is no other trait in scope that would make the read method ambiguous.