ported internal callbacks to Rc RefCells

This commit is contained in:
Maccesch 2023-08-15 12:15:58 +01:00
parent 3cd1728134
commit b80553751b

View file

@ -3,13 +3,11 @@ use default_struct_builder::DefaultBuilder;
use js_sys::{Reflect, Uint8Array}; use js_sys::{Reflect, Uint8Array};
use leptos::leptos_dom::helpers::TimeoutHandle; use leptos::leptos_dom::helpers::TimeoutHandle;
use leptos::*; use leptos::*;
use std::cell::{Cell, RefCell};
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,
};
/// ///
/// ///
@ -50,25 +48,31 @@ 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 = Rc::new(RefCell::new(None::<web_sys::WebTransport>));
let datagrams_reader_initialized_ref = store_value(false); let datagrams_reader_initialized = Rc::new(Cell::new(false));
let datagrams_writer_ref = store_value(None::<web_sys::WritableStreamDefaultWriter>); let datagrams_writer = Rc::new(RefCell::new(None::<web_sys::WritableStreamDefaultWriter>));
let reconnect_timer_ref = store_value(None::<TimeoutHandle>); let reconnect_timer = Rc::new(Cell::new(None::<TimeoutHandle>));
let reconnect_count_ref = store_value(0_u64); let reconnect_count = Rc::new(Cell::new(0_u64));
let unmounted = Rc::new(Cell::new(false));
let connect_ref = store_value(None::<Rc<dyn Fn()>>); let connect_ref = store_value(None::<Rc<dyn Fn()>>);
let reconnect = Rc::new(move || { let reconnect = Rc::new({
if reconnect_count_ref.get_value() < reconnect_limit let reconnect_timer = Rc::clone(&reconnect_timer);
let reconnect_count = Rc::clone(&reconnect_count);
move || {
if reconnect_count.get() < reconnect_limit
&& ready_state.get_untracked() == ConnectionReadyState::Open && ready_state.get_untracked() == ConnectionReadyState::Open
{ {
reconnect_timer_ref.set_value( reconnect_timer.set(
set_timeout_with_handle( set_timeout_with_handle(
move || { move || {
if let Some(connect) = connect_ref.get_value() { if let Some(connect) = connect_ref.get_value() {
connect(); connect();
reconnect_count_ref.update_value(|current| *current += 1); reconnect_count.set(reconnect_count.get() + 1);
} }
}, },
Duration::from_millis(reconnect_interval), Duration::from_millis(reconnect_interval),
@ -76,12 +80,17 @@ pub fn use_webtransport_with_options(
.ok(), .ok(),
) )
} }
}
}); });
connect_ref.set_value(Some(Rc::new(move || { connect_ref.set_value(Some(Rc::new({
let transport = transport_ref.get_value(); let transport = Rc::clone(&transport);
let reconnect_timer = Rc::clone(&reconnect_timer);
reconnect_timer_ref.set_value(None); move || {
let transport = transport.borrow();
reconnect_timer.set(None);
if let Some(transport) = transport.as_ref() { if let Some(transport) = transport.as_ref() {
transport.close(); transport.close();
@ -104,20 +113,28 @@ pub fn use_webtransport_with_options(
} }
} }
}); });
}
}))); })));
let open = { let open = {
let reconnect_count = Rc::clone(&reconnect_count);
move || { move || {
reconnect_count_ref.set_value(0); reconnect_count.set(0);
if let Some(connect) = connect_ref.get_value() { if let Some(connect) = connect_ref.get_value() {
connect(); connect();
} }
} }
}; };
let close = move || { let close = {
reconnect_count_ref.set_value(reconnect_limit); let transport = Rc::clone(&transport);
if let Some(transport) = transport_ref.get_value() { let reconnect_count = Rc::clone(&reconnect_count);
move || {
reconnect_count.set(reconnect_limit);
if let Some(transport) = transport.take() {
transport.close(); transport.close();
set_ready_state.set(ConnectionReadyState::Closing); set_ready_state.set(ConnectionReadyState::Closing);
@ -135,33 +152,47 @@ pub fn use_webtransport_with_options(
} }
}); });
} }
}
}; };
let (datagrams_signal, set_datagrams) = create_signal(None::<Vec<u8>>); let (datagrams_signal, set_datagrams) = create_signal(None::<Vec<u8>>);
let datagrams = Signal::derive(move || { let datagrams = Signal::derive({
// lazily create datagrams reader listener let transport = Rc::clone(&transport);
if ready_state.get() == ConnectionReadyState::Open { let datagrams_reader_initialized = Rc::clone(&datagrams_reader_initialized);
initialize_datagrams_reader(
transport_ref, move || {
datagrams_reader_initialized_ref, lazy_initialize_reader(
ready_state,
transport,
datagrams_reader_initialized,
set_datagrams, set_datagrams,
); );
}
datagrams_signal.get() datagrams_signal.get()
}
}); });
let send_datagrams = move |data| { let send_datagrams = {
if let Some(transport) = transport_ref.get_value() { let transport = Rc::clone(&transport);
let writer = get_or_create_datagrams_writer(datagrams_writer_ref, transport); let datagrams_writer = Rc::clone(&datagrams_writer);
move |data| {
if let Some(transport) = transport.borrow().as_ref() {
let writer = get_or_create_datagrams_writer(datagrams_writer, transport);
let _ = writer.write_with_chunk(&data.into()); let _ = writer.write_with_chunk(&data.into());
} }
}
}; };
// TODO : reliable streams // TODO : reliable streams
on_cleanup(move || {
unmounted.set(true);
close();
});
UseWebTransportReturn { UseWebTransportReturn {
ready_state: ready_state.into(), ready_state: ready_state.into(),
datagrams, datagrams,
@ -170,10 +201,10 @@ pub fn use_webtransport_with_options(
} }
fn get_or_create_datagrams_writer( fn get_or_create_datagrams_writer(
datagrams_writer_ref: StoredValue<Option<WritableStreamDefaultWriter>>, datagrams_writer: Rc<RefCell<Option<web_sys::WritableStreamDefaultWriter>>>,
transport: WebTransport, transport: &web_sys::WebTransport,
) -> WritableStreamDefaultWriter { ) -> web_sys::WritableStreamDefaultWriter {
if let Some(writer) = datagrams_writer_ref.get_value() { if let Some(writer) = datagrams_writer.borrow().clone() {
writer writer
} else { } else {
let writer = transport let writer = transport
@ -181,36 +212,39 @@ fn get_or_create_datagrams_writer(
.writable() .writable()
.get_writer() .get_writer()
.expect("should be able to get the writer"); .expect("should be able to get the writer");
datagrams_writer_ref.set_value(Some(writer.clone())); datagrams_writer.replace(Some(writer.clone()));
writer writer
} }
} }
fn initialize_datagrams_reader( fn lazy_initialize_reader(
transport_ref: StoredValue<Option<web_sys::WebTransport>>, ready_state: ReadSignal<ConnectionReadyState>,
datagrams_reader_initialized_ref: StoredValue<bool>, transport: Rc<RefCell<Option<web_sys::WebTransport>>>,
initialized: Rc<Cell<bool>>,
set_datagrams: WriteSignal<Option<Vec<u8>>>, set_datagrams: WriteSignal<Option<Vec<u8>>>,
) { ) {
if !datagrams_reader_initialized_ref.get_value() { if ready_state.get() == ConnectionReadyState::Open {
if let Some(transport) = transport_ref.get_value() { if !initialized.get() {
datagrams_reader_initialized_ref.set_value(true); if let Some(transport) = transport.borrow().as_ref() {
initialized.set(true);
listen_to_stream( listen_to_stream(
transport.datagrams().readable(), transport.datagrams().readable(),
move || datagrams_reader_initialized_ref.set_value(false), move || initialized.set(false),
set_datagrams, set_datagrams,
); );
} }
} }
}
} }
fn listen_to_stream( fn listen_to_stream(
readable_stream: ReadableStream, readable_stream: web_sys::ReadableStream,
on_done: fn(), on_done: fn(),
set_signal: WriteSignal<Option<Vec<u8>>>, set_signal: WriteSignal<Option<Vec<u8>>>,
) { ) {
let mut reader_options = web_sys::ReadableStreamGetReaderOptions::new(); let mut reader_options = web_sys::ReadableStreamGetReaderOptions::new();
reader_options.mode(ReadableStreamReaderMode::Byob); reader_options.mode(web_sys::ReadableStreamReaderMode::Byob);
let reader: web_sys::ReadableStreamByobReader = readable_stream let reader: web_sys::ReadableStreamByobReader = readable_stream
.get_reader_with_options(&reader_options) .get_reader_with_options(&reader_options)
@ -257,14 +291,19 @@ fn listen_to_stream(
pub struct UseWebTransportOptions { pub struct UseWebTransportOptions {
/// Callback when `WebTransport` is ready. /// Callback when `WebTransport` is ready.
on_open: Rc<dyn Fn()>, on_open: Rc<dyn Fn()>,
/// Error callback. /// Error callback.
on_error: Rc<dyn Fn(WebTransportError)>, on_error: Rc<dyn Fn(WebTransportError)>,
/// Callback when `WebTransport` is closed. /// Callback when `WebTransport` is closed.
on_close: Rc<dyn Fn()>, on_close: Rc<dyn Fn()>,
/// Retry times. Defaults to 3. /// Retry times. Defaults to 3.
reconnect_limit: u64, reconnect_limit: u64,
/// Retry interval in ms. Defaults to 3000. /// Retry interval in ms. Defaults to 3000.
reconnect_interval: u64, reconnect_interval: u64,
/// If `true` the `WebSocket` connection will immediately be opened when calling this function. /// If `true` the `WebSocket` connection will immediately be opened when calling this function.
/// If `false` you have to manually call the `open` function. /// If `false` you have to manually call the `open` function.
/// Defaults to `true`. /// Defaults to `true`.