From 7cfe5d00b983e8c70e4969bee5ee8f9ac223b8b8 Mon Sep 17 00:00:00 2001 From: scratchyone <scratchywon@gmail.com> Date: Thu, 24 Dec 2020 12:08:30 -0500 Subject: [PATCH] Add better error handling --- Cargo.toml | 23 ++++++++++++----------- examples/event.rs | 5 ++--- examples/polling.rs | 5 +++-- src/lib.rs | 42 +++++++++++++++++++++++++++++++----------- src/tests.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 27 deletions(-) create mode 100644 src/tests.rs diff --git a/Cargo.toml b/Cargo.toml index 7c2dd58..1b71c2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,13 +7,16 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -wasm-bindgen = "0.2" -js-sys = "0.3" log = "0.4.11" +thiserror = "1.0.22" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio-tungstenite = "0.12.0" -[dependencies.web-sys] -version = "0.3.22" -features = [ +[target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-bindgen = "0.2" +js-sys = "0.3" +web-sys = { version = "0.3.22", features = [ "BinaryType", "Blob", "ErrorEvent", @@ -21,15 +24,13 @@ features = [ "MessageEvent", "ProgressEvent", "WebSocket", -] +] } [dev-dependencies] console_log = "0.2.0" console_error_panic_hook = "0.1.6" wasm-bindgen-futures = "0.4.19" - -[dev-dependencies.web-sys] -version = "0.3.22" -features = [ +wasm-bindgen-test = "0.3" +web-sys = { version = "0.3.22", features = [ "Window", -] \ No newline at end of file +] } diff --git a/examples/event.rs b/examples/event.rs index e7b9223..cbb529d 100644 --- a/examples/event.rs +++ b/examples/event.rs @@ -2,10 +2,9 @@ use console_error_panic_hook; use console_log; use log::{error, info, Level}; use std::panic; -use wasm_bindgen::JsValue; -use wasm_sockets; +use wasm_sockets::{self, WebSocketError}; -fn main() -> Result<(), JsValue> { +fn main() -> Result<(), WebSocketError> { panic::set_hook(Box::new(console_error_panic_hook::hook)); // console_log and log macros are used instead of println! // so that messages can be seen in the browser console diff --git a/examples/polling.rs b/examples/polling.rs index e7eb6a8..01f78a7 100644 --- a/examples/polling.rs +++ b/examples/polling.rs @@ -3,10 +3,11 @@ use log::{info, Level}; use std::cell::RefCell; use std::panic; use std::rc::Rc; +#[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; -use wasm_sockets::{self, ConnectionStatus}; +use wasm_sockets::{self, ConnectionStatus, WebSocketError}; -fn main() -> Result<(), JsValue> { +fn main() -> Result<(), WebSocketError> { panic::set_hook(Box::new(console_error_panic_hook::hook)); // console_log and log macros are used instead of println! // so that messages can be seen in the browser console diff --git a/src/lib.rs b/src/lib.rs index ac4c33b..c9b995a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,10 +5,9 @@ //! use console_log; //! use log::{error, info, Level}; //! use std::panic; -//! use wasm_bindgen::JsValue; -//! use wasm_sockets; +//! use wasm_sockets::{self, WebSocketError}; //! -//! fn main() -> Result<(), JsValue> { +//! fn main() -> Result<(), WebSocketError> { //! panic::set_hook(Box::new(console_error_panic_hook::hook)); //! // console_log and log macros are used instead of println! //! // so that messages can be seen in the browser console @@ -47,10 +46,11 @@ //! use std::cell::RefCell; //! use std::panic; //! use std::rc::Rc; +//! #[cfg(target_arch = "wasm32")] //! use wasm_bindgen::prelude::*; -//! use wasm_sockets::{self, ConnectionStatus}; +//! use wasm_sockets::{self, ConnectionStatus, WebSocketError}; //! -//! fn main() -> Result<(), JsValue> { +//! fn main() -> Result<(), WebSocketError> { //! panic::set_hook(Box::new(console_error_panic_hook::hook)); //! // console_log and log macros are used instead of println! //! // so that messages can be seen in the browser console @@ -84,11 +84,15 @@ //! fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32; //! } //! ``` - +#[cfg(test)] +mod tests; use log::trace; use std::cell::RefCell; use std::rc::Rc; +use thiserror::Error; +#[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; +#[cfg(target_arch = "wasm32")] use wasm_bindgen::JsCast; use web_sys::{ErrorEvent, MessageEvent, WebSocket}; @@ -129,7 +133,7 @@ impl PollingClient { /// ``` /// PollingClient::new("wss://echo.websocket.org")?; /// ``` - pub fn new(url: &str) -> Result<Self, JsValue> { + pub fn new(url: &str) -> Result<Self, WebSocketError> { // Create connection let mut client = EventClient::new(url)?; let data = Rc::new(RefCell::new(vec![])); @@ -195,11 +199,20 @@ impl PollingClient { self.event_client.send_binary(message) } } + +#[derive(Debug, Clone, Error)] +pub enum WebSocketError { + #[error("Failed to create websocket connection: {0}")] + ConnectionCreationError(String), +} + +#[cfg(target_arch = "wasm32")] pub struct EventClient { /// The URL this client is connected to pub url: Rc<RefCell<String>>, - /// The raw web_sys WebSocket object this client is using - pub connection: Rc<RefCell<web_sys::WebSocket>>, + /// The raw web_sys WebSocket object this client is using. + /// Be careful when using this field, as it will be a different type depending on the compilation target. + connection: Rc<RefCell<web_sys::WebSocket>>, /// The current connection status pub status: Rc<RefCell<ConnectionStatus>>, /// The function bound to the on_error event @@ -211,6 +224,8 @@ pub struct EventClient { /// The function bound to the on_close event pub on_close: Rc<RefCell<Option<Box<dyn Fn() -> ()>>>>, } + +#[cfg(target_arch = "wasm32")] impl EventClient { /// Create a new EventClient and connect to a WebSocket URL /// @@ -218,9 +233,14 @@ impl EventClient { /// ``` /// EventClient::new("wss://echo.websocket.org")?; /// ``` - pub fn new(url: &str) -> Result<Self, JsValue> { + pub fn new(url: &str) -> Result<Self, WebSocketError> { // Create connection - let ws: web_sys::WebSocket = WebSocket::new(url)?; + let ws: web_sys::WebSocket = match WebSocket::new(url) { + Ok(ws) => ws, + Err(e) => Err(WebSocketError::ConnectionCreationError( + e.as_string().unwrap(), + ))?, + }; // For small binary messages, like CBOR, Arraybuffer is more efficient than Blob handling ws.set_binary_type(web_sys::BinaryType::Arraybuffer); diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..eb947e1 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,40 @@ +use wasm_bindgen_test::*; + +wasm_bindgen_test_configure!(run_in_browser); +use crate as wasm_sockets; +#[cfg(test)] +use console_error_panic_hook; +#[cfg(test)] +use console_log; +use log::{error, info, Level}; +use std::panic; +use wasm_bindgen::JsValue; + +#[wasm_bindgen_test] +fn event() { + panic::set_hook(Box::new(console_error_panic_hook::hook)); + // console_log and log macros are used instead of println! + // so that messages can be seen in the browser console + console_log::init_with_level(Level::Trace).expect("Failed to enable logging"); + info!("Creating connection"); + + let mut client = wasm_sockets::EventClient::new("wss://echo.websocket.org").unwrap(); + client.set_on_error(Some(Box::new(|error| { + error!("{:#?}", error); + }))); + client.set_on_connection(Some(Box::new(|client: &wasm_sockets::EventClient| { + info!("{:#?}", client.status); + info!("Sending message..."); + client.send_string("Hello, World!").unwrap(); + client.send_binary(vec![20]).unwrap(); + }))); + client.set_on_close(Some(Box::new(|| { + info!("Connection closed"); + }))); + client.set_on_message(Some(Box::new( + |client: &wasm_sockets::EventClient, message: wasm_sockets::Message| { + info!("New Message: {:#?}", message); + }, + ))); + info!("Connection successfully created"); +} -- GitLab