remove ws_stream_wasm, wisp_mux 1.1.2

This commit is contained in:
Toshit Chawda 2024-03-02 16:03:18 -08:00
parent 06d3225721
commit 1bf1a809bd
No known key found for this signature in database
GPG key ID: 91480ED99E2B3D9D
7 changed files with 202 additions and 114 deletions

View file

@ -14,24 +14,25 @@ hyper = { version = "1.1.0", features = ["client", "http1", "http2"] }
pin-project-lite = "0.2.13"
wasm-bindgen = { version = "0.2.91", features = ["enable-interning"] }
wasm-bindgen-futures = "0.4.39"
ws_stream_wasm = { version = "0.7.4", features = ["tokio_io"] }
futures-util = "0.3.30"
js-sys = "0.3.66"
webpki-roots = "0.26.0"
tokio-rustls = "0.25.0"
web-sys = { version = "0.3.66", features = ["TextEncoder", "Response", "ResponseInit"] }
web-sys = { version = "0.3.66", features = ["TextEncoder", "Response", "ResponseInit", "WebSocket", "BinaryType", "MessageEvent"] }
wasm-streams = "0.4.0"
tokio-util = { version = "0.7.10", features = ["io"] }
async-compression = { version = "0.4.5", features = ["tokio", "gzip", "brotli"] }
fastwebsockets = { version = "0.6.0", features = ["unstable-split"] }
base64 = "0.21.7"
wisp-mux = { path = "../wisp", features = ["ws_stream_wasm", "tokio_io", "hyper_tower"] }
wisp-mux = { path = "../wisp", features = ["tokio_io", "hyper_tower"] }
async_io_stream = { version = "0.3.3", features = ["tokio_io"] }
getrandom = { version = "0.2.12", features = ["js"] }
hyper-util-wasm = { version = "0.1.3", features = ["client", "client-legacy", "http1", "http2"] }
tokio = { version = "1.36.0", default-features = false }
tower-service = "0.3.2"
console_error_panic_hook = "0.1.7"
send_wrapper = "0.6.0"
event-listener = "5.2.0"
[dependencies.ring]
features = ["wasm32_unknown_unknown_js"]

View file

@ -8,14 +8,14 @@ mod wrappers;
use tls_stream::EpxTlsStream;
use utils::{Boolinator, ReplaceErr, UriExt};
use websocket::EpxWebSocket;
use wrappers::{IncomingBody, TlsWispService};
use wrappers::{IncomingBody, TlsWispService, WebSocketWrapper};
use std::sync::Arc;
use async_compression::tokio::bufread as async_comp;
use async_io_stream::IoStream;
use bytes::Bytes;
use futures_util::{stream::SplitSink, StreamExt};
use futures_util::StreamExt;
use http::{uri, HeaderName, HeaderValue, Request, Response};
use hyper::{body::Incoming, Uri};
use hyper_util_wasm::client::legacy::Client;
@ -28,7 +28,6 @@ use tokio_util::{
use wasm_bindgen::{intern, prelude::*};
use web_sys::TextEncoder;
use wisp_mux::{tokioio::TokioIo, tower::ServiceWrapper, ClientMux, MuxStreamIo, StreamType};
use ws_stream_wasm::{WsMessage, WsMeta, WsStream};
type HttpBody = http_body_util::Full<Bytes>;
@ -64,12 +63,11 @@ fn init() {
intern("rawHeaders");
}
#[wasm_bindgen(inspectable)]
pub struct EpoxyClient {
rustls_config: Arc<rustls::ClientConfig>,
mux: Arc<ClientMux<SplitSink<WsStream, WsMessage>>>,
hyper_client: Client<TlsWispService<SplitSink<WsStream, WsMessage>>, HttpBody>,
mux: Arc<ClientMux<WebSocketWrapper>>,
hyper_client: Client<TlsWispService<WebSocketWrapper>, HttpBody>,
#[wasm_bindgen(getter_with_clone)]
pub useragent: String,
#[wasm_bindgen(js_name = "redirectLimit")]
@ -96,12 +94,11 @@ impl EpoxyClient {
}
debug!("connecting to ws {:?}", ws_url);
let (_, ws) = WsMeta::connect(ws_url, vec![])
let (wtx, wrx) = WebSocketWrapper::connect(ws_url, vec![])
.await
.replace_err("Failed to connect to websocket")?;
debug!("connected!");
let (wtx, wrx) = ws.split();
let (mux, fut) = ClientMux::new(wrx, wtx).await?;
let mux = Arc::new(mux);

View file

@ -4,11 +4,21 @@ use std::{
task::{Context, Poll},
};
use event_listener::Event;
use futures_util::Stream;
use hyper::body::Body;
use js_sys::ArrayBuffer;
use pin_project_lite::pin_project;
use send_wrapper::SendWrapper;
use std::future::Future;
use wisp_mux::{tokioio::TokioIo, tower::ServiceWrapper, WispError};
use tokio::sync::mpsc;
use web_sys::{BinaryType, MessageEvent, WebSocket};
use wisp_mux::{
tokioio::TokioIo,
tower::ServiceWrapper,
ws::{Frame, LockedWebSocketWrite, WebSocketRead, WebSocketWrite},
WispError,
};
pin_project! {
pub struct IncomingBody {
@ -51,7 +61,6 @@ where
pub rustls_config: Arc<rustls::ClientConfig>,
}
impl<W: wisp_mux::ws::WebSocketWrite + Send + 'static> tower_service::Service<hyper::Uri>
for TlsWispService<W>
{
@ -107,3 +116,173 @@ impl<W: wisp_mux::ws::WebSocketWrite + Send + 'static> Clone for TlsWispService<
}
}
}
#[derive(Debug)]
pub enum WebSocketError {
Closed,
Unknown,
SendFailed,
}
impl std::fmt::Display for WebSocketError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
use WebSocketError::*;
match self {
Closed => write!(f, "Websocket closed"),
Unknown => write!(f, "Unknown error"),
SendFailed => write!(f, "Send failed"),
}
}
}
impl std::error::Error for WebSocketError {}
impl From<WebSocketError> for WispError {
fn from(err: WebSocketError) -> Self {
Self::WsImplError(Box::new(err))
}
}
pub enum WebSocketMessage {
Close,
Error,
Message(Vec<u8>),
}
pub struct WebSocketWrapper {
inner: SendWrapper<WebSocket>,
// used to retain the closures
#[allow(dead_code)]
onopen: SendWrapper<Closure<dyn Fn()>>,
#[allow(dead_code)]
onclose: SendWrapper<Closure<dyn Fn()>>,
#[allow(dead_code)]
onerror: SendWrapper<Closure<dyn Fn()>>,
#[allow(dead_code)]
onmessage: SendWrapper<Closure<dyn Fn(MessageEvent)>>,
}
pub struct WebSocketReader {
read_rx: mpsc::UnboundedReceiver<WebSocketMessage>,
}
impl WebSocketRead for WebSocketReader {
async fn wisp_read_frame(
&mut self,
_: &LockedWebSocketWrite<impl WebSocketWrite>,
) -> Result<Frame, WispError> {
use WebSocketMessage::*;
match self
.read_rx
.recv()
.await
.ok_or(WispError::WsImplError(Box::new(WebSocketError::Closed)))?
{
Message(bin) => Ok(Frame::binary(bin.into())),
Error => Err(WebSocketError::Unknown.into()),
Close => Err(WebSocketError::Closed.into()),
}
}
}
impl WebSocketWrapper {
pub async fn connect(
url: String,
protocols: Vec<String>,
) -> Result<(Self, WebSocketReader), JsValue> {
let ws = if protocols.is_empty() {
WebSocket::new(&url)
} else {
WebSocket::new_with_str_sequence(
&url,
&protocols
.iter()
.fold(Array::new(), |acc, x| {
acc.push(&jval!(x));
acc
})
.into(),
)
}
.replace_err("Failed to make websocket")?;
ws.set_binary_type(BinaryType::Arraybuffer);
let (read_tx, read_rx) = mpsc::unbounded_channel();
let open_event = Arc::new(Event::new());
let open_event_tx = open_event.clone();
let onopen = Closure::wrap(
Box::new(move || while open_event_tx.notify(usize::MAX) == 0 {}) as Box<dyn Fn()>,
);
let onmessage_tx = read_tx.clone();
let onmessage = Closure::wrap(Box::new(move |evt: MessageEvent| {
if let Ok(arr) = evt.data().dyn_into::<ArrayBuffer>() {
let _ =
onmessage_tx.send(WebSocketMessage::Message(Uint8Array::new(&arr).to_vec()));
}
}) as Box<dyn Fn(MessageEvent)>);
ws.set_onopen(Some(onopen.as_ref().unchecked_ref()));
ws.set_onmessage(Some(onmessage.as_ref().unchecked_ref()));
let onclose_tx = read_tx.clone();
let onclose = Closure::wrap(Box::new(move || {
let _ = onclose_tx.send(WebSocketMessage::Close);
}) as Box<dyn Fn()>);
let onerror_tx = read_tx.clone();
let onerror = Closure::wrap(Box::new(move || {
let _ = onerror_tx.send(WebSocketMessage::Error);
}) as Box<dyn Fn()>);
ws.set_onclose(Some(onclose.as_ref().unchecked_ref()));
ws.set_onerror(Some(onerror.as_ref().unchecked_ref()));
open_event.listen().await;
Ok((
Self {
inner: SendWrapper::new(ws),
onopen: SendWrapper::new(onopen),
onclose: SendWrapper::new(onclose),
onerror: SendWrapper::new(onerror),
onmessage: SendWrapper::new(onmessage),
},
WebSocketReader { read_rx },
))
}
}
impl WebSocketWrite for WebSocketWrapper {
async fn wisp_write_frame(&mut self, frame: Frame) -> Result<(), WispError> {
use wisp_mux::ws::OpCode::*;
match frame.opcode {
Binary => self
.inner
.send_with_u8_array(&frame.payload)
.map_err(|_| WebSocketError::SendFailed.into()),
Text => self
.inner
.send_with_u8_array(&frame.payload)
.map_err(|_| WebSocketError::SendFailed.into()),
Close => {
let _ = self.inner.close();
Ok(())
}
_ => Err(WispError::WsImplNotSupported),
}
}
}
impl Drop for WebSocketWrapper {
fn drop(&mut self) {
self.inner.set_onopen(None);
self.inner.set_onclose(None);
self.inner.set_onerror(None);
self.inner.set_onmessage(None);
}
}