Skip to main content

alloy_transport_ws/
lib.rs

1#![doc = include_str!("../README.md")]
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg",
4    html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico"
5)]
6#![cfg_attr(not(test), warn(unused_crate_dependencies))]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8
9#[macro_use]
10extern crate tracing;
11
12use alloy_pubsub::ConnectionInterface;
13use std::time::Duration;
14
15#[cfg(not(target_family = "wasm"))]
16mod native;
17#[cfg(not(target_family = "wasm"))]
18pub use native::{WebSocketConfig, WsConnect};
19
20#[cfg(target_family = "wasm")]
21mod wasm;
22#[cfg(target_family = "wasm")]
23pub use wasm::WsConnect;
24
25/// The default keepalive interval in seconds.
26const DEFAULT_KEEPALIVE: u64 = 10;
27
28/// An ongoing connection to a backend.
29///
30/// Users should NEVER instantiate a backend directly. Instead, they should use
31/// [`PubSubConnect`] to get a running service with a running backend.
32///
33/// [`PubSubConnect`]: alloy_pubsub::PubSubConnect
34#[derive(Debug)]
35pub struct WsBackend<T> {
36    /// The websocket connection.
37    pub(crate) socket: T,
38
39    /// The interface to the connection.
40    pub(crate) interface: ConnectionInterface,
41
42    /// The keepalive interval for sending pings.
43    pub(crate) keepalive_interval: Duration,
44}
45
46impl<T> WsBackend<T> {
47    /// Create a new [`WsBackend`] from an already-established socket, a [`ConnectionInterface`],
48    /// and a keepalive interval.
49    pub const fn from_socket(
50        socket: T,
51        interface: ConnectionInterface,
52        keepalive_interval: Duration,
53    ) -> Self {
54        Self { socket, interface, keepalive_interval }
55    }
56
57    /// Handle inbound text from the websocket.
58    #[expect(clippy::result_unit_err)]
59    pub fn handle_text(&mut self, text: &str) -> Result<(), ()> {
60        trace!(%text, "received message from websocket");
61
62        match serde_json::from_str(text) {
63            Ok(item) => {
64                trace!(?item, "deserialized message");
65                if let Err(err) = self.interface.send_to_frontend(item) {
66                    error!(item=?err.0, "failed to send deserialized item to handler");
67                    return Err(());
68                }
69            }
70            Err(err) => {
71                error!(%err, "failed to deserialize message");
72                return Err(());
73            }
74        }
75        Ok(())
76    }
77}