mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-02-08 21:33:09 -05:00
added datagrams rc signal and tx closure
This commit is contained in:
parent
40c9b7b92c
commit
f2f926b76c
2 changed files with 134 additions and 5 deletions
|
@ -58,6 +58,10 @@ features = [
|
||||||
"Navigator",
|
"Navigator",
|
||||||
"NodeList",
|
"NodeList",
|
||||||
"PointerEvent",
|
"PointerEvent",
|
||||||
|
"ReadableStream",
|
||||||
|
"ReadableStreamByobReader",
|
||||||
|
"ReadableStreamGetReaderOptions",
|
||||||
|
"ReadableStreamReaderMode",
|
||||||
"ResizeObserver",
|
"ResizeObserver",
|
||||||
"ResizeObserverBoxOptions",
|
"ResizeObserverBoxOptions",
|
||||||
"ResizeObserverEntry",
|
"ResizeObserverEntry",
|
||||||
|
@ -73,7 +77,10 @@ features = [
|
||||||
"WebSocket",
|
"WebSocket",
|
||||||
"WebTransport",
|
"WebTransport",
|
||||||
"WebTransportOptions",
|
"WebTransportOptions",
|
||||||
|
"WebTransportDatagramDuplexStream",
|
||||||
"Window",
|
"Window",
|
||||||
|
"WritableStream",
|
||||||
|
"WritableStreamDefaultWriter",
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
use crate::core::ConnectionReadyState;
|
use crate::core::ConnectionReadyState;
|
||||||
use crate::utils::{CloneableFn, CloneableFnWithArg};
|
|
||||||
use default_struct_builder::DefaultBuilder;
|
use default_struct_builder::DefaultBuilder;
|
||||||
|
use js_sys::{Reflect, Uint8Array};
|
||||||
use leptos::leptos_dom::helpers::TimeoutHandle;
|
use leptos::leptos_dom::helpers::TimeoutHandle;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use web_sys::{
|
||||||
|
ReadableStream, ReadableStreamReaderMode, WebTransport, WritableStreamDefaultWriter,
|
||||||
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -27,7 +30,7 @@ use wasm_bindgen_futures::JsFuture;
|
||||||
/// # view! { }
|
/// # view! { }
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn use_webtransport(url: &str) -> UseWebtransportReturn {
|
pub fn use_webtransport(url: &str) -> UseWebTransportReturn<impl Fn(Vec<u8>) + Clone + 'static> {
|
||||||
use_webtransport_with_options(url, UseWebTransportOptions::default())
|
use_webtransport_with_options(url, UseWebTransportOptions::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +38,7 @@ pub fn use_webtransport(url: &str) -> UseWebtransportReturn {
|
||||||
pub fn use_webtransport_with_options(
|
pub fn use_webtransport_with_options(
|
||||||
url: &str,
|
url: &str,
|
||||||
options: UseWebTransportOptions,
|
options: UseWebTransportOptions,
|
||||||
) -> UseWebtransportReturn {
|
) -> UseWebTransportReturn<impl Fn(Vec<u8>) + Clone + 'static> {
|
||||||
let UseWebTransportOptions {
|
let UseWebTransportOptions {
|
||||||
on_open,
|
on_open,
|
||||||
on_error,
|
on_error,
|
||||||
|
@ -48,6 +51,8 @@ pub fn use_webtransport_with_options(
|
||||||
let (ready_state, set_ready_state) = create_signal(ConnectionReadyState::Closed);
|
let (ready_state, set_ready_state) = create_signal(ConnectionReadyState::Closed);
|
||||||
|
|
||||||
let transport_ref = store_value(None::<web_sys::WebTransport>);
|
let transport_ref = store_value(None::<web_sys::WebTransport>);
|
||||||
|
let datagrams_reader_initialized_ref = store_value(false);
|
||||||
|
let datagrams_writer_ref = store_value(None::<web_sys::WritableStreamDefaultWriter>);
|
||||||
|
|
||||||
let reconnect_timer_ref = store_value(None::<TimeoutHandle>);
|
let reconnect_timer_ref = store_value(None::<TimeoutHandle>);
|
||||||
let reconnect_count_ref = store_value(0_u64);
|
let reconnect_count_ref = store_value(0_u64);
|
||||||
|
@ -132,11 +137,121 @@ pub fn use_webtransport_with_options(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
UseWebtransportReturn {
|
let (datagrams_signal, set_datagrams) = create_signal(None::<Vec<u8>>);
|
||||||
|
|
||||||
|
let datagrams = Signal::derive(move || {
|
||||||
|
// lazily create datagrams reader listener
|
||||||
|
if ready_state.get() == ConnectionReadyState::Open {
|
||||||
|
initialize_datagrams_reader(
|
||||||
|
transport_ref,
|
||||||
|
datagrams_reader_initialized_ref,
|
||||||
|
set_datagrams,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
datagrams_signal.get()
|
||||||
|
});
|
||||||
|
|
||||||
|
let send_datagrams = move |data| {
|
||||||
|
if let Some(transport) = transport_ref.get_value() {
|
||||||
|
let writer = get_or_create_datagrams_writer(datagrams_writer_ref, transport);
|
||||||
|
|
||||||
|
let _ = writer.write_with_chunk(&data.into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO : reliable streams
|
||||||
|
|
||||||
|
UseWebTransportReturn {
|
||||||
ready_state: ready_state.into(),
|
ready_state: ready_state.into(),
|
||||||
|
datagrams,
|
||||||
|
send_datagrams,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_or_create_datagrams_writer(
|
||||||
|
datagrams_writer_ref: StoredValue<Option<WritableStreamDefaultWriter>>,
|
||||||
|
transport: WebTransport,
|
||||||
|
) -> WritableStreamDefaultWriter {
|
||||||
|
if let Some(writer) = datagrams_writer_ref.get_value() {
|
||||||
|
writer
|
||||||
|
} else {
|
||||||
|
let writer = transport
|
||||||
|
.datagrams()
|
||||||
|
.writable()
|
||||||
|
.get_writer()
|
||||||
|
.expect("should be able to get the writer");
|
||||||
|
datagrams_writer_ref.set_value(Some(writer.clone()));
|
||||||
|
writer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_datagrams_reader(
|
||||||
|
transport_ref: StoredValue<Option<web_sys::WebTransport>>,
|
||||||
|
datagrams_reader_initialized_ref: StoredValue<bool>,
|
||||||
|
set_datagrams: WriteSignal<Option<Vec<u8>>>,
|
||||||
|
) {
|
||||||
|
if !datagrams_reader_initialized_ref.get_value() {
|
||||||
|
if let Some(transport) = transport_ref.get_value() {
|
||||||
|
datagrams_reader_initialized_ref.set_value(true);
|
||||||
|
|
||||||
|
listen_to_stream(
|
||||||
|
transport.datagrams().readable(),
|
||||||
|
move || datagrams_reader_initialized_ref.set_value(false),
|
||||||
|
set_datagrams,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listen_to_stream(
|
||||||
|
readable_stream: ReadableStream,
|
||||||
|
on_done: fn(),
|
||||||
|
set_signal: WriteSignal<Option<Vec<u8>>>,
|
||||||
|
) {
|
||||||
|
let mut reader_options = web_sys::ReadableStreamGetReaderOptions::new();
|
||||||
|
reader_options.mode(ReadableStreamReaderMode::Byob);
|
||||||
|
|
||||||
|
let reader: web_sys::ReadableStreamByobReader = readable_stream
|
||||||
|
.get_reader_with_options(&reader_options)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
spawn_local(async move {
|
||||||
|
// the length value 4000 is taken from the MDN example
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader/read#examples
|
||||||
|
let mut buffer = [0_u8; 4000];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let result = JsFuture::from(reader.read_with_u8_array(&mut buffer)).await;
|
||||||
|
match result {
|
||||||
|
Ok(result) => {
|
||||||
|
let done = Reflect::get(&result, &"done".into())
|
||||||
|
.expect("done should always be there")
|
||||||
|
.as_bool()
|
||||||
|
.unwrap_or(true);
|
||||||
|
|
||||||
|
if done {
|
||||||
|
// TODO : close connection?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: Uint8Array = Reflect::get(&result, &"value".into())
|
||||||
|
.expect("if not done there should be a value")
|
||||||
|
.into();
|
||||||
|
|
||||||
|
set_signal.set(Some(value.to_vec()))
|
||||||
|
}
|
||||||
|
Err(..) => {
|
||||||
|
// TODO : error handling?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on_done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Options for [`use_webtransport_with_options`].
|
/// Options for [`use_webtransport_with_options`].
|
||||||
#[derive(DefaultBuilder)]
|
#[derive(DefaultBuilder)]
|
||||||
pub struct UseWebTransportOptions {
|
pub struct UseWebTransportOptions {
|
||||||
|
@ -176,9 +291,16 @@ impl From<UseWebTransportOptions> for web_sys::WebTransportOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return type of [`use_webtransport`].
|
/// Return type of [`use_webtransport`].
|
||||||
pub struct UseWebtransportReturn {
|
pub struct UseWebTransportReturn<SendGramsFn>
|
||||||
|
where
|
||||||
|
SendGramsFn: Fn(Vec<u8>) + Clone + 'static,
|
||||||
|
{
|
||||||
/// The current state of the `WebTransport` connection.
|
/// The current state of the `WebTransport` connection.
|
||||||
pub ready_state: Signal<ConnectionReadyState>,
|
pub ready_state: Signal<ConnectionReadyState>,
|
||||||
|
/// Latest datagrams message received
|
||||||
|
pub datagrams: Signal<Option<Vec<u8>>>,
|
||||||
|
/// Sends binary data through the datagrams stream
|
||||||
|
pub send_datagrams: SendGramsFn,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error enum for [`UseWebTransportOptions::on_error`]
|
/// Error enum for [`UseWebTransportOptions::on_error`]
|
||||||
|
|
Loading…
Add table
Reference in a new issue