Skip to content

Commit 3a02156

Browse files
committed
fix(websocket-websys): Add support for different WASM environments
Add support different WASM environments (such as workers, NodeJS) that don't have a `window` global. This is done by introducing a `WebContext` `enum` that abstracts and detects the `Window` vs the `WorkerGlobalScope` API. This is done due to the `web-sys` lack of interest to support this (see discussion in [this issue](rustwasm/wasm-bindgen#1046)).
1 parent 338e467 commit 3a02156

File tree

6 files changed

+77
-10
lines changed

6 files changed

+77
-10
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ libp2p-webrtc = { version = "0.6.1-alpha", path = "transports/webrtc" }
110110
libp2p-webrtc-utils = { version = "0.1.0", path = "misc/webrtc-utils" }
111111
libp2p-webrtc-websys = { version = "0.2.0-alpha", path = "transports/webrtc-websys" }
112112
libp2p-websocket = { version = "0.43.0", path = "transports/websocket" }
113-
libp2p-websocket-websys = { version = "0.3.0", path = "transports/websocket-websys" }
113+
libp2p-websocket-websys = { version = "0.3.1", path = "transports/websocket-websys" }
114114
libp2p-webtransport-websys = { version = "0.2.0", path = "transports/webtransport-websys" }
115115
libp2p-yamux = { version = "0.45.0", path = "muxers/yamux" }
116116
multiaddr = "0.18.1"

transports/websocket-websys/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.3.1
2+
3+
- Add support for different WASM environments by introducing a `WebContext` that
4+
detects and abstracts the `Window` vs the `WorkerGlobalScope` API.
5+
See [PR 4889](https://github.com/libp2p/rust-libp2p/pull/4889).
6+
17
## 0.3.0
28

39

transports/websocket-websys/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "libp2p-websocket-websys"
33
edition = "2021"
44
rust-version = "1.60.0"
55
description = "WebSocket for libp2p under WASM environment"
6-
version = "0.3.0"
6+
version = "0.3.1"
77
authors = ["Vince Vasta <[email protected]>"]
88
license = "MIT"
99
repository = "https://github.com/libp2p/rust-libp2p"
@@ -20,7 +20,7 @@ parking_lot = "0.12.1"
2020
send_wrapper = "0.6.0"
2121
thiserror = "1.0.50"
2222
wasm-bindgen = "0.2.88"
23-
web-sys = { version = "0.3.65", features = ["BinaryType", "CloseEvent", "MessageEvent", "WebSocket", "Window"] }
23+
web-sys = { version = "0.3.65", features = ["BinaryType", "CloseEvent", "MessageEvent", "WebSocket", "Window", "WorkerGlobalScope"] }
2424

2525
# Passing arguments to the docsrs builder in order to properly document cfg's.
2626
# More information: https://docs.rs/about/builds#cross-compiling

transports/websocket-websys/src/lib.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
//! Libp2p websocket transports built on [web-sys](https://rustwasm.github.io/wasm-bindgen/web-sys/index.html).
2222
23+
mod web_context;
24+
2325
use bytes::BytesMut;
2426
use futures::task::AtomicWaker;
2527
use futures::{future::Ready, io, prelude::*};
@@ -35,7 +37,9 @@ use std::sync::atomic::{AtomicBool, Ordering};
3537
use std::sync::Mutex;
3638
use std::{pin::Pin, task::Context, task::Poll};
3739
use wasm_bindgen::{prelude::*, JsCast};
38-
use web_sys::{window, CloseEvent, Event, MessageEvent, WebSocket};
40+
use web_sys::{CloseEvent, Event, MessageEvent, WebSocket};
41+
42+
use crate::web_context::WebContext;
3943

4044
/// A Websocket transport that can be used in a wasm environment.
4145
///
@@ -300,8 +304,8 @@ impl Connection {
300304
}
301305
}
302306
});
303-
let buffered_amount_low_interval = window()
304-
.expect("to have a window")
307+
let buffered_amount_low_interval = WebContext::new()
308+
.expect("to have a window or worker context")
305309
.set_interval_with_callback_and_timeout_and_arguments(
306310
on_buffered_amount_low_closure.as_ref().unchecked_ref(),
307311
100, // Chosen arbitrarily and likely worth tuning. Due to low impact of the /ws transport, no further effort was invested at the time.
@@ -439,8 +443,8 @@ impl Drop for Connection {
439443
.close_with_code_and_reason(GO_AWAY_STATUS_CODE, "connection dropped");
440444
}
441445

442-
window()
443-
.expect("to have a window")
444-
.clear_interval_with_handle(self.inner.buffered_amount_low_interval)
446+
WebContext::new()
447+
.expect("to have a window or worker context")
448+
.clear_interval_with_handle(self.inner.buffered_amount_low_interval);
445449
}
446450
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use wasm_bindgen::{prelude::*, JsCast};
2+
use web_sys::window;
3+
4+
/// Web context that abstract the window vs web worker API
5+
#[derive(Debug)]
6+
pub(crate) enum WebContext {
7+
Window(web_sys::Window),
8+
Worker(web_sys::WorkerGlobalScope),
9+
}
10+
11+
impl WebContext {
12+
pub(crate) fn new() -> Option<Self> {
13+
match window() {
14+
Some(window) => Some(Self::Window(window)),
15+
None => {
16+
#[wasm_bindgen]
17+
extern "C" {
18+
type Global;
19+
20+
#[wasm_bindgen(method, getter, js_name = WorkerGlobalScope)]
21+
fn worker(this: &Global) -> JsValue;
22+
}
23+
let global: Global = js_sys::global().unchecked_into();
24+
if !global.worker().is_undefined() {
25+
Some(Self::Worker(global.unchecked_into()))
26+
} else {
27+
None
28+
}
29+
}
30+
}
31+
}
32+
33+
/// The `setInterval()` method.
34+
pub(crate) fn set_interval_with_callback_and_timeout_and_arguments(
35+
&self,
36+
handler: &::js_sys::Function,
37+
timeout: i32,
38+
arguments: &::js_sys::Array,
39+
) -> Result<i32, JsValue> {
40+
match self {
41+
WebContext::Window(w) => {
42+
w.set_interval_with_callback_and_timeout_and_arguments(handler, timeout, arguments)
43+
}
44+
WebContext::Worker(w) => {
45+
w.set_interval_with_callback_and_timeout_and_arguments(handler, timeout, arguments)
46+
}
47+
}
48+
}
49+
50+
/// The `clearInterval()` method.
51+
pub(crate) fn clear_interval_with_handle(&self, handle: i32) {
52+
match self {
53+
WebContext::Window(w) => w.clear_interval_with_handle(handle),
54+
WebContext::Worker(w) => w.clear_interval_with_handle(handle),
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)