rerun-io / ewebsock

A Rust Websocket client that compiles to both native and web
Apache License 2.0
219 stars 28 forks source link

Weird `expected a string argument` error #25

Closed brandonros closed 4 months ago

brandonros commented 11 months ago
#![no_std]

use ewebsock::{WsReceiver, WsSender};
use js_sys::Promise;
use log::Level;
use tokio::sync::OnceCell;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;

pub static mut WS_SENDER: OnceCell<WsSender> = OnceCell::const_new();
pub static mut WS_RECEIVER: OnceCell<WsReceiver> = OnceCell::const_new();

#[wasm_bindgen]
pub fn init_logging() -> Result<(), JsValue> {
    // init logging
    console_log::init_with_level(Level::Debug)
        .map_err(|_| JsValue::from_str("Failed to init logging"))?;
    // return
    Ok(())
}

#[wasm_bindgen]
pub async fn init_websocket() -> Result<JsValue, JsValue> {
    // init websocket
    log::info!("initializing websocket");
    let (sender, receiver) = ewebsock::connect("ws://127.0.0.1:3000")
        .map_err(|_| JsValue::from_str("Failed to call WebSocket API"))?;
    let _ = unsafe { WS_SENDER.set(sender) };
    let _ = unsafe { WS_RECEIVER.set(receiver) };
    // TODO: we actually need to poll for Event::OnOpened but we can't here until we return and call from another function?
    // return
    let promise = Promise::resolve(&true.into());
    let result = JsFuture::from(promise).await?;
    Ok(result)
}

#[wasm_bindgen]
pub async fn read_from_websocket() -> Result<JsValue, JsValue> {
    for _ in 0..100 {
        let result = unsafe { WS_RECEIVER.get().unwrap().try_recv() };
        if result.is_some() {
            let result = result.unwrap();
            log::info!("{:?}", result);
        }
    }
    // return
    let promise = Promise::resolve(&JsValue::NULL);
    let result = JsFuture::from(promise).await?;
    Ok(result)
}
[package]
name = "websocket_client"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]

[dependencies]
# logging
log = "0.4.20"
console_log = "1.0.0"
# websocket
ewebsock = "0.4.0"
# webassembly
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["console"] }
js-sys = "0.3"
wasm-bindgen-futures = "0.4"
# static init
tokio = { version = "1", features = ["sync"] }

image

romamik commented 4 months ago

I've just ran into the same issue. As far as I understand, it is because there was some error in web socket but error_event.message is undefined, which is unexpected by rust code.

//ewebsock-0.5.0/src/web.rs ws_connect_impl
   {
        let on_event = on_event.clone();
        let onerror_callback = Closure::wrap(Box::new(move |error_event: web_sys::ErrorEvent| {
            log::error!(
                "error event: {}: {:?}",
                error_event.message(), 
                error_event.error()
            );
            on_event(WsEvent::Error(error_event.message()));
        }) as Box<dyn FnMut(web_sys::ErrorEvent)>);
        ws.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
        onerror_callback.forget();
    }

// web_sys/src/features/gen_ErrorEvent.rs
#[wasm_bindgen]
extern "C" {
    # [wasm_bindgen (extends = Event , extends = :: js_sys :: Object , js_name = ErrorEvent , typescript_type = "ErrorEvent")]
    ...
        pub fn message(this: &ErrorEvent) -> String;

Actual event: image

It can be fixed in ewebsock by not using message, or by treating error_event as untyped js object.