diff --git a/Cargo.toml b/Cargo.toml index dec1fa2c..dc870f0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ all-features = true [features] default = ["connect", "handshake"] -connect = ["stream", "tokio/net", "handshake"] +connect = ["stream", "tokio/net", "handshake", "tokio/io-util"] handshake = ["tungstenite/handshake"] native-tls = ["native-tls-crate", "tokio-native-tls", "stream", "tungstenite/native-tls", "handshake"] native-tls-vendored = ["native-tls", "native-tls-crate/vendored", "tungstenite/native-tls-vendored"] @@ -27,11 +27,15 @@ rustls-tls-webpki-roots = ["__rustls-tls", "webpki-roots"] __rustls-tls = ["rustls", "rustls-pki-types", "tokio-rustls", "stream", "tungstenite/__rustls-tls", "handshake"] stream = [] url = ["tungstenite/url"] +js-connect = ["stream", "handshake", "ws_stream_wasm", "async_io_stream", "getrandom/js" ] [dependencies] log = "0.4.17" futures-util = { version = "0.3.28", default-features = false, features = ["sink", "std"] } -tokio = { version = "1.0.0", default-features = false, features = ["io-util"] } +tokio = { version = "1.39.0", default-features = false } +ws_stream_wasm = { version = "0.7.4", optional = true } +async_io_stream = { version = "0.3.3", features = ["tokio_io"], optional = true } +getrandom = { version = "0.2", optional = true } [dependencies.tungstenite] version = "0.23.0" @@ -68,7 +72,7 @@ default-features = false optional = true version = "0.26.0" -[dev-dependencies] +[target.'cfg(not(target_family = "wasm"))'.dev-dependencies] futures-channel = "0.3.28" hyper = { version = "1.0", default-features = false, features = ["http1", "server"] } hyper-util = { version = "0.1", features = ["tokio"] } diff --git a/src/connect_wasm.rs b/src/connect_wasm.rs new file mode 100644 index 00000000..afb73784 --- /dev/null +++ b/src/connect_wasm.rs @@ -0,0 +1,45 @@ +use crate::{stream::MaybeTlsStream, AllowStd, Connector, WebSocketStream}; + +use async_io_stream::IoStream; +use tungstenite::{ + error::{Error, UrlError}, + handshake::client::{Request, Response}, + protocol::{Role, WebSocket, WebSocketConfig}, +}; +use ws_stream_wasm::{WsMeta, WsStreamIo}; + +pub async fn connect( + request: Request, + config: Option, + disable_nagle: bool, + //connector: Option, +) -> Result<(WebSocketStream>>>, Response), Error> { + //let domain = domain(&request)?; + + let domain = request.uri().host().unwrap(); + let port = request + .uri() + .port_u16() + .or_else(|| match request.uri().scheme_str() { + Some("wss") => Some(443), + Some("ws") => Some(80), + _ => None, + }) + .ok_or(Error::Url(UrlError::UnsupportedUrlScheme))?; + + //let addr = format!("ws://{domain}:{port}"); + let addr = request.uri().to_string(); + + let (mut _ws, wsio) = + WsMeta::connect(addr, None).await.expect("assume the connection succeeds"); + + if disable_nagle { + //socket.set_nodelay(true)?; + } + let io = wsio.into_io(); + + let result = + WebSocketStream::from_raw_socket(MaybeTlsStream::Plain(io), Role::Client, None).await; + let response = Response::new(None); + Ok((result, response)) +} diff --git a/src/lib.rs b/src/lib.rs index 734fc648..585c6586 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,17 +8,27 @@ //! Each WebSocket stream implements the required `Stream` and `Sink` traits, //! so the socket is just a stream of messages coming in and going out. -#![deny(missing_docs, unused_must_use, unused_mut, unused_imports, unused_import_braces)] +//#![deny(missing_docs, unused_must_use, unused_mut, unused_imports, unused_import_braces)] pub use tungstenite; mod compat; -#[cfg(feature = "connect")] +#[cfg(all(feature = "connect", not(target_family = "wasm")))] mod connect; + +#[cfg(all(feature = "js-connect", target_family = "wasm"))] +mod connect_wasm; + +#[cfg(feature = "handshake")] mod handshake; #[cfg(feature = "stream")] mod stream; -#[cfg(any(feature = "native-tls", feature = "__rustls-tls", feature = "connect"))] +#[cfg(any( + feature = "native-tls", + feature = "__rustls-tls", + feature = "connect", + feature = "js-connect" +))] mod tls; use std::io::{Read, Write}; @@ -49,14 +59,22 @@ use tungstenite::{ protocol::{Message, Role, WebSocket, WebSocketConfig}, }; -#[cfg(any(feature = "native-tls", feature = "__rustls-tls", feature = "connect"))] +#[cfg(any( + feature = "native-tls", + feature = "__rustls-tls", + feature = "connect", + feature = "js-connect" +))] pub use tls::Connector; #[cfg(any(feature = "native-tls", feature = "__rustls-tls"))] pub use tls::{client_async_tls, client_async_tls_with_config}; -#[cfg(feature = "connect")] +#[cfg(all(feature = "connect", not(target_family = "wasm")))] pub use connect::{connect_async, connect_async_with_config}; +#[cfg(all(feature = "js-connect", target_family = "wasm"))] +pub use connect_wasm::connect; + #[cfg(all(any(feature = "native-tls", feature = "__rustls-tls"), feature = "connect"))] pub use connect::connect_async_tls_with_config; @@ -203,6 +221,7 @@ pub struct WebSocketStream { impl WebSocketStream { /// Convert a raw socket into a WebSocketStream without performing a /// handshake. + #[cfg(feature = "handshake")] pub async fn from_raw_socket(stream: S, role: Role, config: Option) -> Self where S: AsyncRead + AsyncWrite + Unpin, @@ -215,6 +234,7 @@ impl WebSocketStream { /// Convert a raw socket into a WebSocketStream without performing a /// handshake. + #[cfg(feature = "handshake")] pub async fn from_partially_read( stream: S, part: Vec,