aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Daniel López Azaña <daniloaz@gmail.com>2024-03-28 19:19:46 +0100
committerLibravatar Daniel López Azaña <daniloaz@gmail.com>2024-03-28 19:19:46 +0100
commite1c0e90581b7ce97f87ddf43267ceb32e28447e3 (patch)
treea347bfed5552256fcbe5d54798814a1a1d24cf0a
parentb4e12fd1165b5e3960a1294dadec45eb40893b37 (diff)
✨ (client_listener.rs): Implement Debug trait for ClientListener for better logging
♻️ (connection_details.rs): Refactor ConnectionDetails to use Option for optional fields ♻️ (connection_details.rs): Change new constructor to accept &str and convert to String ✨ (connection_details.rs): Implement Debug trait for ConnectionDetails ♻️ (connection_options.rs): Implement Debug trait for ConnectionOptions ♻️ (lightstreamer_client.rs): Refactor LightstreamerClient to use Option for server_address and adapter_set ✨ (lightstreamer_client.rs): Implement Debug trait for LightstreamerClient ♻️ (main.rs): Update subscribe_to_channel function to use new control.txt URL and parameters ♻️ (main.rs): Update main function to use Option<&str> when creating LightstreamerClient ✨ (proxy.rs): Add Proxy struct and ProxyType enum to handle proxy configurations
-rw-r--r--src/client_listener.rs4
-rw-r--r--src/connection_details.rs42
-rw-r--r--src/connection_options.rs27
-rw-r--r--src/lightstreamer_client.rs66
-rw-r--r--src/main.rs30
-rw-r--r--src/proxy.rs80
6 files changed, 220 insertions, 29 deletions
diff --git a/src/client_listener.rs b/src/client_listener.rs
index 06902aa..9d3d6d5 100644
--- a/src/client_listener.rs
+++ b/src/client_listener.rs
@@ -1,3 +1,5 @@
+use std::fmt::Debug;
+
/// Interface to be implemented to listen to `LightstreamerClient` events comprehending notifications
/// of connection activity and errors.
///
@@ -6,7 +8,7 @@
/// has changed. On the other hand, all the notifications for a single `LightstreamerClient`,
/// including notifications to `ClientListener`, `SubscriptionListener` and `ClientMessageListener`
/// will be dispatched by the same thread.
-pub trait ClientListener {
+pub trait ClientListener: Debug {
/// Event handler that receives a notification when the `ClientListener` instance is removed
/// from a `LightstreamerClient` through `LightstreamerClient.removeListener()`. This is the
/// last event to be fired on the listener.
diff --git a/src/connection_details.rs b/src/connection_details.rs
index 1d18bf6..06b6d15 100644
--- a/src/connection_details.rs
+++ b/src/connection_details.rs
@@ -1,6 +1,10 @@
+use hyper::server;
+
use crate::client_listener::ClientListener;
use crate::IllegalArgumentException;
+use std::fmt::{self, Debug, Formatter};
+
/// Used by `LightstreamerClient` to provide a basic connection properties data object.
///
/// Data object that contains the configuration settings needed to connect to a Lightstreamer Server.
@@ -9,9 +13,9 @@ use crate::IllegalArgumentException;
///
/// See also `LightstreamerClient`
pub struct ConnectionDetails {
- adapter_set: String,
+ adapter_set: Option<String>,
client_ip: Option<String>,
- server_address: String,
+ server_address: Option<String>,
server_instance_address: Option<String>,
server_socket_name: Option<String>,
session_id: Option<String>,
@@ -31,7 +35,7 @@ impl ConnectionDetails {
/// that the "DEFAULT" Adapter Set is used.
///
/// See also `setAdapterSet()`
- pub fn get_adapter_set(&self) -> &String {
+ pub fn get_adapter_set(&self) -> Option<&String> {
self.adapter_set.as_ref()
}
@@ -152,18 +156,11 @@ impl ConnectionDetails {
}
/// Creates a new ConnectionDetails object with default values.
- pub fn new(server_address: Option<String>, adapter_set: Option<String>) -> ConnectionDetails {
- if let Some(server_address) = server_address {
- ConnectionDetails {
- server_address: Some(server_address),
- adapter_set,
- ..Default::default()
- }
- } else {
- ConnectionDetails {
- adapter_set,
- ..Default::default()
- }
+ pub fn new(server_address: Option<&str>, adapter_set: Option<&str>) -> ConnectionDetails {
+ ConnectionDetails {
+ server_address: server_address.map(|s| s.to_string()), // convert &str to String
+ adapter_set: adapter_set.map(|s| s.to_string()), // convert &str to String
+ ..Default::default()
}
}
@@ -346,6 +343,21 @@ impl ConnectionDetails {
}
}
+impl Debug for ConnectionDetails {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ConnectionDetails")
+ .field("adapter_set", &self.adapter_set)
+ .field("client_ip", &self.client_ip)
+ .field("server_address", &self.server_address)
+ .field("server_instance_address", &self.server_instance_address)
+ .field("server_socket_name", &self.server_socket_name)
+ .field("session_id", &self.session_id)
+ .field("user", &self.user)
+ .field("password", &self.password)
+ .finish()
+ }
+}
+
impl Default for ConnectionDetails {
fn default() -> Self {
ConnectionDetails {
diff --git a/src/connection_options.rs b/src/connection_options.rs
index aefb0c0..cbe45b5 100644
--- a/src/connection_options.rs
+++ b/src/connection_options.rs
@@ -1,5 +1,7 @@
use crate::proxy::Proxy;
+use std::fmt::{self, Debug, Formatter};
+
/// Used by LightstreamerClient to provide an extra connection properties data object.
/// Data struct that contains the policy settings used to connect to a Lightstreamer Server.
/// An instance of this struct is attached to every LightstreamerClient as connection_options.
@@ -121,6 +123,31 @@ impl ConnectionOptions {
}
}
+impl Debug for ConnectionOptions {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ConnectionOptions")
+ .field("content_length", &self.content_length)
+ .field("first_retry_max_delay", &self.first_retry_max_delay)
+ .field("forced_transport", &self.forced_transport)
+ .field("http_extra_headers", &self.http_extra_headers)
+ .field("http_extra_headers_on_session_creation_only", &self.http_extra_headers_on_session_creation_only)
+ .field("idle_timeout", &self.idle_timeout)
+ .field("keepalive_interval", &self.keepalive_interval)
+ .field("polling_interval", &self.polling_interval)
+ .field("proxy", &self.proxy)
+ .field("real_max_bandwidth", &self.real_max_bandwidth)
+ .field("reconnect_timeout", &self.reconnect_timeout)
+ .field("requested_max_bandwidth", &self.requested_max_bandwidth)
+ .field("retry_delay", &self.retry_delay)
+ .field("reverse_heartbeat_interval", &self.reverse_heartbeat_interval)
+ .field("server_instance_address_ignored", &self.server_instance_address_ignored)
+ .field("session_recovery_timeout", &self.session_recovery_timeout)
+ .field("slowing_enabled", &self.slowing_enabled)
+ .field("stalled_timeout", &self.stalled_timeout)
+ .finish()
+ }
+}
+
impl Default for ConnectionOptions {
fn default() -> Self {
ConnectionOptions {
diff --git a/src/lightstreamer_client.rs b/src/lightstreamer_client.rs
index f91e843..214a722 100644
--- a/src/lightstreamer_client.rs
+++ b/src/lightstreamer_client.rs
@@ -6,6 +6,7 @@ use crate::subscription::Subscription;
use crate::IllegalStateException;
use cookie::Cookie;
+use std::fmt::{self, Debug, Formatter};
/// Facade class for the management of the communication to Lightstreamer Server. Used to provide
/// configuration settings, event handlers, operations for the control of the connection lifecycle,
@@ -45,8 +46,8 @@ use cookie::Cookie;
/// * `IllegalArgumentException`: if a not valid address is passed. See `ConnectionDetails.setServerAddress()`
/// for details.
pub struct LightstreamerClient {
- server_address: String,
- adapter_set: String,
+ server_address: Option<String>,
+ adapter_set: Option<String>,
/// Data object that contains the details needed to open a connection to a Lightstreamer Server.
/// This instance is set up by the `LightstreamerClient` object at its own creation. Properties
/// of this object can be overwritten by values received from a Lightstreamer Server.
@@ -59,6 +60,19 @@ pub struct LightstreamerClient {
subscriptions: Vec<Subscription>,
}
+impl Debug for LightstreamerClient {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.debug_struct("LightstreamerClient")
+ .field("server_address", &self.server_address)
+ .field("adapter_set", &self.adapter_set)
+ .field("connection_details", &self.connection_details)
+ .field("connection_options", &self.connection_options)
+ .field("listeners", &self.listeners)
+ .field("subscriptions", &self.subscriptions)
+ .finish()
+ }
+}
+
impl LightstreamerClient {
/// A constant string representing the name of the library.
pub const LIB_NAME: &'static str = "rust_client";
@@ -232,13 +246,49 @@ impl LightstreamerClient {
&self.subscriptions
}
- pub fn new (server_address: &str, adapter_set: &str) -> Result<LightstreamerClient, IllegalStateException> {
- let connection_details = ConnectionDetails::new(
- server_address.to_string(),
- adapter_set.to_string(),
- );
+ /// Creates a new instance of `LightstreamerClient`.
+ ///
+ /// The constructor initializes the client with the server address and adapter set, if provided.
+ /// It sets up the connection details and options for the client. If no server address or
+ /// adapter set is specified, those properties on the client will be `None`. This allows
+ /// for late configuration of these details before connecting to the Lightstreamer server.
+ ///
+ /// # Arguments
+ /// * `server_address` - An optional reference to a string slice that represents the server
+ /// address to connect to. If `None`, the server address must be set later.
+ /// * `adapter_set` - An optional reference to a string slice that specifies the adapter set name.
+ /// If `None`, the adapter set must be set later.
+ ///
+ /// # Returns
+ /// A result containing the new `LightstreamerClient` instance if successful, or an
+ /// `IllegalStateException` if the initialization fails due to invalid state conditions.
+ ///
+ /// # Panics
+ /// Does not panic under normal circumstances. However, unexpected internal errors during
+ /// the creation of internal components could cause panics, which should be considered when
+ /// using this function in production code.
+ ///
+ /// # Example
+ /// ```
+ /// // Example usage of `new` to create a LightstreamerClient with specified server address and
+ /// // adapter set.
+ /// let server_address = Some("http://myserver.com");
+ /// let adapter_set = Some("MY_ADAPTER_SET");
+ /// let ls_client = LightstreamerClient::new(server_address, adapter_set);
+ ///
+ /// assert!(ls_client.is_ok());
+ /// if let Ok(client) = ls_client {
+ /// assert_eq!(client.server_address.unwrap(), "http://myserver.com".to_string());
+ /// assert_eq!(client.adapter_set.unwrap(), "MY_ADAPTER_SET".to_string());
+ /// }
+ /// ```
+ pub fn new(
+ server_address: Option<&str>,
+ adapter_set: Option<&str>,
+ ) -> Result<LightstreamerClient, IllegalStateException> {
+ let connection_details = ConnectionDetails::new(server_address, adapter_set);
let connection_options = ConnectionOptions::new();
-
+
Ok(LightstreamerClient {
server_address: server_address.map(|s| s.to_string()),
adapter_set: adapter_set.map(|s| s.to_string()),
diff --git a/src/main.rs b/src/main.rs
index 07a3bf4..2dddb0d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -108,8 +108,20 @@ async fn establish_persistent_ws_connection(
async fn subscribe_to_channel(session_id: String) -> Result<(), reqwest::Error> {
let client = Client::new();
- let subscribe_url = "http://push.lightstreamer.com/lightstreamer/bind_session.txt";
- let params = [("LS_session", &session_id)];
+ //let subscribe_url = "http://push.lightstreamer.com/lightstreamer/bind_session.txt";
+ //let params = [("LS_session", &session_id)];
+ let subscribe_url =
+ "http://push.lightstreamer.com/lightstreamer/control.txt?LS_protocol=TLCP-2.0.0";
+ let params = [
+ ("LS_session", &session_id),
+ ("LS_op", &"add".to_string()),
+ ("LS_subId", &"1".to_string()),
+ ("LS_data_adapter", &"CHAT_ROOM".to_string()),
+ ("LS_group", &"chat_room".to_string()),
+ ("LS_schema", &"timestamp message".to_string()),
+ ("LS_mode", &"DISTINCT".to_string()),
+ ("LS_reqId", &"1".to_string()),
+ ];
let response = client.post(subscribe_url).form(&params).send().await?;
@@ -204,15 +216,23 @@ impl SubscriptionListener for MySubscriptionListener {
async fn main() -> Result<(), Box<dyn Error>> {
let mut subscription = Subscription::new(
SubscriptionMode::Merge,
- Some(vec!["item1".to_string(),"item2".to_string(),"item3".to_string()]),
- Some(vec!["stock_name".to_string(),"last_price".to_string()]),
+ Some(vec![
+ "item1".to_string(),
+ "item2".to_string(),
+ "item3".to_string(),
+ ]),
+ Some(vec!["stock_name".to_string(), "last_price".to_string()]),
)?;
subscription.add_listener(Box::new(MySubscriptionListener {}));
- let client = LightstreamerClient::new("http://push.lightstreamer.com/lightstreamer", "DEMO")?;
+ let client = LightstreamerClient::new(
+ Some("http://push.lightstreamer.com/lightstreamer"),
+ Some("DEMO"),
+ )?;
println!("Subscription: {:?}", subscription);
+ println!("Client: {:?}", client);
Ok(())
}
diff --git a/src/proxy.rs b/src/proxy.rs
index 48b2758..9a8add8 100644
--- a/src/proxy.rs
+++ b/src/proxy.rs
@@ -1,3 +1,83 @@
+/// Simple class representing a Proxy configuration.
+///
+/// An instance of this class can be used through `ConnectionOptions.setProxy()` to instruct
+/// a `LightstreamerClient` to connect to the Lightstreamer Server passing through a proxy.
+///
+/// # Parameters
+///
+/// * `proxy_type`: the proxy type
+/// * `host`: the proxy host
+/// * `port`: the proxy port
+/// * `user`: the user name to be used to validate against the proxy. Optional.
+/// * `password`: the password to be used to validate against the proxy. Optional.
+#[derive(Debug)]
pub struct Proxy {
+ proxy_type: ProxyType,
+ host: String,
+ port: u16,
+ user: Option<String>,
+ password: Option<String>,
+}
+impl Proxy {
+ /// Creates a new instance of `Proxy`.
+ ///
+ /// # Parameters
+ ///
+ /// * `proxy_type`: the proxy type
+ /// * `host`: the proxy host
+ /// * `port`: the proxy port
+ /// * `user`: the user name to be used to validate against the proxy. Optional.
+ /// * `password`: the password to be used to validate against the proxy. Optional.
+ pub fn new(
+ proxy_type: ProxyType,
+ host: String,
+ port: u16,
+ user: Option<String>,
+ password: Option<String>,
+ ) -> Self {
+ Proxy {
+ proxy_type,
+ host,
+ port,
+ user,
+ password,
+ }
+ }
+
+ /// Returns the proxy type.
+ pub fn get_proxy_type(&self) -> &ProxyType {
+ &self.proxy_type
+ }
+
+ /// Returns the proxy host.
+ pub fn get_host(&self) -> &str {
+ &self.host
+ }
+
+ /// Returns the proxy port.
+ pub fn get_port(&self) -> u16 {
+ self.port
+ }
+
+ /// Returns the proxy user name.
+ pub fn get_user(&self) -> Option<&String> {
+ self.user.as_ref()
+ }
+
+ /// Returns the proxy password.
+ pub fn get_password(&self) -> Option<&String> {
+ self.password.as_ref()
+ }
+}
+
+/// Represents the type of proxy.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ProxyType {
+ /// HTTP proxy.
+ Http,
+ /// SOCKS4 proxy.
+ Socks4,
+ /// SOCKS5 proxy.
+ Socks5,
} \ No newline at end of file