mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-02-08 21:33:09 -05:00
ported internal callbacks to Rc RefCells
This commit is contained in:
parent
3cd1728134
commit
b80553751b
1 changed files with 131 additions and 92 deletions
|
@ -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,118 +48,151 @@ 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);
|
||||||
&& ready_state.get_untracked() == ConnectionReadyState::Open
|
let reconnect_count = Rc::clone(&reconnect_count);
|
||||||
{
|
|
||||||
reconnect_timer_ref.set_value(
|
move || {
|
||||||
set_timeout_with_handle(
|
if reconnect_count.get() < reconnect_limit
|
||||||
move || {
|
&& ready_state.get_untracked() == ConnectionReadyState::Open
|
||||||
if let Some(connect) = connect_ref.get_value() {
|
{
|
||||||
connect();
|
reconnect_timer.set(
|
||||||
reconnect_count_ref.update_value(|current| *current += 1);
|
set_timeout_with_handle(
|
||||||
}
|
move || {
|
||||||
},
|
if let Some(connect) = connect_ref.get_value() {
|
||||||
Duration::from_millis(reconnect_interval),
|
connect();
|
||||||
|
reconnect_count.set(reconnect_count.get() + 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Duration::from_millis(reconnect_interval),
|
||||||
|
)
|
||||||
|
.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();
|
||||||
|
|
||||||
if let Some(transport) = transport.as_ref() {
|
reconnect_timer.set(None);
|
||||||
transport.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
let transport =
|
if let Some(transport) = transport.as_ref() {
|
||||||
web_sys::WebTransport::new_with_options(url, &options.into()).unwrap_throw();
|
transport.close();
|
||||||
|
|
||||||
set_ready_state.set(ConnectionReadyState::Connecting);
|
|
||||||
|
|
||||||
spawn_local(async move {
|
|
||||||
match JsFuture::from(transport.ready()).await {
|
|
||||||
Ok(_) => {
|
|
||||||
set_ready_state.set(ConnectionReadyState::Open);
|
|
||||||
on_open();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// TODO : handle error?
|
|
||||||
set_ready_state.set(ConnectionReadyState::Closed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
let transport =
|
||||||
|
web_sys::WebTransport::new_with_options(url, &options.into()).unwrap_throw();
|
||||||
|
|
||||||
|
set_ready_state.set(ConnectionReadyState::Connecting);
|
||||||
|
|
||||||
|
spawn_local(async move {
|
||||||
|
match JsFuture::from(transport.ready()).await {
|
||||||
|
Ok(_) => {
|
||||||
|
set_ready_state.set(ConnectionReadyState::Open);
|
||||||
|
on_open();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// TODO : handle error?
|
||||||
|
set_ready_state.set(ConnectionReadyState::Closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
})));
|
})));
|
||||||
|
|
||||||
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);
|
||||||
transport.close();
|
|
||||||
set_ready_state.set(ConnectionReadyState::Closing);
|
|
||||||
|
|
||||||
spawn_local(async move {
|
move || {
|
||||||
let result = JsFuture::from(transport.closed()).await;
|
reconnect_count.set(reconnect_limit);
|
||||||
set_ready_state.set(ConnectionReadyState::Closed);
|
|
||||||
|
|
||||||
match result {
|
if let Some(transport) = transport.take() {
|
||||||
Ok(_) => {
|
transport.close();
|
||||||
on_close();
|
set_ready_state.set(ConnectionReadyState::Closing);
|
||||||
|
|
||||||
|
spawn_local(async move {
|
||||||
|
let result = JsFuture::from(transport.closed()).await;
|
||||||
|
set_ready_state.set(ConnectionReadyState::Closed);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
on_close();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// TODO : handle error?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
});
|
||||||
// TODO : handle error?
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
let _ = writer.write_with_chunk(&data.into());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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`.
|
||||||
|
|
Loading…
Add table
Reference in a new issue