use crate::{DummyEncoder, ReconnectLimit};
use codee::{CodecError, Encoder, HybridEncoder};
use default_struct_builder::DefaultBuilder;
use leptos::prelude::*;
use std::marker::PhantomData;
use std::sync::Arc;
use thiserror::Error;
use web_sys::{CloseEvent, Event};
type ArcFnBytes = Arc<dyn Fn(&[u8]) + Send + Sync>;
#[derive(DefaultBuilder)]
pub struct UseWebSocketOptions<Rx, E, D, Hb, HbCodec>
where
Rx: ?Sized,
Hb: Default + Send + Sync + 'static,
HbCodec: Encoder<Hb>,
HbCodec: HybridEncoder<
Hb,
<HbCodec as Encoder<Hb>>::Encoded,
Error = <HbCodec as Encoder<Hb>>::Error,
>,
{
#[builder(skip)]
pub(crate) heartbeat: Option<HeartbeatOptions<Hb, HbCodec>>,
pub(crate) on_open: Arc<dyn Fn(Event) + Send + Sync>,
#[builder(skip)]
pub(crate) on_message: Arc<dyn Fn(&Rx) + Send + Sync>,
pub(crate) on_message_raw: Arc<dyn Fn(&str) + Send + Sync>,
pub(crate) on_message_raw_bytes: ArcFnBytes,
#[builder(skip)]
pub(crate) on_error: Arc<dyn Fn(UseWebSocketError<E, D>) + Send + Sync>,
pub(crate) on_close: Arc<dyn Fn(CloseEvent) + Send + Sync>,
pub(crate) reconnect_limit: ReconnectLimit,
pub(crate) reconnect_interval: u64,
pub(crate) immediate: bool,
#[builder(into)]
pub(crate) protocols: Signal<Option<Vec<String>>>,
}
impl<Rx: ?Sized, E, D, Hb, HbCodec> UseWebSocketOptions<Rx, E, D, Hb, HbCodec>
where
Hb: Default + Send + Sync + 'static,
HbCodec: Encoder<Hb>,
HbCodec: HybridEncoder<
Hb,
<HbCodec as Encoder<Hb>>::Encoded,
Error = <HbCodec as Encoder<Hb>>::Error,
>,
{
pub fn on_error<F>(self, handler: F) -> Self
where
F: Fn(UseWebSocketError<E, D>) + Send + Sync + 'static,
{
Self {
on_error: Arc::new(handler),
..self
}
}
pub fn on_message<F>(self, handler: F) -> Self
where
F: Fn(&Rx) + Send + Sync + 'static,
{
Self {
on_message: Arc::new(handler),
..self
}
}
pub fn heartbeat<NewHb, NewHbCodec>(
self,
interval: u64,
) -> UseWebSocketOptions<Rx, E, D, NewHb, NewHbCodec>
where
NewHb: Default + Send + Sync + 'static,
NewHbCodec: Encoder<NewHb>,
NewHbCodec: HybridEncoder<
NewHb,
<NewHbCodec as Encoder<NewHb>>::Encoded,
Error = <NewHbCodec as Encoder<NewHb>>::Error,
>,
{
UseWebSocketOptions {
heartbeat: Some(HeartbeatOptions {
data: PhantomData::<NewHb>,
interval,
codec: PhantomData::<NewHbCodec>,
}),
on_open: self.on_open,
on_message: self.on_message,
on_message_raw: self.on_message_raw,
on_message_raw_bytes: self.on_message_raw_bytes,
on_close: self.on_close,
on_error: self.on_error,
reconnect_limit: self.reconnect_limit,
reconnect_interval: self.reconnect_interval,
immediate: self.immediate,
protocols: self.protocols,
}
}
}
impl<Rx: ?Sized, E, D> Default for UseWebSocketOptions<Rx, E, D, (), DummyEncoder> {
fn default() -> Self {
Self {
heartbeat: None,
on_open: Arc::new(|_| {}),
on_message: Arc::new(|_| {}),
on_message_raw: Arc::new(|_| {}),
on_message_raw_bytes: Arc::new(|_| {}),
on_error: Arc::new(|_| {}),
on_close: Arc::new(|_| {}),
reconnect_limit: ReconnectLimit::default(),
reconnect_interval: 3000,
immediate: true,
protocols: Default::default(),
}
}
}
#[cfg_attr(feature = "ssr", allow(dead_code))]
pub struct HeartbeatOptions<Hb, HbCodec>
where
Hb: Default + Send + Sync + 'static,
HbCodec: Encoder<Hb>,
HbCodec: HybridEncoder<
Hb,
<HbCodec as Encoder<Hb>>::Encoded,
Error = <HbCodec as Encoder<Hb>>::Error,
>,
{
data: PhantomData<Hb>,
pub(crate) interval: u64,
codec: PhantomData<HbCodec>,
}
impl<Hb, HbCodec> Clone for HeartbeatOptions<Hb, HbCodec>
where
Hb: Default + Send + Sync + 'static,
HbCodec: Encoder<Hb>,
HbCodec: HybridEncoder<
Hb,
<HbCodec as Encoder<Hb>>::Encoded,
Error = <HbCodec as Encoder<Hb>>::Error,
>,
{
fn clone(&self) -> Self {
*self
}
}
impl<Hb, HbCodec> Copy for HeartbeatOptions<Hb, HbCodec>
where
Hb: Default + Send + Sync + 'static,
HbCodec: Encoder<Hb>,
HbCodec: HybridEncoder<
Hb,
<HbCodec as Encoder<Hb>>::Encoded,
Error = <HbCodec as Encoder<Hb>>::Error,
>,
{
}
#[derive(Error, Debug)]
pub enum UseWebSocketError<E, D> {
#[error("WebSocket error event")]
Event(Event),
#[error("WebSocket codec error: {0}")]
Codec(#[from] CodecError<E, D>),
#[error("WebSocket heartbeat codec error: {0}")]
HeartbeatCodec(String),
}