lightstreamer_rs/
lib.rs

1//! # Lightstreamer Rust Client
2//!
3//! This project is a Rust implementation of the Lightstreamer TLCP (Text-based Live Connections Protocol). It provides a robust client SDK to interact with Lightstreamer servers, enabling real-time data streaming for financial applications, IoT systems, and other use cases requiring live data updates. While it was initially developed to support the [ig_trading_api](https://github.com/joaquinbejar/ig_trading_api) project, it has evolved into a more comprehensive SDK with broader applicability.
4//!
5//! ## About Lightstreamer
6//!
7//! Lightstreamer is a high-performance real-time messaging server that provides several key features:
8//! - Real-time data streaming with optimized bandwidth usage
9//! - Support for various transport mechanisms (WebSockets, HTTP streaming, etc.)
10//! - Different subscription modes for various data delivery patterns
11//! - Robust connection management with automatic recovery
12//! - Scalable architecture for high-volume applications
13//!
14//! ## Features
15//!
16//! This Rust client SDK provides the following capabilities:
17//!
18//! - **Connection Management**:
19//!   - Full-duplex WebSocket-based connection mode
20//!   - Automatic reconnection with configurable retry policies
21//!   - Session recovery after temporary disconnections
22//!   - Connection status monitoring and event notifications
23//!   - Proxy support for enterprise environments
24//!
25//! - **Subscription Capabilities**:
26//!   - Support for multiple subscription modes (MERGE, DISTINCT, COMMAND, RAW)
27//!   - Subscription to individual items or item groups
28//!   - Field schema definition for structured data
29//!   - Real-time item updates with change detection
30//!   - Snapshot support for initial state recovery
31//!
32//! - **Configuration Options**:
33//!   - Extensive connection options (polling intervals, timeouts, etc.)
34//!   - Bandwidth control and throttling
35//!   - Custom HTTP headers for authentication
36//!   - Logging configuration for debugging
37//!
38//! - **Event Handling**:
39//!   - Comprehensive event listener system
40//!   - Subscription lifecycle events (subscription, unsubscription)
41//!   - Item update notifications with field-level change detection
42//!   - Connection status change notifications
43//!   - Error handling and reporting
44//!
45//! ## Implementation Status
46//!
47//! The current implementation supports most core features of the Lightstreamer protocol, with a focus on the WebSocket transport mechanism and the MERGE subscription mode. While initially developed for specific trading API requirements, the library has expanded to include:
48//!
49//! - All subscription modes (MERGE, DISTINCT, COMMAND, RAW)
50//! - Robust error handling and recovery mechanisms
51//! - Comprehensive configuration options
52//! - Thread-safe asynchronous operation using Tokio
53//!
54//! Some advanced features that may be implemented in future versions include:
55//!
56//! - Message sending capabilities (MPN)
57//! - Client-side filtering and frequency limitations
58//! - Additional transport mechanisms beyond WebSockets
59//! - Enhanced security features
60//!
61//! ## Installation
62//!
63//! To use this SDK in your Rust project, add the following dependency to your `Cargo.toml`:
64//!
65//! ```toml
66//! [dependencies]
67//! lightstreamer-rs = "0.1.4"
68//! ```
69//!
70//! ## Usage
71//!
72//! ### Quick Start (Simplified API)
73//!
74//! For most use cases, use the simplified `SimpleClient` API:
75//!
76//! ```ignore
77//! use lightstreamer_rs::client::{ClientConfig, SimpleClient, SubscriptionParams};
78//! use lightstreamer_rs::subscription::SubscriptionMode;
79//!
80//! #[tokio::main]
81//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
82//!     // 1. Create configuration
83//!     let config = ClientConfig::new("http://push.lightstreamer.com/lightstreamer")
84//!         .adapter_set("DEMO");
85//!
86//!     // 2. Create client
87//!     let client = SimpleClient::new(config)?;
88//!
89//!     // 3. Subscribe and get channel receiver
90//!     let params = SubscriptionParams::new(
91//!         SubscriptionMode::Merge,
92//!         vec!["item1".to_string(), "item2".to_string()],
93//!         vec!["last_price".to_string(), "time".to_string()],
94//!     ).data_adapter("QUOTE_ADAPTER");
95//!
96//!     let mut receiver = client.subscribe(params).await?;
97//!
98//!     // 4. Process updates asynchronously
99//!     tokio::spawn(async move {
100//!         while let Some(update) = receiver.recv().await {
101//!             println!("Price: {:?}", update.get_value("last_price"));
102//!         }
103//!     });
104//!
105//!     // 5. Connect and run
106//!     client.connect().await?;
107//!     
108//!     Ok(())
109//! }
110//! ```
111//!
112//! ### Advanced Usage (Full API)
113//!
114//! Here's a comprehensive example of how to use the Lightstreamer Rust Client SDK:
115//!
116//! ```ignore
117//! // This example shows how to use the Lightstreamer Rust client
118//! use lightstreamer_rs::client::{LightstreamerClient, Transport};
119//! use lightstreamer_rs::subscription::{Subscription, SubscriptionMode, SubscriptionListener, ItemUpdate};
120//! use std::sync::Arc;
121//! use tokio::sync::Notify;
122//! use std::time::Duration;
123//!
124//! // Define a custom subscription listener
125//! struct MySubscriptionListener;
126//!
127//! impl SubscriptionListener for MySubscriptionListener {
128//!     fn on_subscription(&self) {
129//!         info!("Subscription confirmed by the server");
130//!     }
131//!     
132//!     fn on_item_update(&self, update: ItemUpdate) {
133//!         info!("Received update for item: {}", update.get_item_name());
134//!         for field in update.get_fields() {
135//!             if let Some(value) = update.get_value(field) {
136//!                 info!("  {} = {}", field, value);
137//!             }
138//!         }
139//!     }
140//! }
141//!
142//! async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
143//!     // Create a new LightstreamerClient instance
144//!     let result = LightstreamerClient::new(
145//!         Some("ws://your-lightstreamer-server.com"),  // Server address
146//!         Some("YOUR_ADAPTER_SET"),                   // Adapter set
147//!         None,                                       // User (optional)
148//!         None,                                       // Password (optional)
149//!     );
150//!     
151//!     let mut client = match result {
152//!         Ok(client) => client,
153//!         Err(e) => return Err(e),
154//!     };
155//!     
156//!     // Configure the connection details if needed
157//!     client.connection_details.set_user("YOUR_USERNAME");
158//!     client.connection_details.set_password("YOUR_PASSWORD");
159//!     
160//!     // Configure connection options if needed
161//!     client.connection_options.set_content_length(50000000);
162//!     client.connection_options.set_keepalive_interval(5);
163//!     client.connection_options.set_forced_transport(Some(Transport::WsStreaming));
164//!     
165//!     // Create a shutdown signal for graceful termination
166//!     let shutdown_signal = Arc::new(Notify::new());
167//!     
168//!     // Connect to the Lightstreamer server
169//!     if let Err(e) = client.connect(shutdown_signal.clone()).await {
170//!         return Err(e);
171//!     }
172//!     
173//!     // Create a subscription
174//!     let subscription_result = Subscription::new(
175//!         SubscriptionMode::Merge,
176//!         Some(vec!["item1".to_string(), "item2".to_string()]),
177//!         Some(vec!["field1".to_string(), "field2".to_string()]),
178//!     );
179//!     
180//!     let subscription = match subscription_result {
181//!         Ok(sub) => sub,
182//!         Err(e) => return Err(e),
183//!     };
184//!     
185//!     // Add a listener to the subscription (optional)
186//!     let listener = Box::new(MySubscriptionListener);
187//!     subscription.add_listener(listener);
188//!     
189//!     // Get the subscription sender from the client
190//!     // Note: This method might not exist in the current API, check the documentation
191//!     let subscription_sender = client.get_subscriptions()[0].clone();
192//!     
193//!     // Subscribe and get the subscription ID
194//!     let subscription_id_result = LightstreamerClient::subscribe_get_id(
195//!         subscription_sender.clone(),
196//!         subscription
197//!     ).await;
198//!     
199//!     let subscription_id = match subscription_id_result {
200//!         Ok(id) => id,
201//!         Err(e) => return Err(e),
202//!     };
203//!     
204//!     info!("Subscribed with ID: {}", subscription_id);
205//!     
206//!     // Wait for some time (in a real application, you would wait for a shutdown signal)
207//!     tokio::time::sleep(Duration::from_secs(5)).await;
208//!     
209//!     // Unsubscribe before disconnecting
210//!     LightstreamerClient::unsubscribe(subscription_sender, subscription_id).await;
211//!     
212//!     Ok(())
213//! }
214//! ```
215//!
216//! ### Handling Client Events
217//!
218//! You can also add listeners to handle client events:
219//!
220//! Here's an example of implementing a client listener:
221//!
222//! ```ignore
223//! // Note: ClientListener is a private trait, this is just for illustration
224//! use lightstreamer_rs::client::model::ClientStatus;
225//!
226//! struct MyClientListener;
227//!
228//! // This is just an example of what the ClientListener trait might look like
229//! // The actual implementation is internal to the library
230//! trait ClientListener {
231//!     fn on_status_change(&self, status: &ClientStatus);
232//!     fn on_server_error(&self, error_code: i32, error_message: &str);
233//!     fn on_property_change(&self, property: &str);
234//! }
235//!
236//! impl ClientListener for MyClientListener {
237//!     fn on_status_change(&self, status: &ClientStatus) {
238//!         info!("Client status changed to: {:?}", status);
239//!     }
240//!     
241//!     fn on_server_error(&self, error_code: i32, error_message: &str) {
242//!         info!("Server error: {} - {}", error_code, error_message);
243//!     }
244//!     
245//!     fn on_property_change(&self, property: &str) {
246//!         info!("Property changed: {}", property);
247//!     }
248//! }
249//!
250//! // Then add the listener to your client
251//! // client.add_listener(Box::new(MyClientListener));
252//! ```
253//!
254//! ### Channel-Based Update Processing
255//!
256//! For asynchronous processing of updates in separate tasks, you can use the `ChannelSubscriptionListener`:
257//!
258//! ```ignore
259//! use lightstreamer_rs::subscription::ChannelSubscriptionListener;
260//!
261//! // Create a channel-based listener
262//! let (listener, mut update_receiver) = ChannelSubscriptionListener::create_channel();
263//!
264//! // Add the listener to your subscription
265//! subscription.add_listener(Box::new(listener));
266//!
267//! // Process updates asynchronously in a separate task
268//! tokio::spawn(async move {
269//!     while let Some(update) = update_receiver.recv().await {
270//!         // Process the update
271//!         println!("Item: {:?}", update.get_item_name());
272//!         println!("Fields: {:?}", update.get_fields());
273//!         
274//!         // Perform any async operations
275//!         // e.g., save to database, send to another service, etc.
276//!     }
277//! });
278//! ```
279//!
280//! This approach allows you to:
281//! - Decouple update reception from processing
282//! - Process updates asynchronously without blocking the Lightstreamer event loop
283//! - Easily integrate with other async workflows
284//! - Handle backpressure naturally through channel buffering
285//!
286
287/// Module containing subscription-related functionality.
288///
289/// This module provides the necessary types and functions to create and manage subscriptions
290/// to Lightstreamer items. It includes the `Subscription` struct, subscription modes,
291/// item updates, and subscription listeners.
292pub mod subscription;
293
294/// Module containing utility functions and error types.
295///
296/// This module provides common utilities and error types used throughout the library,
297/// including exception types for handling illegal arguments and states.
298pub mod utils;
299
300/// Module containing client-related functionality.
301///
302/// This module provides the main `LightstreamerClient` type and related components for
303/// connecting to Lightstreamer servers, managing sessions, and handling client events.
304pub mod client;
305
306/// Module containing connection-related functionality.
307///
308/// This module provides types for managing connection details and options.
309pub mod connection;