rerun-io / ewebsock

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

Failing to run web demo #36

Open patrickelectric opened 5 months ago

patrickelectric commented 5 months ago

image

emilk commented 5 months ago

Does it work when using ./example_app/build_web.sh in the repo?

patrickelectric commented 4 months ago

just to be sure, is there something different from adding directly into an eframe_template + trunk serve and running the sh ? I'll try to replicate in the example and see how it goes

patrickelectric commented 4 months ago

I got the same problem with the example once adding my code.. not sure exactly how. My web.rs, I have the same code working with tugstenio websocket.

use eframe::wasm_bindgen::{self, prelude::*};

/// This is the entry-point for all the web-assembly.
/// This is called once from the HTML.
/// It loads the app, installs some callbacks, then returns.
/// You can add more callbacks like this if you want to call in to your code.
#[wasm_bindgen]
pub async fn start(canvas_id: &str) -> Result<(), JsValue> {
    // Redirect `log` message to `console.log` and friends:
    eframe::WebLogger::init(log::LevelFilter::Debug).ok();

    // let app = crate::ExampleApp::default();
    let app = App::default().await;
    eframe::WebRunner::new()
        .start(canvas_id, Default::default(), Box::new(|_cc| Box::new(app)))
        .await?;
    Ok(())
}

use chrono::prelude::*;
use humantime::format_duration;
//use tokio_with_wasm::runtime::Runtime;
use tokio_with_wasm::tokio_wasm::sync::mpsc;
use futures_util::{SinkExt, StreamExt};
use tokio_tungstenite_wasm::connect;
use url::Url;
use std::collections::BTreeMap;

struct MessageInfo {
    value: serde_json::Value,
    previous_value: Option<serde_json::Value>,
    last_sample_time: DateTime<chrono::Utc>,
}

impl MessageInfo {
    pub fn update(&mut self, value: serde_json::Value) {

    }
}

struct App {
    receiver: mpsc::Receiver<String>,
    vehicles: BTreeMap<u8, BTreeMap<u8, BTreeMap<String, MessageInfo>>>,
}

impl App {
    async fn default() -> Self {
        let (tx, rx) = mpsc::channel(32);
        wasm_bindgen_futures::spawn_local(connect_and_receive_messages(tx));
        Self {
            receiver: rx,
            vehicles: Default::default(),
        }
    }
}

async fn connect_and_receive_messages(mut tx: mpsc::Sender<String>) {
    let ws =
        ewebsock::connect("ws://0.0.0.0:8088/ws/mavlink", ewebsock::Options {
            max_incoming_frame_size: 100,
        }).expect("Can't connect");
    let (mut sende, receiver) = ws;

    while let Some(ewebsock::WsEvent::Message(message)) = receiver.try_recv() {
        if let ewebsock::WsMessage::Text(message) = message {
            eframe::web_sys::console::log_1(&message.to_string().into());
            tx.send(message)
                .await
                .unwrap();
        }
    }
}

impl eframe::App for App {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ctx.request_repaint();
            while let Ok(message) = self.receiver.try_recv() {
                let Ok(message) = serde_json::from_str::<serde_json::Value>(&message) else {
                    continue;
                };
                let system_id: u8 = message["header"]["system_id"].as_u64().unwrap() as u8;
                let component_id: u8 = message["header"]["component_id"].as_u64().unwrap() as u8;
                let message_name: String = message["message"]["type"].to_string().trim_matches(['"']).to_string();
                if !self.vehicles.contains_key(&system_id) {
                    self.vehicles.insert(system_id, Default::default());
                }
                if !self.vehicles[&system_id].contains_key(&component_id) {
                    self.vehicles.get_mut(&system_id).unwrap().insert(component_id, Default::default());
                }
                let previous_message = match self.vehicles.get(&system_id).unwrap().get(&component_id).unwrap().get(&message_name) {
                    Some(previous_message) => Some(previous_message.value.clone()),
                    None => None,
                };

                self.vehicles.get_mut(&system_id).unwrap().get_mut(&component_id).unwrap().insert(message_name, MessageInfo {
                    value: message,
                    previous_value: previous_message,
                    last_sample_time: Utc::now(),
                });
            }

            for (system_id, components) in &self.vehicles {
                egui::CollapsingHeader::new(format!("Vehicle {system_id}")).default_open(true).show(ui, |ui| {
                    for (component_id, messages) in components {
                        egui::CollapsingHeader::new(format!("Component {component_id}")).default_open(true).show(ui, |ui| {
                            for (name, message) in messages {
                                ui.collapsing(name, |ui| {
                                    ui.label(serde_json::to_string_pretty(&message.value).unwrap());
                                    ui.label(format_duration((Utc::now() - message.last_sample_time).to_std().unwrap()).to_string() + " Ago");
                                });
                            }
                        });
                    }
                });
            }
        });
    }
}
emilk commented 4 months ago

check your wasm bindgen version? 🤷

red-avtovo commented 3 months ago

That happened to me as well. When I try to connect to a non-existing web socket, then on the wasm version, I receive this error. On the native version, I receive a proper Error response

image
red-avtovo commented 3 months ago

Here are my dependenices:

[dependencies]
egui = "0.28"
egui-notify = "0.15"
eframe = { version = "0.28" , default-features=false, features = ["default_fonts", "glow"] }

log = "0.4"

ewebsock = "0.6"

serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

strum = { version = "0.26", features = ["derive"], optional = true }

# native:
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
env_logger = "0.11"

# web:
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen-futures = "0.4"
web-sys = { version = "0.3.4", features=["Window", "MediaQueryList", "Navigator"] }