dioxus icon indicating copy to clipboard operation
dioxus copied to clipboard

Desktop API to send large (1 MB+) payloads to Javascript

Open thorn132 opened this issue 1 year ago • 1 comments

The eval method for sending data to JavaScript cannot handle large payloads. In the following example, it freezes both the WebView and the backend when the payload exceeds 100k elements in debug mode, and 1M elements in release mode (on Windows 11, Git rev 53343bf).

use dioxus::prelude::*;

#[component]
fn Eval() -> Element {
    let mut payload_size = use_signal(|| 100usize);

    let received_size = use_resource(move || async move {
        let handler = eval(
            r#"
                console.time('recv');
                let msg = await dioxus.recv();
                console.timeEnd('recv');
                return msg.length;
            "#,
        )
        .unwrap();

        handler.send(vec![0u8; payload_size()].into()).unwrap();

        handler.await.unwrap().as_i64().unwrap()
    });

    rsx! {
        input {
            r#type: "number",
            value: "{payload_size}",
            oninput: move |ev| payload_size.set(ev.value().parse().unwrap_or(0))
        }
        h1 { "Received {received_size.read():?}" }
    }
}

fn main() {
    launch(Eval)
}

Since eval is not intended for large payloads/byte buffers, an alternative API supporting fast Rust->JS buffer transfers would be helpful. The API could look something like this:

let socket = use_binary_socket(r#"
    // defines the onmessage handler when the socket is created
    let ctx = document.getElementById("my-canvas").getContext("2d");
    let img = new ImageData(new Uint8ClampedArray(ev.data), 1000, 1000);
    ctx.putImageData(img, 0, 0);
"#);

socket.send(vec![0u8; 4_000_000]);

Also, the risks of using eval should be communicated in documentation and/or with runtime warnings for payloads exceeding some size threshold.

thorn132 avatar Feb 08 '24 22:02 thorn132

We would really appreciate this feature if it became available. Being able to pipe pixel buffers in opens dioxus up to a whole heap of opportunities for our commercial applications.

JulianRuiseco avatar May 01 '24 16:05 JulianRuiseco

You can send large chunks of binary data from rust to javascript with the custom asset handler added in https://github.com/DioxusLabs/dioxus/pull/1719

ealmloff avatar May 01 '24 17:05 ealmloff

I think this issue can be closed now. At the time it was created, asset handlers which included non-trivial processing time (e.g. reading a WGPU render buffer and encoding it for display in an img element) would cause other DOM edits to be applied in reverse order if the handler was called too frequently, which is what motivated trying eval and then finding that it also broke things.

That edit order bug with asset handlers doesn't happen in 0.5.1. The framerate of updates is still too low, but for now I think that's from my sub-optimal usage of the asset handler, so another solution for byte-buffer transfers probably isn't needed.

thorn132 avatar May 01 '24 18:05 thorn132

@thorn132 Thank you for the comment and update. This was very helpful

JulianRuiseco avatar May 01 '24 18:05 JulianRuiseco