From 63e8b5371819c25e3bc87558bde85271ff7eed40 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Sat, 23 Nov 2024 11:44:58 +0200 Subject: [PATCH 01/14] draft wasm --- examples/websocket_client.rs | 2 +- relay_client/Cargo.toml | 11 ++++++++--- relay_client/src/lib.rs | 9 +-------- relay_client/src/websocket.rs | 7 +++++-- relay_client/src/websocket/inbound.rs | 2 +- relay_client/src/websocket/stream.rs | 22 ++++++++++------------ 6 files changed, 26 insertions(+), 27 deletions(-) diff --git a/examples/websocket_client.rs b/examples/websocket_client.rs index 8003b6f..4458157 100644 --- a/examples/websocket_client.rs +++ b/examples/websocket_client.rs @@ -19,7 +19,7 @@ struct Args { address: String, /// Specify WalletConnect project ID. - #[structopt(short, long, default_value = "3cbaa32f8fbf3cdcc87d27ca1fa68069")] + #[structopt(short, long, default_value = "5c9d8a326d3afb25ed1dff90f6d1807a")] project_id: String, } diff --git a/relay_client/Cargo.toml b/relay_client/Cargo.toml index 503cb2e..3e0532d 100644 --- a/relay_client/Cargo.toml +++ b/relay_client/Cargo.toml @@ -5,8 +5,9 @@ edition = "2021" license = "Apache-2.0" [features] -default = ["tokio-tungstenite/native-tls"] -rustls = ["tokio-tungstenite/rustls-tls-native-roots"] +default = ["tokio-tungstenite-wasm/native-tls"] +rustls = ["tokio-tungstenite-wasm/rustls-tls-native-roots"] + [dependencies] relay_rpc = { path = "../relay_rpc" } @@ -25,10 +26,14 @@ reqwest = { version = "0.12.2", features = ["json"] } # WebSocket client dependencies. tokio = { version = "1.22", features = ["rt", "time", "sync", "macros", "rt-multi-thread"] } -tokio-tungstenite = "0.21.0" +tokio-tungstenite-wasm = { version = "0.3"} futures-channel = "0.3" tokio-stream = "0.1" tokio-util = "0.7" +[lints.rust] +unused_imports = "allow" +dead_code = "allow" + [lints.clippy] indexing_slicing = "deny" diff --git a/relay_client/src/lib.rs b/relay_client/src/lib.rs index 7408975..a4d2b23 100644 --- a/relay_client/src/lib.rs +++ b/relay_client/src/lib.rs @@ -107,17 +107,10 @@ impl ConnectionOptions { fn as_ws_request(&self) -> Result, RequestBuildError> { use { crate::websocket::WebsocketClientError, - tokio_tungstenite::tungstenite::client::IntoClientRequest, }; - let url = self.as_url()?; - - let mut request = url - .into_client_request() - .map_err(WebsocketClientError::Transport)?; - + let mut request = HttpRequest::builder().uri(format!("{}", url)).body(()).map_err(WebsocketClientError::HttpErr)?; self.update_request_headers(request.headers_mut())?; - Ok(request) } diff --git a/relay_client/src/websocket.rs b/relay_client/src/websocket.rs index 29bb2f5..938063f 100644 --- a/relay_client/src/websocket.rs +++ b/relay_client/src/websocket.rs @@ -33,10 +33,10 @@ pub use { inbound::*, outbound::*, stream::*, - tokio_tungstenite::tungstenite::protocol::CloseFrame, + tokio_tungstenite_wasm::CloseFrame, }; -pub type TransportError = tokio_tungstenite::tungstenite::Error; +pub type TransportError = tokio_tungstenite_wasm::Error; #[derive(Debug, thiserror::Error)] pub enum WebsocketClientError { @@ -52,6 +52,9 @@ pub enum WebsocketClientError { #[error("Websocket transport error: {0}")] Transport(TransportError), + #[error("Url error: {0}")] + HttpErr(http::Error), + #[error("Not connected")] NotConnected, } diff --git a/relay_client/src/websocket/inbound.rs b/relay_client/src/websocket/inbound.rs index 2581c7d..9da920e 100644 --- a/relay_client/src/websocket/inbound.rs +++ b/relay_client/src/websocket/inbound.rs @@ -5,7 +5,7 @@ use { rpc::{self, ErrorResponse, Payload, Response, ServiceRequest, SuccessfulResponse}, }, tokio::sync::mpsc::UnboundedSender, - tokio_tungstenite::tungstenite::Message, + tokio_tungstenite_wasm::Message, }; /// The lower-level inbound RPC request. diff --git a/relay_client/src/websocket/stream.rs b/relay_client/src/websocket/stream.rs index 28a5e1e..b983fa9 100644 --- a/relay_client/src/websocket/stream.rs +++ b/relay_client/src/websocket/stream.rs @@ -18,27 +18,27 @@ use { task::{Context, Poll}, }, tokio::{ - net::TcpStream, sync::{ mpsc, mpsc::{UnboundedReceiver, UnboundedSender}, oneshot, }, }, - tokio_tungstenite::{ - connect_async, - tungstenite::{protocol::CloseFrame, Message}, - MaybeTlsStream, + tokio_tungstenite_wasm::{ + CloseFrame, + connect as connect_async, + Message, WebSocketStream, }, }; -pub type SocketStream = WebSocketStream>; +pub type SocketStream = WebSocketStream; /// Opens a connection to the Relay and returns [`ClientStream`] for the /// connection. pub async fn create_stream(request: HttpRequest<()>) -> Result { - let (socket, _) = connect_async(request) + let uri = request.uri(); + let socket = connect_async(format!("{}://{}", uri.scheme().unwrap(), uri.host().unwrap())) .await .map_err(WebsocketClientError::ConnectionFailed)?; @@ -143,7 +143,7 @@ impl ClientStream { pub async fn close(&mut self, frame: Option>) -> Result<(), ClientError> { self.close_frame = frame.clone(); self.socket - .close(frame) + .close() .await .map_err(|err| WebsocketClientError::ClosingFailed(err).into()) } @@ -223,8 +223,6 @@ impl ClientStream { self.close_frame = frame.clone(); Some(StreamEvent::ConnectionClosed(frame.clone())) } - - _ => None, }, Err(error) => Some(StreamEvent::InboundError( @@ -269,7 +267,7 @@ impl Stream for ClientStream { type Item = StreamEvent; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.socket.is_terminated() { + if self.is_terminated() { return Poll::Ready(None); } @@ -301,7 +299,7 @@ impl Stream for ClientStream { impl FusedStream for ClientStream { fn is_terminated(&self) -> bool { - self.socket.is_terminated() + false } } From f9677a1964efdcf61962a74a2fa070e45ba32043 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Sat, 23 Nov 2024 12:48:50 +0200 Subject: [PATCH 02/14] fix url --- relay_client/src/websocket.rs | 2 +- relay_client/src/websocket/connection.rs | 5 +++-- relay_client/src/websocket/stream.rs | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/relay_client/src/websocket.rs b/relay_client/src/websocket.rs index 938063f..86b0774 100644 --- a/relay_client/src/websocket.rs +++ b/relay_client/src/websocket.rs @@ -300,7 +300,7 @@ impl Client { /// Opens a connection to the Relay. pub async fn connect(&self, opts: &ConnectionOptions) -> Result<(), ClientError> { let (tx, rx) = oneshot::channel(); - let request = opts.as_ws_request()?; + let request = opts.as_url()?; if self .control_tx diff --git a/relay_client/src/websocket/connection.rs b/relay_client/src/websocket/connection.rs index e08fb2e..e0c02d7 100644 --- a/relay_client/src/websocket/connection.rs +++ b/relay_client/src/websocket/connection.rs @@ -1,3 +1,4 @@ +use url::Url; use { super::{ outbound::OutboundRequest, @@ -21,7 +22,7 @@ use { pub(super) enum ConnectionControl { Connect { - request: HttpRequest<()>, + request: Url, tx: oneshot::Sender>, }, @@ -107,7 +108,7 @@ impl Connection { Self { stream: None } } - async fn connect(&mut self, request: HttpRequest<()>) -> Result<(), ClientError> { + async fn connect(&mut self, request: Url) -> Result<(), ClientError> { if let Some(mut stream) = self.stream.take() { stream.close(None).await?; } diff --git a/relay_client/src/websocket/stream.rs b/relay_client/src/websocket/stream.rs index b983fa9..4a9df57 100644 --- a/relay_client/src/websocket/stream.rs +++ b/relay_client/src/websocket/stream.rs @@ -1,3 +1,4 @@ +use url::Url; use { super::{ inbound::InboundRequest, @@ -36,9 +37,8 @@ pub type SocketStream = WebSocketStream; /// Opens a connection to the Relay and returns [`ClientStream`] for the /// connection. -pub async fn create_stream(request: HttpRequest<()>) -> Result { - let uri = request.uri(); - let socket = connect_async(format!("{}://{}", uri.scheme().unwrap(), uri.host().unwrap())) +pub async fn create_stream(request: Url) -> Result { + let socket = connect_async(request) .await .map_err(WebsocketClientError::ConnectionFailed)?; From ab53dbc5cd378847978b21ae363bf28dd5e9613a Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Sat, 23 Nov 2024 12:49:21 +0200 Subject: [PATCH 03/14] .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 088ba6b..cbed4d7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +.idea/ From b9fdeb9175ba5eec06281aa171a39f0b7fd15d7d Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 11:20:29 +0200 Subject: [PATCH 04/14] use HttpRequest --- .gitignore | 2 ++ Cargo.toml | 8 ++++-- relay_client/Cargo.toml | 22 ++++++++-------- relay_client/src/lib.rs | 24 +++++++++++++++++- relay_client/src/websocket.rs | 25 ++++++++++-------- relay_client/src/websocket/connection.rs | 5 ++-- relay_client/src/websocket/inbound.rs | 6 +++-- relay_client/src/websocket/stream.rs | 32 ++++++++++++++---------- relay_rpc/Cargo.toml | 2 ++ relay_rpc/src/auth.rs | 9 +++++-- wasm_websocket_client/README.md | 29 +++++++++++++++++++++ 11 files changed, 120 insertions(+), 44 deletions(-) create mode 100644 wasm_websocket_client/README.md diff --git a/.gitignore b/.gitignore index cbed4d7..d8a0ee9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ Cargo.lock **/*.rs.bk .idea/ + +pkg/ diff --git a/Cargo.toml b/Cargo.toml index 7857ebc..694a35f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,17 +8,21 @@ license = "Apache-2.0" [workspace] members = ["blockchain_api", "relay_client", "relay_rpc"] +exclude = ["wasm_websocket_client"] [features] default = ["full"] full = ["client", "rpc"] -client = ["dep:relay_client"] -rpc = ["dep:relay_rpc"] +wasm = ["relay_client/wasm", "client", "rpc"] +wasm-debug = ["relay_client/wasm", "relay_client/wasm-debug", "client", "rpc"] +client = ["relay_client"] +rpc = ["relay_rpc"] [dependencies] relay_client = { path = "./relay_client", optional = true } relay_rpc = { path = "./relay_rpc", optional = true } + [dev-dependencies] anyhow = "1" structopt = { version = "0.3", default-features = false } diff --git a/relay_client/Cargo.toml b/relay_client/Cargo.toml index 3e0532d..57566c9 100644 --- a/relay_client/Cargo.toml +++ b/relay_client/Cargo.toml @@ -5,9 +5,10 @@ edition = "2021" license = "Apache-2.0" [features] -default = ["tokio-tungstenite-wasm/native-tls"] -rustls = ["tokio-tungstenite-wasm/rustls-tls-native-roots"] - +default = ["tokio-tungstenite/native-tls", "tokio-tungstenite/url"] +rustls = ["tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/url"] +wasm = ["wasm-bindgen-futures", "tokio-tungstenite-wasm"] +wasm-debug = ["web-sys"] [dependencies] relay_rpc = { path = "../relay_rpc" } @@ -17,7 +18,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_qs = "0.10" pin-project = "1.0" -chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } +chrono = { version = "0.4", default-features = false, features = ["alloc", "std", "wasmbind", "wasm-bindgen"] } url = "2.3" http = "1.0.0" @@ -25,15 +26,14 @@ http = "1.0.0" reqwest = { version = "0.12.2", features = ["json"] } # WebSocket client dependencies. -tokio = { version = "1.22", features = ["rt", "time", "sync", "macros", "rt-multi-thread"] } -tokio-tungstenite-wasm = { version = "0.3"} +tokio = { version = "1", features = ["rt", "time", "sync", "macros"] } +tokio-tungstenite = { version = "0.24", optional = true} +tokio-tungstenite-wasm = { version = "0.3", optional = true} futures-channel = "0.3" -tokio-stream = "0.1" -tokio-util = "0.7" -[lints.rust] -unused_imports = "allow" -dead_code = "allow" +# WASM dependencies. +wasm-bindgen-futures = { version = "0.4" , optional = true } +web-sys = { version = "0.3" , optional = true, features = ["ConsoleEvent"] } [lints.clippy] indexing_slicing = "deny" diff --git a/relay_client/src/lib.rs b/relay_client/src/lib.rs index a4d2b23..ce0937d 100644 --- a/relay_client/src/lib.rs +++ b/relay_client/src/lib.rs @@ -104,12 +104,34 @@ impl ConnectionOptions { Ok(url) } + #[cfg(not(target_arch = "wasm32"))] fn as_ws_request(&self) -> Result, RequestBuildError> { use { crate::websocket::WebsocketClientError, + tokio_tungstenite::tungstenite::client::IntoClientRequest, }; + + let url = self.as_url()?; + + let mut request = url + .into_client_request() + .map_err(WebsocketClientError::Transport)?; + + self.update_request_headers(request.headers_mut())?; + + Ok(request) + } + + #[cfg(target_arch = "wasm32")] + fn as_ws_request(&self) -> Result, RequestBuildError> { + use crate::websocket::WebsocketClientError; + let url = self.as_url()?; - let mut request = HttpRequest::builder().uri(format!("{}", url)).body(()).map_err(WebsocketClientError::HttpErr)?; + let mut request = HttpRequest::builder() + .uri(format!("{}", url)) + .body(()) + .map_err(WebsocketClientError::HttpErr)?; + self.update_request_headers(request.headers_mut())?; Ok(request) } diff --git a/relay_client/src/websocket.rs b/relay_client/src/websocket.rs index 86b0774..0688d48 100644 --- a/relay_client/src/websocket.rs +++ b/relay_client/src/websocket.rs @@ -28,15 +28,15 @@ use { oneshot, }, }; -pub use { - fetch::*, - inbound::*, - outbound::*, - stream::*, - tokio_tungstenite_wasm::CloseFrame, -}; - +pub use {fetch::*, inbound::*, outbound::*, stream::*}; +#[cfg(not(target_arch = "wasm32"))] +pub type TransportError = tokio_tungstenite::tungstenite::Error; +#[cfg(not(target_arch = "wasm32"))] +pub use tokio_tungstenite::tungstenite::protocol::CloseFrame; +#[cfg(target_arch = "wasm32")] pub type TransportError = tokio_tungstenite_wasm::Error; +#[cfg(target_arch = "wasm32")] +pub use tokio_tungstenite_wasm::CloseFrame; #[derive(Debug, thiserror::Error)] pub enum WebsocketClientError { @@ -149,7 +149,12 @@ impl Client { { let (control_tx, control_rx) = mpsc::unbounded_channel(); - tokio::spawn(connection_event_loop(control_rx, handler)); + let fut = connection_event_loop(control_rx, handler); + #[cfg(target_arch = "wasm32")] + wasm_bindgen_futures::spawn_local(fut); + + #[cfg(not(target_arch = "wasm32"))] + tokio::spawn(fut); Self { control_tx } } @@ -300,7 +305,7 @@ impl Client { /// Opens a connection to the Relay. pub async fn connect(&self, opts: &ConnectionOptions) -> Result<(), ClientError> { let (tx, rx) = oneshot::channel(); - let request = opts.as_url()?; + let request = opts.as_ws_request()?; if self .control_tx diff --git a/relay_client/src/websocket/connection.rs b/relay_client/src/websocket/connection.rs index e0c02d7..e08fb2e 100644 --- a/relay_client/src/websocket/connection.rs +++ b/relay_client/src/websocket/connection.rs @@ -1,4 +1,3 @@ -use url::Url; use { super::{ outbound::OutboundRequest, @@ -22,7 +21,7 @@ use { pub(super) enum ConnectionControl { Connect { - request: Url, + request: HttpRequest<()>, tx: oneshot::Sender>, }, @@ -108,7 +107,7 @@ impl Connection { Self { stream: None } } - async fn connect(&mut self, request: Url) -> Result<(), ClientError> { + async fn connect(&mut self, request: HttpRequest<()>) -> Result<(), ClientError> { if let Some(mut stream) = self.stream.take() { stream.close(None).await?; } diff --git a/relay_client/src/websocket/inbound.rs b/relay_client/src/websocket/inbound.rs index 9da920e..c005046 100644 --- a/relay_client/src/websocket/inbound.rs +++ b/relay_client/src/websocket/inbound.rs @@ -1,3 +1,7 @@ +#[cfg(not(target_arch = "wasm32"))] +use tokio_tungstenite::tungstenite::Message; +#[cfg(target_arch = "wasm32")] +use tokio_tungstenite_wasm::Message; use { crate::ClientError, relay_rpc::{ @@ -5,9 +9,7 @@ use { rpc::{self, ErrorResponse, Payload, Response, ServiceRequest, SuccessfulResponse}, }, tokio::sync::mpsc::UnboundedSender, - tokio_tungstenite_wasm::Message, }; - /// The lower-level inbound RPC request. /// /// Provides access to the request payload (via [`InboundRequest::data()`]) and diff --git a/relay_client/src/websocket/stream.rs b/relay_client/src/websocket/stream.rs index 4a9df57..9da8ad1 100644 --- a/relay_client/src/websocket/stream.rs +++ b/relay_client/src/websocket/stream.rs @@ -1,4 +1,12 @@ -use url::Url; +#[cfg(not(target_arch = "wasm32"))] +use tokio_tungstenite::{ + connect_async, + tungstenite::{protocol::CloseFrame, Message}, + MaybeTlsStream, + WebSocketStream, +}; +#[cfg(target_arch = "wasm32")] +use tokio_tungstenite_wasm::{connect as connect_async, Message, WebSocketStream}; use { super::{ inbound::InboundRequest, @@ -19,26 +27,23 @@ use { task::{Context, Poll}, }, tokio::{ + net::TcpStream, sync::{ mpsc, mpsc::{UnboundedReceiver, UnboundedSender}, oneshot, }, }, - tokio_tungstenite_wasm::{ - CloseFrame, - connect as connect_async, - Message, - WebSocketStream, - }, }; - +#[cfg(not(target_arch = "wasm32"))] +pub type SocketStream = WebSocketStream>; +#[cfg(target_arch = "wasm32")] pub type SocketStream = WebSocketStream; /// Opens a connection to the Relay and returns [`ClientStream`] for the /// connection. -pub async fn create_stream(request: Url) -> Result { - let socket = connect_async(request) +pub async fn create_stream(request: HttpRequest<()>) -> Result { + let (socket, _) = connect_async(request) .await .map_err(WebsocketClientError::ConnectionFailed)?; @@ -143,7 +148,7 @@ impl ClientStream { pub async fn close(&mut self, frame: Option>) -> Result<(), ClientError> { self.close_frame = frame.clone(); self.socket - .close() + .close(frame) .await .map_err(|err| WebsocketClientError::ClosingFailed(err).into()) } @@ -182,7 +187,6 @@ impl ClientStream { Payload::Response(response) => { let id = response.id(); - if id.is_zero() { return match response { Response::Error(response) => Some(StreamEvent::InboundError( @@ -223,6 +227,8 @@ impl ClientStream { self.close_frame = frame.clone(); Some(StreamEvent::ConnectionClosed(frame.clone())) } + + _ => None, }, Err(error) => Some(StreamEvent::InboundError( @@ -299,7 +305,7 @@ impl Stream for ClientStream { impl FusedStream for ClientStream { fn is_terminated(&self) -> bool { - false + self.socket.is_terminated() } } diff --git a/relay_rpc/Cargo.toml b/relay_rpc/Cargo.toml index c3206d1..a31737c 100644 --- a/relay_rpc/Cargo.toml +++ b/relay_rpc/Cargo.toml @@ -29,6 +29,8 @@ rand = "0.8" chrono = { version = "0.4", default-features = false, features = [ "std", "clock", + "wasmbind", + "wasm-bindgen", ] } regex = "1.7" once_cell = "1.16" diff --git a/relay_rpc/src/auth.rs b/relay_rpc/src/auth.rs index a1128a5..4e790bc 100644 --- a/relay_rpc/src/auth.rs +++ b/relay_rpc/src/auth.rs @@ -10,6 +10,8 @@ use { std::{fmt::Display, time::Duration}, }; +// use web_sys::console; + #[cfg(feature = "cacao")] pub mod cacao; pub mod did; @@ -33,7 +35,7 @@ pub const DEFAULT_TOKEN_AUD: &str = RELAY_WEBSOCKET_ADDRESS; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(transparent)] -pub struct SerializedAuthToken(String); +pub struct SerializedAuthToken(pub String); impl Display for SerializedAuthToken { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -81,9 +83,11 @@ impl AuthToken { } pub fn as_jwt(&self, key: &SigningKey) -> Result { + // console::log_1(&"begin jwt".into()); let iat = self.iat.unwrap_or_else(Utc::now); + // console::log_1(&"iat".into()); let aud = self.aud.as_deref().unwrap_or(DEFAULT_TOKEN_AUD); - + // console::log_1(&"aud".into()); encode_auth_token(key, &self.sub, aud, iat, self.ttl) } } @@ -103,6 +107,7 @@ pub fn encode_auth_token( .map_err(|_| Error::InvalidDuration)? .map(|ttl| (iat + ttl).timestamp()); + // console::log_1(&"exp done".into()); let claims = { let data = JwtBasicClaims { iss: DecodedClientId::from_key(&key.verifying_key()).into(), diff --git a/wasm_websocket_client/README.md b/wasm_websocket_client/README.md new file mode 100644 index 0000000..d4fd5cc --- /dev/null +++ b/wasm_websocket_client/README.md @@ -0,0 +1,29 @@ +# Wasm Websocket Client Example + +## Quickstart + +1. Set the PROJECT_ID env: + +```shell +export PROJECT_ID="my-project-id" +``` + +2. Install wasm-pack + +```shell +cargo install wasm-pack +``` + +3. Install basic-http-server + +```shell +cargo install basic-http-server +``` + +4. Build + +```shell + wasm-pack build --target web --dev +``` + +Visit [http://localhost:4000](http://localhost:4000) From 979b5bb6cabe1fac1d4b116c1ccf8b6eee0ac49f Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 12:13:17 +0200 Subject: [PATCH 05/14] adding example --- Cargo.toml | 8 +- relay_client/Cargo.toml | 3 +- relay_client/src/websocket/stream.rs | 45 ++++++-- wasm_websocket_client/Cargo.toml | 35 +++++++ wasm_websocket_client/favicon.ico | Bin 0 -> 15406 bytes wasm_websocket_client/index.html | 43 ++++++++ wasm_websocket_client/src/lib.rs | 148 +++++++++++++++++++++++++++ wasm_websocket_client/src/utils.rs | 70 +++++++++++++ wasm_websocket_client/styles.css | 71 +++++++++++++ 9 files changed, 410 insertions(+), 13 deletions(-) create mode 100644 wasm_websocket_client/Cargo.toml create mode 100644 wasm_websocket_client/favicon.ico create mode 100644 wasm_websocket_client/index.html create mode 100644 wasm_websocket_client/src/lib.rs create mode 100644 wasm_websocket_client/src/utils.rs create mode 100644 wasm_websocket_client/styles.css diff --git a/Cargo.toml b/Cargo.toml index 694a35f..74faa4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,15 +13,19 @@ exclude = ["wasm_websocket_client"] [features] default = ["full"] full = ["client", "rpc"] -wasm = ["relay_client/wasm", "client", "rpc"] +wasm = ["relay_client/wasm", "rpc"] wasm-debug = ["relay_client/wasm", "relay_client/wasm-debug", "client", "rpc"] client = ["relay_client"] rpc = ["relay_rpc"] [dependencies] -relay_client = { path = "./relay_client", optional = true } relay_rpc = { path = "./relay_rpc", optional = true } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +relay_client = { path = "./relay_client", optional = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +relay_client = { path = "./relay_client", default-features = false , features = ["wasm"], optional = true } [dev-dependencies] anyhow = "1" diff --git a/relay_client/Cargo.toml b/relay_client/Cargo.toml index 57566c9..49d92fb 100644 --- a/relay_client/Cargo.toml +++ b/relay_client/Cargo.toml @@ -7,7 +7,7 @@ license = "Apache-2.0" [features] default = ["tokio-tungstenite/native-tls", "tokio-tungstenite/url"] rustls = ["tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/url"] -wasm = ["wasm-bindgen-futures", "tokio-tungstenite-wasm"] +wasm = ["wasm-bindgen-futures", "tokio-tungstenite-wasm", "getrandom"] wasm-debug = ["web-sys"] [dependencies] @@ -34,6 +34,7 @@ futures-channel = "0.3" # WASM dependencies. wasm-bindgen-futures = { version = "0.4" , optional = true } web-sys = { version = "0.3" , optional = true, features = ["ConsoleEvent"] } +getrandom = { version = "0.2" , optional = true, features = ["wasm-bindgen", "js"]} [lints.clippy] indexing_slicing = "deny" diff --git a/relay_client/src/websocket/stream.rs b/relay_client/src/websocket/stream.rs index 9da8ad1..266814c 100644 --- a/relay_client/src/websocket/stream.rs +++ b/relay_client/src/websocket/stream.rs @@ -6,7 +6,7 @@ use tokio_tungstenite::{ WebSocketStream, }; #[cfg(target_arch = "wasm32")] -use tokio_tungstenite_wasm::{connect as connect_async, Message, WebSocketStream}; +use tokio_tungstenite_wasm::{connect as connect_async, CloseFrame, Message, WebSocketStream}; use { super::{ inbound::InboundRequest, @@ -26,22 +26,22 @@ use { pin::Pin, task::{Context, Poll}, }, - tokio::{ - net::TcpStream, - sync::{ - mpsc, - mpsc::{UnboundedReceiver, UnboundedSender}, - oneshot, - }, + tokio::sync::{ + mpsc, + mpsc::{UnboundedReceiver, UnboundedSender}, + oneshot, }, }; #[cfg(not(target_arch = "wasm32"))] pub type SocketStream = WebSocketStream>; +#[cfg(not(target_arch = "wasm32"))] +use tokio::net::TcpStream; #[cfg(target_arch = "wasm32")] pub type SocketStream = WebSocketStream; /// Opens a connection to the Relay and returns [`ClientStream`] for the /// connection. +#[cfg(not(target_arch = "wasm32"))] pub async fn create_stream(request: HttpRequest<()>) -> Result { let (socket, _) = connect_async(request) .await @@ -50,6 +50,16 @@ pub async fn create_stream(request: HttpRequest<()>) -> Result) -> Result { + let url = format!("{}", request.uri()); + let socket = connect_async(url) + .await + .map_err(WebsocketClientError::ConnectionFailed)?; + + Ok(ClientStream::new(socket)) +} + /// Possible events produced by the [`ClientStream`]. /// /// The events are produced by polling [`ClientStream`] in a loop. @@ -147,9 +157,16 @@ impl ClientStream { /// Closes the connection. pub async fn close(&mut self, frame: Option>) -> Result<(), ClientError> { self.close_frame = frame.clone(); + #[cfg(not(target_arch = "wasm32"))] self.socket .close(frame) .await + .map_err(|err| WebsocketClientError::ClosingFailed(err).into()); + + #[cfg(target_arch = "wasm32")] + self.socket + .close() + .await .map_err(|err| WebsocketClientError::ClosingFailed(err).into()) } @@ -187,6 +204,7 @@ impl ClientStream { Payload::Response(response) => { let id = response.id(); + if id.is_zero() { return match response { Response::Error(response) => Some(StreamEvent::InboundError( @@ -227,7 +245,7 @@ impl ClientStream { self.close_frame = frame.clone(); Some(StreamEvent::ConnectionClosed(frame.clone())) } - + #[cfg(not(target_arch = "wasm32"))] _ => None, }, @@ -273,7 +291,8 @@ impl Stream for ClientStream { type Item = StreamEvent; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.is_terminated() { + #[cfg(not(target_arch = "wasm32"))] + if self.socket.is_terminated() { return Poll::Ready(None); } @@ -304,9 +323,15 @@ impl Stream for ClientStream { } impl FusedStream for ClientStream { + #[cfg(not(target_arch = "wasm32"))] fn is_terminated(&self) -> bool { self.socket.is_terminated() } + + #[cfg(target_arch = "wasm32")] + fn is_terminated(&self) -> bool { + false + } } impl Drop for ClientStream { diff --git a/wasm_websocket_client/Cargo.toml b/wasm_websocket_client/Cargo.toml new file mode 100644 index 0000000..2e31baf --- /dev/null +++ b/wasm_websocket_client/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "wasm_websocket_client" +version = "0.1.0" +edition = "2021" +authors = ["WalletConnect Team"] +license = "Apache-2.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1" +data-encoding = "2" +futures = "0.3" +rand = "0.8.5" +getrandom = { version = "0.2", features = ["js"] } +wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } +wasm-bindgen-futures = "0.4" +web-sys = { version = "0.3", features = [ + "Element", "HtmlElement", "Window", + "WebSocket", "console", "Event", + "Document", "Crypto", "CryptoKey", + "DateTimeValue", "SubtleCrypto", "Performance", + "TimeEvent" +] } +walletconnect_sdk = { path = "../", default-features = false, features = ["wasm", "wasm-debug"] } +console_error_panic_hook = { version = "0.1" } +web-time = { version = "1", features = ["serde"] } +gloo-timers = { version = "0.3", features = ["futures"] } + +[package.metadata.wasm-pack.profile.dev] +wasm-bindgen = { debug-js-glue = true, demangle-name-section = true } +wasm-opt = false + + diff --git a/wasm_websocket_client/favicon.ico b/wasm_websocket_client/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cd842843ecbdb39d7f8051530b1335c9bed1510e GIT binary patch literal 15406 zcmeHOYp_;T8UC#PXFvLD=TI3XCEe&cMN^iQlUdQo)RfcsBhxPClwBQ18>gnGW-^^p zz(6i?N5CSJJAxvh6ayR}1%v~_;k(~&tLI&}{jRmw-rxQXOn>s5*=Mc2_Ir8W%i4S0 zPA+#@?zOqgFVCSI$$k5Ex!jCgE;llw?x(&Xmz#&S>C^S|D|5M>Z_MSUf(9($Q0*v! zzlk|l+*O!6(#p>n5pTzh~;W46yF?orX$ z{cF(&e`{u@v69xuQV>rL+$juwB~xzI=n=PUI!NRMQ!I@qPp=GQQdO8$j^J5;v*h&Nj~L6 zC3}jfKK)D4EglEI6e0S3@`ezVf8H#0$oydZCce_Y8c%iOZIY*Z;eaSSI$h-FPlLaw zIJss0rg;c|ZP(qRxa32k@Ykz^Xjh@Tr}(A4+SgjQvYBBAe`DVtMX!+;jr|Xb&cp$U zp|Sr@qPqEZQQPuEQQi6j$h%s{O!-mDG4=ps{n`6OuY3~j>&q}m>y-6y?*>l0H~v?@kugI-l1 zjrt(tQ+-R(QJ+#+>0V!|ze(QUOJRscde4mDnu&|vPf0&VimF_sf}#J zrSpXAN~lLZH-6;2vd(fDG-0d(JY0_K50jAN>5uCU$doy3@VL)IK8@n1X&u~3PG#e* zqVfFwqPp$Jcu%}L>MzD;PMIvni2?LTdjk4=oW1%v`HrC%Pp^6g-@q#eU?AMS?MXf{ z?I=AggpaPi{B9@+^tbrfN5XmF@k@JIn~fi9bA00XF~ZgFHLd+rDXsiW2Kyuan2sU! z_iAUAe*L$y;U?Gq1bN1PG5yj`FFsO6pbh!lIs2TWpT37-nJG5Md<$I~w~b3e&NL4# za`ZRHmSxcI*%H$atOtb!3%jAKxI_r?!dq=^diD^rO0OC|}2Q1Y!WJaXR?$k*T72aG@TzI_4+d z)c5{jKyGUNT;~8^6&B49wP$`6*U9{$9`@mf?Fo4iushTzf^CYoTR7@qsK4-_C@%km zC@uXM#>XEP1&kpJ^WPEK&+RgGS-Mz)zPC6c+Q#z_sBD1UWP1DLrbw5jCt2z8RKNFW zV)qNK7WAIwIa^xwIX4|U4djTPzgWDc?}f{O__Uv@+kPa+`n6s6IvBe7!%hs!Pt10n z$Lz?6i`z-{%7$-RTU*DU#2oGmQcrc)J&ykRp5JQyh?5iJ3~|8wKEg|Jj$)n1oTr1i zDo^oV{k-U$|Cgh`R~;9fm$!(vxsd<#9%!F_8f}|J|p%>Xs-* z28W52xgS_6-xSf;EC2YGsBQl#-bwd~I@UF6n44C2-XrJrwH-ghIQ34whR6FE~) z>KobH(_@%jj+X-p+fIoUm<@L1%mev{N1BtCYxB?3H>jQWok6txxx@<0#_vhk2g*

&I`DgE;%#{^60?yvnbKe=E}tpq z&=4;L?P1}Zlp6LpL8X)a~#?0$}S_bzUOzq zt0y#UUei3X9D8wZcgLqm@%P)gZ+YFPOTABu5s%BLpt&*a*ZIHJi|esYGEL#<7x@?Z-=>TtW=#cwFC-?m_glUgqyz zNMpKPb(VtrGOf;SGyh$`xj>Va!zbKit-Rj(oV+8tguW}l`!Pv<2 z&*XFgkCo&3VJOUTyXfqT{IU0sy6=n9icfhl2>Cf35BE8*b3Y`ta~fO6ShKk3eWI}F z{mB36_)fjk?)~^Cn0>%>`RVwr-i!3Jkwa^x?NeLjo@E>Bzm(^_n%=*5k_h_;^c{np z^ev!$BZ>#{m)Bz7>xmmt-k@^KVuLLi{gV4Ld)>Dk>z(tj zlKNXmS84ny-~*3n&!xP6md5YPH~z{J7ehNl$?`BX7bAoEjSGm=9q6yK(O+k&Gi__G z!x@chMG^g(&WgzI1dn&Do@7@N)+Bnb9r#VYl~#RLo}DpCq+E@^J&c9Cea1oYHZlj% z4fA}UOzdHG&OB@2J7x3G;y`{U`Oa&=}S1 z(OC>O_jpWs9d=k6*Cq#BkVeT-x+0l{h3}Dj+O3y1sCR~EZvkhJ<$M5X<9F54qB8@m$DI(17g*%;UgoqNXFb2^7a*YC?*4T2qf0xL2MB~6boZ}J?Nowc3wr=ro`5v|)4X3}f^(^?~G#oRpUs`O|Z#I|Xy5iU}Uhe6>?q38Y&^2XyLWwP@d<_wBD3o**h g6J*rOG1&U#czIlcKKIVgTt?tu{k`gei}1jI0Rp?;I{*Lx literal 0 HcmV?d00001 diff --git a/wasm_websocket_client/index.html b/wasm_websocket_client/index.html new file mode 100644 index 0000000..f3221a8 --- /dev/null +++ b/wasm_websocket_client/index.html @@ -0,0 +1,43 @@ + + + + + WASM WebSocket Client Example + + + +

WASM WebSocket Client Example

+ +
+
client
+
state
+
topic
+
message
+
error
+ +
wc1
+
disconnected
+
+
+
+ +
wc2
+
disconnected
+
+
+
+
+
+
+ + diff --git a/wasm_websocket_client/src/lib.rs b/wasm_websocket_client/src/lib.rs new file mode 100644 index 0000000..aac419d --- /dev/null +++ b/wasm_websocket_client/src/lib.rs @@ -0,0 +1,148 @@ +mod utils; + +use std::fmt::Display; +use std::fmt::Formatter; +use walletconnect_sdk::client::{ + error::ClientError, + websocket::{Client, CloseFrame, ConnectionHandler, PublishedMessage}, + ConnectionOptions, +}; +use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::spawn_local; +use web_sys::console; + +use rand::rngs::OsRng; +use std::time::Duration; +use walletconnect_sdk::rpc::{ + auth::{ed25519_dalek::SigningKey, AuthToken}, + domain::Topic, +}; + +enum ClientId { + WC1, + WC2, +} + +impl ClientId { + fn div(&self, d: &str) -> String { + format!("{}{d}", self) + } +} +impl Display for ClientId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + match self { + ClientId::WC1 => write!(f, "wc1"), + ClientId::WC2 => write!(f, "wc2") + } + } +} + +struct Handler { + client_id: ClientId, +} + +impl Handler { + fn new(name: ClientId) -> Self { + Self { client_id: name } + } + fn error_div(&self) -> String { + self.client_id.div("error") + } + + fn connect_div(&self) -> String { + self.client_id.div("connect") + } + + fn message_div(&self) -> String { + self.client_id.div("message") + } +} + +impl ConnectionHandler for Handler { + fn connected(&mut self) { + let _ = utils::set_result_text(&self.connect_div(), "connected"); + } + + fn disconnected(&mut self, _frame: Option>) { + let _ = utils::set_result_text(&self.connect_div(), "disconnected"); + } + + fn message_received(&mut self, message: PublishedMessage) { + let div = self.message_div(); + let from = match self.client_id { + ClientId::WC1 => "wc2", + ClientId::WC2 => "wc1", + }; + let msg = format!("message from {from}: '{}'", message.message.as_ref()); + let _ = utils::set_result_text(&div, &msg); + } + + fn inbound_error(&mut self, error: ClientError) { + let e = format!("inbound error: {error}"); + let _ = utils::set_result_text(&self.error_div(), &e); + } + + fn outbound_error(&mut self, error: ClientError) { + let e = format!("outbound error: {error}"); + let _ = utils::set_result_text(&self.error_div(), &e); + } +} + +fn create_opts_result(address: &str, project_id: &str) -> anyhow::Result { + let mut csprng = OsRng; + let key = SigningKey::generate(&mut csprng); + console::log_1(&"loaded key".into()); + let auth = AuthToken::new("http://example.com") + .aud(address) + .ttl(Duration::from_secs(60 * 60)); + console::log_1(&"AuthToken Init".into()); + let auth = auth.as_jwt(&key)?; + console::log_1(&"AuthToken JWT".into()); + Ok(ConnectionOptions::new(project_id, auth).with_address(address)) +} + +fn create_conn_opts(address: &str, project_id: &str) -> Option { + match create_opts_result(address, project_id) { + Ok(o) => Some(o), + Err(e) => { + let error_msg = format!("Failed to create connection options: {:?}", e); + let _ = utils::set_result_text(&ClientId::WC1.div("error"), &error_msg); + let _ = utils::set_result_text(&ClientId::WC2.div("error"), &error_msg); + None + } + } +} + +#[wasm_bindgen(start)] +pub fn run() { + console_error_panic_hook::set_once(); + let project_id = env!("PROJECT_ID"); + spawn_local(async { + let client1 = Client::new(Handler::new(ClientId::WC1)); + let client2 = Client::new(Handler::new(ClientId::WC2)); + let opts = create_conn_opts("wss://relay.walletconnect.org", project_id); + if opts.is_none() { + return; + } + utils::connect("wc1", &client1, &opts.unwrap()).await; + let opts = create_conn_opts("wss://relay.walletconnect.org", project_id); + if opts.is_none() { + return; + } + utils::connect("wc2", &client2, &opts.unwrap()).await; + + let topic = Topic::generate(); + let sub = utils::subscribe_topic(ClientId::WC1, &client1, topic.clone()).await; + if !sub { + return; + } + let sub = utils::subscribe_topic(ClientId::WC2, &client2, topic.clone()).await; + if !sub { + return; + } + spawn_local(utils::publish(ClientId::WC1, client1, topic.clone())); + spawn_local(utils::publish(ClientId::WC2, client2, topic.clone())); + console::log_1(&"done".into()); + }); +} + diff --git a/wasm_websocket_client/src/utils.rs b/wasm_websocket_client/src/utils.rs new file mode 100644 index 0000000..d029638 --- /dev/null +++ b/wasm_websocket_client/src/utils.rs @@ -0,0 +1,70 @@ +use crate::ClientId; +use gloo_timers::future::TimeoutFuture; +use std::sync::Arc; +use std::time::Duration; +use walletconnect_sdk::client::websocket::Client; +use walletconnect_sdk::client::ConnectionOptions; +use walletconnect_sdk::rpc::domain::Topic; +use wasm_bindgen::JsValue; +use web_sys::console; + +// Helper function to set text in the result div +pub fn set_result_text(div: &str, text: &str) -> Result<(), JsValue> { + let window = web_sys::window().expect("no global `window` exists"); + let document = window.document().expect("should have a document on window"); + let result_div = document.get_element_by_id(div).expect("should have result element"); + + result_div.set_inner_html(""); + + let text_element = document.create_element("p")?; + text_element.set_inner_html(text); + result_div.append_child(&text_element)?; + Ok(()) +} + +pub async fn subscribe_topic(id: ClientId, client: &Client, topic: Topic) -> bool { + let msg = format!("{topic}"); + match client.subscribe(topic).await { + Ok(_) => { + let div = format!("{}topic", id); + let _ = set_result_text(&div, &msg); + true + } + Err(e) => { + let div = id.div("error"); + let _ = set_result_text(&div, &format!("failed to subscribe {e}")); + false + } + } +} + +pub async fn connect(id: &str, client: &Client, opts: &ConnectionOptions) { + match client.connect(opts).await { + Ok(_) => { + console::log_1(&"WebSocket connection successful".into()); + } + Err(e) => { + let error_msg = format!("WebSocket connection failed: {:?}", e); + let div = format!("{}error", id); + let _ = set_result_text(&div, error_msg.as_str()); + } + } +} + +pub async fn publish(id: ClientId, client: Client, topic: Topic) { + for i in 1..9 { + let msg = format!("{i}"); + if let Err(e) = client.publish(topic.clone(), + Arc::from(msg.as_str()), + None, + 0, + Duration::from_secs(60), + false, + ).await { + let error_msg = format!("Failed message send {e}"); + let _ = set_result_text(&id.div("error"), &error_msg); + return; + } + TimeoutFuture::new(2000).await; + } +} diff --git a/wasm_websocket_client/styles.css b/wasm_websocket_client/styles.css new file mode 100644 index 0000000..00a0f85 --- /dev/null +++ b/wasm_websocket_client/styles.css @@ -0,0 +1,71 @@ +/* Base styles */ +.grid-container { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 1rem; + padding: 1rem; + max-width: 1200px; + margin: 0 auto; +} + +.grid-item { + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 4px; + padding: 1rem; + min-height: 2.5rem; + display: flex; + align-items: center; +} + +/* Header row */ +.grid-item:nth-child(-n+5) { + background-color: #e9ecef; + font-weight: bold; + text-transform: capitalize; +} + +/* Topic cell truncation */ +#wc1topic, #wc2topic { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 8ch; +} + +/* Status indicators */ +#wc1connect, #wc2connect { + &:contains("connected") { + color: #198754; + background-color: #d1e7dd; + } + + &:contains("disconnected") { + color: #842029; + background-color: #f8d7da; + } +} + +/* Error cells */ +#wc1error, #wc2error { + color: #842029; +} + +/* Responsive breakpoints */ +@media (max-width: 768px) { + .grid-container { + grid-template-columns: repeat(3, 1fr); + } + + .grid-item:nth-child(-n+5) { + display: none; + } +} + +@media (max-width: 480px) { + .grid-container { + grid-template-columns: repeat(2, 1fr); + gap: 0.5rem; + padding: 0.5rem; + } +} From 0bfd370953d51da036ebd4654003829f0a59ca49 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 13:08:11 +0200 Subject: [PATCH 06/14] Adding github wasm action --- .github/workflows/ci.yaml | 10 ++++++++++ relay_client/src/websocket/stream.rs | 9 ++++++--- relay_rpc/src/jwt.rs | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0288989..fc9ff53 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -80,3 +80,13 @@ jobs: with: github_token: ${{ secrets.github_token }} locale: "US" + + wasm: + name: "wasm" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + - name: "wasm-pack" + run: wasm-pack build --target web --dev diff --git a/relay_client/src/websocket/stream.rs b/relay_client/src/websocket/stream.rs index 266814c..a706810 100644 --- a/relay_client/src/websocket/stream.rs +++ b/relay_client/src/websocket/stream.rs @@ -155,15 +155,18 @@ impl ClientStream { } /// Closes the connection. + #[cfg(not(target_arch = "wasm32"))] pub async fn close(&mut self, frame: Option>) -> Result<(), ClientError> { self.close_frame = frame.clone(); - #[cfg(not(target_arch = "wasm32"))] self.socket .close(frame) .await - .map_err(|err| WebsocketClientError::ClosingFailed(err).into()); + .map_err(|err| WebsocketClientError::ClosingFailed(err).into()) + } - #[cfg(target_arch = "wasm32")] + #[cfg(target_arch = "wasm32")] + pub async fn close(&mut self, frame: Option>) -> Result<(), ClientError> { + self.close_frame = frame.clone(); self.socket .close() .await diff --git a/relay_rpc/src/jwt.rs b/relay_rpc/src/jwt.rs index 120a99d..d37599f 100644 --- a/relay_rpc/src/jwt.rs +++ b/relay_rpc/src/jwt.rs @@ -67,7 +67,7 @@ impl Default for JwtHeader<'_> { } } -impl<'a> JwtHeader<'a> { +impl JwtHeader<'_> { pub fn is_valid(&self) -> bool { self.typ == JWT_HEADER_TYP && self.alg == JWT_HEADER_ALG } From 401c7be1c47f45dbfec7fa24ef9d1918329549c6 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 13:13:20 +0200 Subject: [PATCH 07/14] adding PROJECT_ID --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fc9ff53..762f690 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -82,6 +82,8 @@ jobs: locale: "US" wasm: + env: + PROJECT_ID: "dummy" name: "wasm" runs-on: ubuntu-latest steps: From 4a02876dc8f27a91d19697320eb925cae82460d0 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 14:40:03 +0200 Subject: [PATCH 08/14] cd wasm_client --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 762f690..b6c1423 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -91,4 +91,4 @@ jobs: - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: "wasm-pack" - run: wasm-pack build --target web --dev + run: cd wasm_websocket_client && wasm-pack build --target web From 7d946df7f9e83ae2eb140546bbac36764164b734 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 15:18:03 +0200 Subject: [PATCH 09/14] raget cfg in Cargo.toml --- relay_client/Cargo.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/relay_client/Cargo.toml b/relay_client/Cargo.toml index 49d92fb..b5a92e9 100644 --- a/relay_client/Cargo.toml +++ b/relay_client/Cargo.toml @@ -27,8 +27,12 @@ reqwest = { version = "0.12.2", features = ["json"] } # WebSocket client dependencies. tokio = { version = "1", features = ["rt", "time", "sync", "macros"] } -tokio-tungstenite = { version = "0.24", optional = true} -tokio-tungstenite-wasm = { version = "0.3", optional = true} +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio-tungstenite = { version = "0.24", optional = true } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +tokio-tungstenite-wasm = { version = "0.3", optional = true } + futures-channel = "0.3" # WASM dependencies. From b1e85fbe9962ddbdba59f639cb47970c177cfd9b Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 15:36:50 +0200 Subject: [PATCH 10/14] remove wasm flag --- Cargo.toml | 13 +++---------- relay_client/Cargo.toml | 8 ++------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 74faa4a..13f221d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,20 +13,13 @@ exclude = ["wasm_websocket_client"] [features] default = ["full"] full = ["client", "rpc"] -wasm = ["relay_client/wasm", "rpc"] -wasm-debug = ["relay_client/wasm", "relay_client/wasm-debug", "client", "rpc"] -client = ["relay_client"] -rpc = ["relay_rpc"] +client = ["dep:relay_client"] +rpc = ["dep:relay_rpc"] [dependencies] +relay_client = { path = "./relay_client", optional = true } relay_rpc = { path = "./relay_rpc", optional = true } -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -relay_client = { path = "./relay_client", optional = true } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -relay_client = { path = "./relay_client", default-features = false , features = ["wasm"], optional = true } - [dev-dependencies] anyhow = "1" structopt = { version = "0.3", default-features = false } diff --git a/relay_client/Cargo.toml b/relay_client/Cargo.toml index b5a92e9..0e2f0bb 100644 --- a/relay_client/Cargo.toml +++ b/relay_client/Cargo.toml @@ -7,8 +7,6 @@ license = "Apache-2.0" [features] default = ["tokio-tungstenite/native-tls", "tokio-tungstenite/url"] rustls = ["tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/url"] -wasm = ["wasm-bindgen-futures", "tokio-tungstenite-wasm", "getrandom"] -wasm-debug = ["web-sys"] [dependencies] relay_rpc = { path = "../relay_rpc" } @@ -27,15 +25,13 @@ reqwest = { version = "0.12.2", features = ["json"] } # WebSocket client dependencies. tokio = { version = "1", features = ["rt", "time", "sync", "macros"] } +futures-channel = "0.3" + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tokio-tungstenite = { version = "0.24", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] tokio-tungstenite-wasm = { version = "0.3", optional = true } - -futures-channel = "0.3" - -# WASM dependencies. wasm-bindgen-futures = { version = "0.4" , optional = true } web-sys = { version = "0.3" , optional = true, features = ["ConsoleEvent"] } getrandom = { version = "0.2" , optional = true, features = ["wasm-bindgen", "js"]} From ee0db239824d31f3970bd6ab15ccb17bedbde27c Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 15:58:49 +0200 Subject: [PATCH 11/14] fix wasm_client build --- relay_client/Cargo.toml | 10 +++++----- wasm_websocket_client/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/relay_client/Cargo.toml b/relay_client/Cargo.toml index 0e2f0bb..6400ac0 100644 --- a/relay_client/Cargo.toml +++ b/relay_client/Cargo.toml @@ -28,13 +28,13 @@ tokio = { version = "1", features = ["rt", "time", "sync", "macros"] } futures-channel = "0.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tokio-tungstenite = { version = "0.24", optional = true } +tokio-tungstenite = { version = "0.24" } [target.'cfg(target_arch = "wasm32")'.dependencies] -tokio-tungstenite-wasm = { version = "0.3", optional = true } -wasm-bindgen-futures = { version = "0.4" , optional = true } -web-sys = { version = "0.3" , optional = true, features = ["ConsoleEvent"] } -getrandom = { version = "0.2" , optional = true, features = ["wasm-bindgen", "js"]} +tokio-tungstenite-wasm = { version = "0.3" } +wasm-bindgen-futures = { version = "0.4" } +web-sys = { version = "0.3" , features = ["ConsoleEvent"] } +getrandom = { version = "0.2" , features = ["wasm-bindgen", "js"]} [lints.clippy] indexing_slicing = "deny" diff --git a/wasm_websocket_client/Cargo.toml b/wasm_websocket_client/Cargo.toml index 2e31baf..4f16278 100644 --- a/wasm_websocket_client/Cargo.toml +++ b/wasm_websocket_client/Cargo.toml @@ -23,7 +23,7 @@ web-sys = { version = "0.3", features = [ "DateTimeValue", "SubtleCrypto", "Performance", "TimeEvent" ] } -walletconnect_sdk = { path = "../", default-features = false, features = ["wasm", "wasm-debug"] } +walletconnect_sdk = { path = "../" } console_error_panic_hook = { version = "0.1" } web-time = { version = "1", features = ["serde"] } gloo-timers = { version = "0.3", features = ["futures"] } From 2ecbe5d04c07c73bceda10098f6a69257dccb4c0 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Fri, 29 Nov 2024 16:58:03 +0200 Subject: [PATCH 12/14] revert auth.rs --- examples/websocket_client.rs | 2 +- relay_rpc/src/auth.rs | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/examples/websocket_client.rs b/examples/websocket_client.rs index 4458157..8003b6f 100644 --- a/examples/websocket_client.rs +++ b/examples/websocket_client.rs @@ -19,7 +19,7 @@ struct Args { address: String, /// Specify WalletConnect project ID. - #[structopt(short, long, default_value = "5c9d8a326d3afb25ed1dff90f6d1807a")] + #[structopt(short, long, default_value = "3cbaa32f8fbf3cdcc87d27ca1fa68069")] project_id: String, } diff --git a/relay_rpc/src/auth.rs b/relay_rpc/src/auth.rs index 4e790bc..a1128a5 100644 --- a/relay_rpc/src/auth.rs +++ b/relay_rpc/src/auth.rs @@ -10,8 +10,6 @@ use { std::{fmt::Display, time::Duration}, }; -// use web_sys::console; - #[cfg(feature = "cacao")] pub mod cacao; pub mod did; @@ -35,7 +33,7 @@ pub const DEFAULT_TOKEN_AUD: &str = RELAY_WEBSOCKET_ADDRESS; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(transparent)] -pub struct SerializedAuthToken(pub String); +pub struct SerializedAuthToken(String); impl Display for SerializedAuthToken { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -83,11 +81,9 @@ impl AuthToken { } pub fn as_jwt(&self, key: &SigningKey) -> Result { - // console::log_1(&"begin jwt".into()); let iat = self.iat.unwrap_or_else(Utc::now); - // console::log_1(&"iat".into()); let aud = self.aud.as_deref().unwrap_or(DEFAULT_TOKEN_AUD); - // console::log_1(&"aud".into()); + encode_auth_token(key, &self.sub, aud, iat, self.ttl) } } @@ -107,7 +103,6 @@ pub fn encode_auth_token( .map_err(|_| Error::InvalidDuration)? .map(|ttl| (iat + ttl).timestamp()); - // console::log_1(&"exp done".into()); let claims = { let data = JwtBasicClaims { iss: DecodedClientId::from_key(&key.verifying_key()).into(), From 44e1ce6b2313cc7efe9c1f05f5b9e901beebfd08 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Tue, 3 Dec 2024 19:53:32 +0200 Subject: [PATCH 13/14] rename wasm_websocket_client --- .github/workflows/ci.yaml | 2 +- Cargo.toml | 3 +-- .../Cargo.toml | 5 ++++- .../README.md | 0 .../favicon.ico | Bin .../index.html | 0 .../src/lib.rs | 0 .../src/utils.rs | 0 .../styles.css | 0 9 files changed, 6 insertions(+), 4 deletions(-) rename {wasm_websocket_client => wasm_websocket_demo}/Cargo.toml (92%) rename {wasm_websocket_client => wasm_websocket_demo}/README.md (100%) rename {wasm_websocket_client => wasm_websocket_demo}/favicon.ico (100%) rename {wasm_websocket_client => wasm_websocket_demo}/index.html (100%) rename {wasm_websocket_client => wasm_websocket_demo}/src/lib.rs (100%) rename {wasm_websocket_client => wasm_websocket_demo}/src/utils.rs (100%) rename {wasm_websocket_client => wasm_websocket_demo}/styles.css (100%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b6c1423..3315e35 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -91,4 +91,4 @@ jobs: - name: Install wasm-pack run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - name: "wasm-pack" - run: cd wasm_websocket_client && wasm-pack build --target web + run: cd wasm_websocket_demo && wasm-pack build --target web diff --git a/Cargo.toml b/Cargo.toml index 13f221d..3801b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,7 @@ authors = ["WalletConnect Team"] license = "Apache-2.0" [workspace] -members = ["blockchain_api", "relay_client", "relay_rpc"] -exclude = ["wasm_websocket_client"] +members = ["blockchain_api", "relay_client", "relay_rpc", "wasm_websocket_demo"] [features] default = ["full"] diff --git a/wasm_websocket_client/Cargo.toml b/wasm_websocket_demo/Cargo.toml similarity index 92% rename from wasm_websocket_client/Cargo.toml rename to wasm_websocket_demo/Cargo.toml index 4f16278..28641d8 100644 --- a/wasm_websocket_client/Cargo.toml +++ b/wasm_websocket_demo/Cargo.toml @@ -1,10 +1,13 @@ [package] -name = "wasm_websocket_client" +name = "wasm_websocket_demo" version = "0.1.0" edition = "2021" authors = ["WalletConnect Team"] license = "Apache-2.0" +[build] +target = "wasm32-unknown-uknown" + [lib] crate-type = ["cdylib"] diff --git a/wasm_websocket_client/README.md b/wasm_websocket_demo/README.md similarity index 100% rename from wasm_websocket_client/README.md rename to wasm_websocket_demo/README.md diff --git a/wasm_websocket_client/favicon.ico b/wasm_websocket_demo/favicon.ico similarity index 100% rename from wasm_websocket_client/favicon.ico rename to wasm_websocket_demo/favicon.ico diff --git a/wasm_websocket_client/index.html b/wasm_websocket_demo/index.html similarity index 100% rename from wasm_websocket_client/index.html rename to wasm_websocket_demo/index.html diff --git a/wasm_websocket_client/src/lib.rs b/wasm_websocket_demo/src/lib.rs similarity index 100% rename from wasm_websocket_client/src/lib.rs rename to wasm_websocket_demo/src/lib.rs diff --git a/wasm_websocket_client/src/utils.rs b/wasm_websocket_demo/src/utils.rs similarity index 100% rename from wasm_websocket_client/src/utils.rs rename to wasm_websocket_demo/src/utils.rs diff --git a/wasm_websocket_client/styles.css b/wasm_websocket_demo/styles.css similarity index 100% rename from wasm_websocket_client/styles.css rename to wasm_websocket_demo/styles.css From d556e084e84f0b351bce52a51f56db03ba540630 Mon Sep 17 00:00:00 2001 From: Douglas Chimento Date: Wed, 4 Dec 2024 22:08:33 +0200 Subject: [PATCH 14/14] fmt and add dummy PROJECT_ID --- .github/workflows/ci.yaml | 1 + wasm_websocket_demo/src/lib.rs | 40 ++++++++++++++++-------------- wasm_websocket_demo/src/utils.rs | 42 +++++++++++++++++++------------- 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3315e35..bbb7dfd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -43,6 +43,7 @@ jobs: rust: stable env: RUST_BACKTRACE: full + PROJECT_ID: "dummy" steps: - uses: actions/checkout@v3 diff --git a/wasm_websocket_demo/src/lib.rs b/wasm_websocket_demo/src/lib.rs index aac419d..cfd5d51 100644 --- a/wasm_websocket_demo/src/lib.rs +++ b/wasm_websocket_demo/src/lib.rs @@ -1,21 +1,25 @@ mod utils; -use std::fmt::Display; -use std::fmt::Formatter; -use walletconnect_sdk::client::{ - error::ClientError, - websocket::{Client, CloseFrame, ConnectionHandler, PublishedMessage}, - ConnectionOptions, -}; -use wasm_bindgen::prelude::*; -use wasm_bindgen_futures::spawn_local; -use web_sys::console; - -use rand::rngs::OsRng; -use std::time::Duration; -use walletconnect_sdk::rpc::{ - auth::{ed25519_dalek::SigningKey, AuthToken}, - domain::Topic, +use { + rand::rngs::OsRng, + std::{ + fmt::{Display, Formatter}, + time::Duration, + }, + walletconnect_sdk::{ + client::{ + error::ClientError, + websocket::{Client, CloseFrame, ConnectionHandler, PublishedMessage}, + ConnectionOptions, + }, + rpc::{ + auth::{ed25519_dalek::SigningKey, AuthToken}, + domain::Topic, + }, + }, + wasm_bindgen::prelude::*, + wasm_bindgen_futures::spawn_local, + web_sys::console, }; enum ClientId { @@ -32,7 +36,7 @@ impl Display for ClientId { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { match self { ClientId::WC1 => write!(f, "wc1"), - ClientId::WC2 => write!(f, "wc2") + ClientId::WC2 => write!(f, "wc2"), } } } @@ -45,6 +49,7 @@ impl Handler { fn new(name: ClientId) -> Self { Self { client_id: name } } + fn error_div(&self) -> String { self.client_id.div("error") } @@ -145,4 +150,3 @@ pub fn run() { console::log_1(&"done".into()); }); } - diff --git a/wasm_websocket_demo/src/utils.rs b/wasm_websocket_demo/src/utils.rs index d029638..377cc82 100644 --- a/wasm_websocket_demo/src/utils.rs +++ b/wasm_websocket_demo/src/utils.rs @@ -1,18 +1,22 @@ -use crate::ClientId; -use gloo_timers::future::TimeoutFuture; -use std::sync::Arc; -use std::time::Duration; -use walletconnect_sdk::client::websocket::Client; -use walletconnect_sdk::client::ConnectionOptions; -use walletconnect_sdk::rpc::domain::Topic; -use wasm_bindgen::JsValue; -use web_sys::console; +use { + crate::ClientId, + gloo_timers::future::TimeoutFuture, + std::{sync::Arc, time::Duration}, + walletconnect_sdk::{ + client::{websocket::Client, ConnectionOptions}, + rpc::domain::Topic, + }, + wasm_bindgen::JsValue, + web_sys::console, +}; // Helper function to set text in the result div pub fn set_result_text(div: &str, text: &str) -> Result<(), JsValue> { let window = web_sys::window().expect("no global `window` exists"); let document = window.document().expect("should have a document on window"); - let result_div = document.get_element_by_id(div).expect("should have result element"); + let result_div = document + .get_element_by_id(div) + .expect("should have result element"); result_div.set_inner_html(""); @@ -54,13 +58,17 @@ pub async fn connect(id: &str, client: &Client, opts: &ConnectionOptions) { pub async fn publish(id: ClientId, client: Client, topic: Topic) { for i in 1..9 { let msg = format!("{i}"); - if let Err(e) = client.publish(topic.clone(), - Arc::from(msg.as_str()), - None, - 0, - Duration::from_secs(60), - false, - ).await { + if let Err(e) = client + .publish( + topic.clone(), + Arc::from(msg.as_str()), + None, + 0, + Duration::from_secs(60), + false, + ) + .await + { let error_msg = format!("Failed message send {e}"); let _ = set_result_text(&id.div("error"), &error_msg); return;