How to push event handler events into an channel on an async main loop?

Consider:

use std::{cell::RefCell, rc::Rc};
use wasm_bindgen::{closure::Closure, JsCast};
use web_sys::{DedicatedWorkerGlobalScope, MessageEvent};

pub async fn main() {
    let mut g: DedicatedWorkerGlobalScope = js_sys::global()
        .dyn_into::<web_sys::DedicatedWorkerGlobalScope>()
        .unwrap();

    let (s, r) = async_channel::unbounded();

    web_sys::console::log_1(&"Rust: setting up handler".into());

    let onmessage_callback = Closure::wrap(Box::new(move |ev: MessageEvent| {
        web_sys::console::log_1(&"Rust: on_message".into());
        s.send(ev).await;})
        as Box<dyn FnMut(MessageEvent)>);
    g.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
    onmessage_callback.forget();

    g.post_message(&"ready".into());

    web_sys::console::log_1(&"Rust: main".into());}

  1. This code here does not compile because I am using async in the event handler, which takes regular functions.

  2. An alternative is to not use an async channel, to us a regular channel -- but then I run into the problem in the main loop, if there is nothing available, I need the code to busy wait.

I am looking for the following two properties:

  1. in the main loop, if there is an item, we process it; if there is not an item, we async block and get resumed when an item is pushed

  2. we can somehow route messages from the message handler to this channel

I think you just need to use try_send, instead of send, handling the case where the channel is closed, and perhaps ignoring the case where it is full since it is unbounded?

That is to say try_send appears to be a sync function which returns a Result rather than a future in async_channel.

1 Like