1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
//! # Silver9 WebSocket
//!
//! A simplified high-performance low-latency Rust WebSocket client library providing three distinct
//! implementations: async/threaded with channels, non-blocking with callbacks, and blocking with callbacks.
//!
//! ## Features
//!
//! - **Low latency** - Built as a thin layer over [tungstenite-rs](https://docs.rs/tungstenite/latest/tungstenite)
//! - **Multiple client types** - Choose between async channels, non-blocking callbacks, or blocking callbacks
//! - **TLS support** - Built-in support for secure WebSocket connections via `native-tls`
//! - **Event-driven** - Handler callbacks or channel-based event delivery
//! - **Type-safe API** - Leverage Rust's type system for correctness
//! - **Built-in tracing** - Comprehensive logging support via the `tracing` crate
//!
//! ## Client Types
//!
//! This library provides three WebSocket client implementations:
//!
//! ### 1. [`S9NonBlockingWebSocketClient`]
//!
//! Pure non-blocking client with zero-overhead handler callbacks. Best for lowest possible
//! latency with direct control.
//!
//! **Key characteristics:**
//! - Runs on caller's thread
//! - Non-blocking socket I/O
//! - Zero-copy message delivery via callbacks
//! - Direct method calls from handler
//! - Lowest latency
//!
//! ### 2. [`S9BlockingWebSocketClient`]
//!
//! Synchronous blocking client with handler callbacks. Best for simple applications where
//! blocking is acceptable.
//!
//! **Key characteristics:**
//! - Runs on caller's thread
//! - Blocking socket I/O (with optional timeouts)
//! - Zero-copy message delivery via callbacks
//! - Direct method calls from handler
//! - Simple synchronous model
//!
//! ### 3. [`S9AsyncNonBlockingWebSocketClient`]
//!
//! Spawns a background thread and communicates via channels. Best for applications that need
//! async event processing with channels.
//!
//! **Key characteristics:**
//! - Spawns dedicated background thread
//! - Non-blocking socket I/O
//! - Event delivery via [`Receiver<WebSocketEvent>`](crossbeam_channel::Receiver)
//! - Control via [`Sender<ControlMessage>`](crossbeam_channel::Sender)
//! - Thread-safe
//!
//! ## Quick Start
//!
//! ### Non-blocking Client (with handler callbacks)
//!
//! ```no_run
//! use s9_websocket::{S9NonBlockingWebSocketClient, S9WebSocketClientHandler, NonBlockingOptions};
//! use std::time::Duration;
//!
//! struct MyHandler;
//!
//! impl S9WebSocketClientHandler<S9NonBlockingWebSocketClient> for MyHandler {
//! // Only implement the methods you care about
//! fn on_text_message(&mut self, client: &mut S9NonBlockingWebSocketClient, data: &[u8]) {
//! println!("Received: {}", String::from_utf8_lossy(data));
//! client.close();
//! }
//!
//! fn on_connection_closed(&mut self, _client: &mut S9NonBlockingWebSocketClient, reason: Option<String>) {
//! println!("Connection closed: {:?}", reason);
//! }
//!
//! fn on_error(&mut self, _client: &mut S9NonBlockingWebSocketClient, error: String) {
//! eprintln!("Error: {}", error);
//! }
//! }
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let options = NonBlockingOptions::new()
//! .spin_wait_duration(Some(Duration::from_millis(10)))?;
//!
//! let mut client = S9NonBlockingWebSocketClient::connect("wss://echo.websocket.org", options)?;
//! client.send_text_message("Hello!")?;
//!
//! let mut handler = MyHandler;
//! client.run(&mut handler);
//! # Ok(())
//! # }
//! ```
//!
//! ### Blocking Client
//!
//! ```no_run
//! use s9_websocket::{S9BlockingWebSocketClient, S9WebSocketClientHandler, BlockingOptions};
//!
//! struct MyHandler;
//!
//! impl S9WebSocketClientHandler<S9BlockingWebSocketClient> for MyHandler {
//! // Only implement the methods you care about
//! fn on_text_message(&mut self, client: &mut S9BlockingWebSocketClient, data: &[u8]) {
//! println!("Received: {}", String::from_utf8_lossy(data));
//! client.close();
//! }
//!
//! fn on_connection_closed(&mut self, _client: &mut S9BlockingWebSocketClient, reason: Option<String>) {
//! println!("Connection closed: {:?}", reason);
//! }
//!
//! fn on_error(&mut self, _client: &mut S9BlockingWebSocketClient, error: String) {
//! eprintln!("Error: {}", error);
//! }
//! }
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let options = BlockingOptions::new();
//! let mut client = S9BlockingWebSocketClient::connect("wss://echo.websocket.org", options)?;
//! client.send_text_message("Hello!")?;
//!
//! let mut handler = MyHandler;
//! client.run(&mut handler);
//! # Ok(())
//! # }
//! ```
//!
//! ### Async Non-blocking Client (with channels)
//!
//! ```no_run
//! use s9_websocket::{S9AsyncNonBlockingWebSocketClient, WebSocketEvent, ControlMessage, NonBlockingOptions};
//! use std::time::Duration;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Configure with 10ms sleep between reads
//! let options = NonBlockingOptions::new()
//! .spin_wait_duration(Some(Duration::from_millis(10)))?;
//!
//! // Connect to WebSocket server
//! let mut client = S9AsyncNonBlockingWebSocketClient::connect(
//! "wss://echo.websocket.org",
//! options
//! )?;
//!
//! // Start the event loop (spawns thread)
//! let _handle = client.run()?;
//!
//! // Send a message via control channel
//! client.control_tx.send(ControlMessage::SendText("Hello!".to_string()))?;
//!
//! // Handle events from channel
//! loop {
//! match client.event_rx.recv() {
//! Ok(WebSocketEvent::TextMessage(data)) => {
//! println!("Received: {}", String::from_utf8_lossy(&data));
//! client.control_tx.send(ControlMessage::Close())?;
//! },
//! Ok(WebSocketEvent::Quit) => break,
//! _ => {}
//! }
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## Accessing the Underlying Socket
//!
//! All clients provide access to the underlying tungstenite WebSocket for advanced use cases:
//!
//! ```no_run
//! # use s9_websocket::{S9NonBlockingWebSocketClient, NonBlockingOptions};
//! # let options = NonBlockingOptions::new();
//! # let mut client = S9NonBlockingWebSocketClient::connect("wss://echo.websocket.org", options)?;
//! // Get immutable reference to the socket
//! let socket = client.get_socket();
//!
//! // Get mutable reference to the socket
//! let socket_mut = client.get_socket_mut();
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Note for S9AsyncNonBlockingWebSocketClient**: Socket access returns `Option<&WebSocket>`
//! because the socket is moved to a background thread after calling `run()`.
//!
//! ## Performance Tips
//!
//! 1. **Tune spin wait duration**: Balance CPU usage vs latency
//! - `None`: Maximum performance, high CPU usage
//! - `Some(Duration::from_millis(1-10))`: Good balance
//! - `Some(Duration::from_millis(50-100))`: Lower CPU, higher latency
//!
//! 2. **Enable TCP_NODELAY**: Reduce latency for small messages
//! ```no_run
//! # use s9_websocket::NonBlockingOptions;
//! let options = NonBlockingOptions::new().nodelay(true);
//! ```
//!
//! ## Scalability
//!
//! **Important:** This library does not scale to thousands of connections. Each client requires
//! one OS thread (either spawned or caller's thread). For applications requiring 1000+ concurrent
//! connections, consider async libraries like `tokio-tungstenite` or `async-tungstenite`.
//!
//! ## Error Handling
//!
//! All fallible operations return [`S9Result<T>`], which is an alias for `Result<T, S9WebSocketError>`.
//! See [`S9WebSocketError`] for detailed error types.
//!
//! - **non-blocking**: A `WebSocketEvent::Quit` event is published after any error during reading messages from underlying WebSocket
//! - **blocking**: The `S9WebSocketClientHandler::on_quit()` callback is called after any error during reading messages from underlying WebSocket
//!
//! ## Logging
//!
//! The library uses the `tracing` crate. Enable logging in your application:
//!
//! ### Log levels:
//! - **TRACE**: Detailed message content and connection details
//! - **DEBUG**: Connection lifecycle events
//! - **ERROR**: Error conditions
//!
//! ```no_run
//! tracing_subscriber::fmt()
//! .with_max_level(tracing::Level::INFO)
//! .init();
//! ```
//!
//! For more examples and detailed documentation, see the [README on GitHub](https://github.com/AlexSilver9/s9_websocket).
pub use *;
pub use ;