#![doc = document_features::document_features!()]
#![warn(missing_docs)]
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "tokio"))]
mod native_tungstenite;
use std::ops::ControlFlow;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "tokio"))]
pub use native_tungstenite::*;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "tokio")]
mod native_tungstenite_tokio;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "tokio")]
pub use native_tungstenite_tokio::*;
#[cfg(not(target_arch = "wasm32"))]
mod tungstenite_common;
#[cfg(target_arch = "wasm32")]
mod web;
#[cfg(target_arch = "wasm32")]
pub use web::*;
#[derive(Clone, Debug)]
pub enum WsMessage {
Binary(Vec<u8>),
Text(String),
Unknown(String),
Ping(Vec<u8>),
Pong(Vec<u8>),
}
#[derive(Clone, Debug)]
pub enum WsEvent {
Opened,
Message(WsMessage),
Error(String),
Closed,
}
pub struct WsReceiver {
rx: std::sync::mpsc::Receiver<WsEvent>,
}
impl WsReceiver {
pub fn new() -> (Self, EventHandler) {
Self::new_with_callback(|| {})
}
pub fn new_with_callback(wake_up: impl Fn() + Send + Sync + 'static) -> (Self, EventHandler) {
let (tx, rx) = std::sync::mpsc::channel();
let on_event = Box::new(move |event| {
wake_up(); if tx.send(event).is_ok() {
ControlFlow::Continue(())
} else {
ControlFlow::Break(())
}
});
let ws_receiver = Self { rx };
(ws_receiver, on_event)
}
pub fn try_recv(&self) -> Option<WsEvent> {
self.rx.try_recv().ok()
}
}
pub type Error = String;
pub type Result<T> = std::result::Result<T, Error>;
pub(crate) type EventHandler = Box<dyn Send + Fn(WsEvent) -> ControlFlow<()>>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Options {
pub max_incoming_frame_size: usize,
pub additional_headers: Vec<(String, String)>,
pub subprotocols: Vec<String>,
pub read_timeout: Option<std::time::Duration>,
}
impl Default for Options {
fn default() -> Self {
Self {
max_incoming_frame_size: 64 * 1024 * 1024,
additional_headers: vec![],
subprotocols: vec![],
read_timeout: Some(std::time::Duration::from_millis(10)),
}
}
}
pub fn connect(url: impl Into<String>, options: Options) -> Result<(WsSender, WsReceiver)> {
let (ws_receiver, on_event) = WsReceiver::new();
let ws_sender = ws_connect(url.into(), options, on_event)?;
Ok((ws_sender, ws_receiver))
}
pub fn connect_with_wakeup(
url: impl Into<String>,
options: Options,
wake_up: impl Fn() + Send + Sync + 'static,
) -> Result<(WsSender, WsReceiver)> {
let (receiver, on_event) = WsReceiver::new_with_callback(wake_up);
let sender = ws_connect(url.into(), options, on_event)?;
Ok((sender, receiver))
}
pub fn ws_connect(url: String, options: Options, on_event: EventHandler) -> Result<WsSender> {
ws_connect_impl(url, options, on_event)
}
pub fn ws_receive(url: String, options: Options, on_event: EventHandler) -> Result<()> {
ws_receive_impl(url, options, on_event)
}