Skip to content

Commit

Permalink
feat(transport): Add WebTransport for WASM environments
Browse files Browse the repository at this point in the history
Use `web-sys::WebTransport` and provide a `Transport`.
  • Loading branch information
oblique committed Jun 2, 2023
1 parent e2e6816 commit 5346e01
Show file tree
Hide file tree
Showing 14 changed files with 1,051 additions and 4 deletions.
70 changes: 66 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ members = [
"transports/wasm-ext",
"transports/webrtc",
"transports/websocket",
"transports/websys-webtransport",
]
resolver = "2"

Expand Down Expand Up @@ -94,6 +95,7 @@ libp2p-uds = { version = "0.39.0", path = "transports/uds" }
libp2p-wasm-ext = { version = "0.40.0", path = "transports/wasm-ext" }
libp2p-webrtc = { version = "0.5.0-alpha", path = "transports/webrtc" }
libp2p-websocket = { version = "0.42.0", path = "transports/websocket" }
libp2p-websys-webtransport = { version = "0.43.0", path = "transports/websys-webtransport" }
libp2p-yamux = { version = "0.44.0", path = "muxers/yamux" }
multistream-select = { version = "0.13.0", path = "misc/multistream-select" }
quick-protobuf-codec = { version = "0.2.0", path = "misc/quick-protobuf-codec" }
Expand Down
5 changes: 5 additions & 0 deletions libp2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ full = [
"wasm-ext-websocket",
"webrtc",
"websocket",
"websys-webtransport",
"yamux",
]

Expand Down Expand Up @@ -83,6 +84,7 @@ wasm-ext = ["dep:libp2p-wasm-ext"]
wasm-ext-websocket = ["wasm-ext", "libp2p-wasm-ext?/websocket"]
webrtc = ["dep:libp2p-webrtc", "libp2p-webrtc?/pem"]
websocket = ["dep:libp2p-websocket"]
websys-webtransport = ["dep:libp2p-websys-webtransport"]
yamux = ["dep:libp2p-yamux"]

[dependencies]
Expand Down Expand Up @@ -128,6 +130,9 @@ libp2p-uds = { workspace = true, optional = true }
libp2p-webrtc = { workspace = true, optional = true }
libp2p-websocket = { workspace = true, optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
libp2p-websys-webtransport = { workspace = true, optional = true }

[dev-dependencies]
async-std = { version = "1.6.2", features = ["attributes"] }
async-trait = "0.1"
Expand Down
5 changes: 5 additions & 0 deletions libp2p/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ pub mod webrtc {
#[cfg(not(target_arch = "wasm32"))]
#[doc(inline)]
pub use libp2p_websocket as websocket;
#[cfg(feature = "websys-webtransport")]
#[cfg(target_arch = "wasm32")]
#[cfg_attr(docsrs, doc(cfg(feature = "websys-webtransport")))]
#[doc(inline)]
pub use libp2p_websys_webtransport as websys_webtransport;
#[cfg(feature = "yamux")]
#[doc(inline)]
pub use libp2p_yamux as yamux;
Expand Down
5 changes: 5 additions & 0 deletions transports/websys-webtransport/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## 0.43.0 - unreleased

* Initial implementation of WebTranport trasnport that uses web-sys. [PR 4015]

[PR 4015]: https://github.com/libp2p/rust-libp2p/pull/4015
48 changes: 48 additions & 0 deletions transports/websys-webtransport/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[package]
name = "libp2p-websys-webtransport"
edition = "2021"
rust-version = { workspace = true }
description = "WebTransport for libp2p under WASM environment"
version = "0.43.0"
authors = [
"Yiannis Marangos <yiannis@eiger.co>",
"oblique <psyberbits@gmail.com>",
]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"]

[dependencies]
futures = "0.3.28"
js-sys = "0.3.63"
libp2p-core = { workspace = true }
libp2p-identity = { workspace = true }
libp2p-noise = { workspace = true }
log = "0.4.18"
send_wrapper = { version = "0.6.0", features = ["futures"] }
thiserror = "1.0.4"
wasm-bindgen = "0.2.86"
wasm-bindgen-futures = "0.4.36"
web-sys = { version = "0.3.63", features = [
"ReadableStreamDefaultReader",
"WebTransport",
"WebTransportBidirectionalStream",
"WebTransportHash",
"WebTransportOptions",
"WebTransportReceiveStream",
"WebTransportSendStream",
"WritableStreamDefaultWriter",
] }

[dev-dependencies]
getrandom = { version = "0.2.9", features = ["js"] }
multibase = "0.9.1"
wasm-bindgen-test = "0.3.36"

# Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs", "--cfg", "web_sys_unstable_apis"]
rustc-args = ["--cfg", "docsrs", "--cfg", "web_sys_unstable_apis"]
60 changes: 60 additions & 0 deletions transports/websys-webtransport/src/cached_js_promise.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use futures::FutureExt;
use js_sys::Promise;
use send_wrapper::SendWrapper;
use std::task::{ready, Context, Poll};
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::JsFuture;

/// Convenient wrapper to poll a promise to completion.
pub(crate) struct CachedJsPromise {
promise: Option<SendWrapper<JsFuture>>,
}

impl CachedJsPromise {
/// Creates new uninitialized promise.
pub(crate) fn new() -> Self {
CachedJsPromise { promise: None }
}

/// Initialize promise if needed and then poll.
///
/// If promise is not initialized then call `init` and initialize it.
pub(crate) fn maybe_init_and_poll<F>(
&mut self,
cx: &mut Context,
init: F,
) -> Poll<Result<JsValue, JsValue>>
where
F: FnOnce() -> Promise,
{
if self.promise.is_none() {
self.promise = Some(SendWrapper::new(JsFuture::from(init())));
}

self.poll(cx)
}

/// Poll an already initialized promise.
///
/// # Panics
///
/// If promise is not initialized then it panics. Use `maybe_init_and_poll`
/// if unsure.
pub(crate) fn poll(&mut self, cx: &mut Context) -> Poll<Result<JsValue, JsValue>> {
let val = ready!(self
.promise
.as_mut()
.expect("CachedJsPromise not initialized")
.poll_unpin(cx));

// Future finished, drop it
self.promise.take();

Poll::Ready(val)
}

/// Checks if promise is already running
pub(crate) fn is_active(&self) -> bool {
self.promise.is_some()
}
}
Loading

0 comments on commit 5346e01

Please sign in to comment.