aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar daniloaz <daniloaz@gmail.com>2024-03-24 21:47:33 +0100
committerLibravatar daniloaz <daniloaz@gmail.com>2024-03-24 21:47:33 +0100
commitb4e12fd1165b5e3960a1294dadec45eb40893b37 (patch)
tree214908f3aaf1bea984adfdce4d9b755ba71be670
parent7e1eb27a06e5545b3d1b77b5998dc0463df27d70 (diff)
Unstable commit, won't compile.
-rw-r--r--src/connection_details.rs362
-rw-r--r--src/lib.rs21
-rw-r--r--src/lightstreamer_client.rs25
-rw-r--r--src/main.rs55
-rw-r--r--src/subscription.rs23
-rw-r--r--src/subscription_listener.rs48
6 files changed, 509 insertions, 25 deletions
diff --git a/src/connection_details.rs b/src/connection_details.rs
index 03f33f5..1d18bf6 100644
--- a/src/connection_details.rs
+++ b/src/connection_details.rs
@@ -1,3 +1,363 @@
+use crate::client_listener::ClientListener;
+use crate::IllegalArgumentException;
+
+/// 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.
+///
+/// An instance of this class is attached to every `LightstreamerClient` as `LightstreamerClient.connectionDetails`
+///
+/// See also `LightstreamerClient`
pub struct ConnectionDetails {
+ adapter_set: String,
+ client_ip: Option<String>,
+ server_address: String,
+ server_instance_address: Option<String>,
+ server_socket_name: Option<String>,
+ session_id: Option<String>,
+ user: Option<String>,
+ password: Option<String>,
+ listeners: Vec<Box<dyn ClientListener>>,
+}
+
+impl ConnectionDetails {
+ /// Inquiry method that gets the name of the Adapter Set (which defines the Metadata Adapter
+ /// and one or several Data Adapters) mounted on Lightstreamer Server that supply all the
+ /// items used in this application.
+ ///
+ /// # Returns
+ ///
+ /// The name of the Adapter Set; returns `None` if no name has been configured, that means
+ /// that the "DEFAULT" Adapter Set is used.
+ ///
+ /// See also `setAdapterSet()`
+ pub fn get_adapter_set(&self) -> &String {
+ self.adapter_set.as_ref()
+ }
+
+ /// Inquiry method that gets the IP address of this client as seen by the Server which is
+ /// serving the current session as the client remote address (note that it may not correspond
+ /// to the client host; for instance it may refer to an intermediate proxy). If, upon a new
+ /// session, this address changes, it may be a hint that the intermediary network nodes handling
+ /// the connection have changed, hence the network capabilities may be different. The library
+ /// uses this information to optimize the connection.
+ ///
+ /// Note that in case of polling or in case rebind requests are needed, subsequent requests
+ /// related to the same session may, in principle, expose a different IP address to the Server;
+ /// these changes would not be reported.
+ ///
+ /// If a session is not currently active, `None` is returned; soon after a session is established,
+ /// the value may become available; but it is possible that this information is not provided
+ /// by the Server and that it will never be available.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "clientIp" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Returns
+ ///
+ /// A canonical representation of an IP address (it can be either IPv4 or IPv6), or `None`.
+ pub fn get_client_ip(&self) -> Option<&String> {
+ self.client_ip.as_ref()
+ }
+
+ /// Inquiry method that gets the configured address of Lightstreamer Server.
+ ///
+ /// # Returns
+ ///
+ /// The configured address of Lightstreamer Server.
+ pub fn get_server_address(&self) -> Option<&String> {
+ self.server_address.as_ref()
+ }
+
+ /// Inquiry method that gets the server address to be used to issue all requests related to
+ /// the current session. In fact, when a Server cluster is in place, the Server address specified
+ /// through `setServerAddress()` can identify various Server instances; in order to ensure that
+ /// all requests related to a session are issued to the same Server instance, the Server can
+ /// answer to the session opening request by providing an address which uniquely identifies
+ /// its own instance. When this is the case, this address is returned by the method; otherwise,
+ /// `None` is returned.
+ ///
+ /// Note that the addresses will always have the `http:` or `https:` scheme. In case WebSockets
+ /// are used, the specified scheme is internally converted to match the related WebSocket protocol
+ /// (i.e. `http` becomes `ws` while `https` becomes `wss`).
+ ///
+ /// Server Clustering is an optional feature, available depending on Edition and License Type.
+ /// To know what features are enabled by your license, please see the License tab of the Monitoring
+ /// Dashboard (by default, available at /dashboard).
+ ///
+ /// The method gives a meaningful answer only when a session is currently active.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "serverInstanceAddress" on any `ClientListener` listening to the related
+ /// `LightstreamerClient`.
+ ///
+ /// # Returns
+ ///
+ /// Address used to issue all requests related to the current session.
+ pub fn get_server_instance_address(&self) -> Option<&String> {
+ self.server_instance_address.as_ref()
+ }
+
+ /// Inquiry method that gets the instance name of the Server which is serving the current session.
+ /// To be more precise, each answering port configured on a Server instance (through a `<http_server>`
+ /// or `<https_server>` element in the Server configuration file) can be given a different name;
+ /// the name related to the port to which the session opening request has been issued is returned.
+ ///
+ /// Note that each rebind to the same session can, potentially, reach the Server on a port different
+ /// than the one used for the previous request, depending on the behavior of intermediate nodes.
+ /// However, the only meaningful case is when a Server cluster is in place and it is configured
+ /// in such a way that the port used for all `bind_session` requests differs from the port used
+ /// for the initial `create_session` request.
+ ///
+ /// Server Clustering is an optional feature, available depending on Edition and License Type.
+ /// To know what features are enabled by your license, please see the License tab of the Monitoring
+ /// Dashboard (by default, available at /dashboard).
+ ///
+ /// If a session is not currently active, `None` is returned; soon after a session is established,
+ /// the value will become available.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "serverSocketName" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Returns
+ ///
+ /// Name configured for the Server instance which is managing the current session, or `None`.
+ pub fn get_server_socket_name(&self) -> Option<&String> {
+ self.server_socket_name.as_ref()
+ }
+
+ /// Inquiry method that gets the ID associated by the server to this client session.
+ ///
+ /// The method gives a meaningful answer only when a session is currently active.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "sessionId" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Returns
+ ///
+ /// ID assigned by the Server to this client session.
+ pub fn get_session_id(&self) -> Option<&String> {
+ self.session_id.as_ref()
+ }
+
+ /// Inquiry method that gets the username to be used for the authentication on Lightstreamer
+ /// Server when initiating the session.
+ ///
+ /// # Returns
+ ///
+ /// The username to be used for the authentication on Lightstreamer Server; returns `None`
+ /// if no user name has been configured.
+ pub fn get_user(&self) -> Option<&String> {
+ self.user.as_ref()
+ }
+
+ /// 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()
+ }
+ }
+ }
+
+ /// Setter method that sets the name of the Adapter Set mounted on Lightstreamer Server to
+ /// be used to handle all requests in the session.
+ ///
+ /// An Adapter Set defines the Metadata Adapter and one or several Data Adapters. It is configured
+ /// on the server side through an "adapters.xml" file; the name is configured through the "id"
+ /// attribute in the `<adapters_conf>` element.
+ ///
+ /// The default Adapter Set, configured as "DEFAULT" on the Server.
+ ///
+ /// The Adapter Set name should be set on the `LightstreamerClient.connectionDetails` object
+ /// before calling the `LightstreamerClient.connect()` method. However, the value can be changed
+ /// at any time: the supplied value will be used for the next time a new session is requested
+ /// to the server.
+ ///
+ /// This setting can also be specified in the `LightstreamerClient` constructor.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "adapterSet" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Parameters
+ ///
+ /// * `adapter_set`: The name of the Adapter Set to be used. A `None` value is equivalent to
+ /// the "DEFAULT" name.
+ pub fn set_adapter_set(&mut self, adapter_set: Option<String>) {
+ self.adapter_set = adapter_set;
+
+ // Notify listeners about the property change
+ for listener in &self.listeners {
+ listener.on_property_change("adapterSet");
+ }
+ }
+
+ /// Setter method that sets the password to be used for the authentication on Lightstreamer
+ /// Server when initiating the session. The Metadata Adapter is responsible for checking the
+ /// credentials (username and password).
+ ///
+ /// If no password is supplied, no password information will be sent at session initiation.
+ /// The Metadata Adapter, however, may still allow the session.
+ ///
+ /// The password should be set on the `LightstreamerClient.connectionDetails` object before
+ /// calling the `LightstreamerClient.connect()` method. However, the value can be changed at
+ /// any time: the supplied value will be used for the next time a new session is requested to
+ /// the server.
+ ///
+ /// NOTE: The password string will be stored in the current instance. That is necessary in order
+ /// to allow automatic reconnection/reauthentication for fail-over. For maximum security, avoid
+ /// using an actual private password to authenticate on Lightstreamer Server; rather use a session-id
+ /// originated by your web/application server, that can be checked by your Metadata Adapter.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "password" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Parameters
+ ///
+ /// * `password`: The password to be used for the authentication on Lightstreamer Server. The
+ /// password can be `None`.
+ ///
+ /// See also `setUser()`
+ pub fn set_password(&mut self, password: Option<String>) {
+ self.password = password;
+
+ // Notify listeners about the property change
+ for listener in &self.listeners {
+ listener.on_property_change("password");
+ }
+ }
+
+ /// Setter method that sets the address of Lightstreamer Server.
+ ///
+ /// Note that the addresses specified must always have the `http:` or `https:` scheme. In case
+ /// WebSockets are used, the specified scheme is internally converted to match the related WebSocket
+ /// protocol (i.e. `http` becomes `ws` while `https` becomes `wss`).
+ ///
+ /// WSS/HTTPS is an optional feature, available depending on Edition and License Type. To know
+ /// what features are enabled by your license, please see the License tab of the Monitoring
+ /// Dashboard (by default, available at /dashboard).
+ ///
+ /// If no server address is supplied the client will be unable to connect.
+ ///
+ /// This method can be called at any time. If called while connected, it will be applied when
+ /// the next session creation request is issued. This setting can also be specified in the
+ /// `LightstreamerClient` constructor.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "serverAddress" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Parameters
+ ///
+ /// * `server_address`: The full address of Lightstreamer Server. A `None` value can also be
+ /// used, to restore the default value.
+ ///
+ /// An IPv4 or IPv6 can also be used in place of a hostname. Some examples of valid values include:
+ ///
+ /// - `http://push.mycompany.com`
+ /// - `http://push.mycompany.com:8080`
+ /// - `http://79.125.7.252`
+ /// - `http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]`
+ /// - `http://[2001:0db8:85a3::8a2e:0370:7334]:8080`
+ ///
+ /// # Raises
+ ///
+ /// * `IllegalArgumentException`: if the given address is not valid.
+ pub fn set_server_address(
+ &mut self,
+ server_address: Option<String>,
+ ) -> Result<(), IllegalArgumentException> {
+ // Validate the server address
+ if let Some(address) = &server_address {
+ if !address.starts_with("http://") && !address.starts_with("https://") {
+ return Err(IllegalArgumentException::new(
+ "Invalid server address: must start with http:// or https://",
+ ));
+ }
+ }
+
+ self.server_address = server_address;
+
+ // Notify listeners about the property change
+ for listener in &self.listeners {
+ listener.on_property_change("serverAddress");
+ }
+
+ Ok(())
+ }
+
+ /// Setter method that sets the username to be used for the authentication on Lightstreamer
+ /// Server when initiating the session. The Metadata Adapter is responsible for checking the
+ /// credentials (username and password).
+ ///
+ /// If no username is supplied, no user information will be sent at session initiation. The
+ /// Metadata Adapter, however, may still allow the session.
+ ///
+ /// The username should be set on the `LightstreamerClient.connectionDetails` object before
+ /// calling the `LightstreamerClient.connect()` method. However, the value can be changed at
+ /// any time: the supplied value will be used for the next time a new session is requested to
+ /// the server.
+ ///
+ /// A change to this setting will be notified through a call to `ClientListener.onPropertyChange()`
+ /// with argument "user" on any `ClientListener` listening to the related `LightstreamerClient`.
+ ///
+ /// # Parameters
+ ///
+ /// * `user`: The username to be used for the authentication on Lightstreamer Server. The username
+ /// can be `None`.
+ ///
+ /// See also `setPassword()`
+ pub fn set_user(&mut self, user: Option<String>) {
+ self.user = user;
+
+ // Notify listeners about the property change
+ for listener in &self.listeners {
+ listener.on_property_change("user");
+ }
+ }
+
+ /// Adds a listener that will receive events related to changes in the `ConnectionDetails`.
+ ///
+ /// The same listener can be added to multiple instances of `ConnectionDetails`.
+ ///
+ /// # Parameters
+ ///
+ /// * `listener`: An object that will receive the events as documented in the `ClientListener`
+ /// interface.
+ pub fn add_listener(&mut self, listener: Box<dyn ClientListener>) {
+ self.listeners.push(listener);
+ }
+
+ /// Removes a listener from the `ConnectionDetails` instance so that it will not receive events
+ /// anymore.
+ ///
+ /// # Parameters
+ ///
+ /// * `listener`: The listener to be removed.
+ pub fn remove_listener(&mut self, listener: Box<dyn ClientListener>) {
+ unimplemented!("Implement mechanism to remove listener from ConnectionDetails.");
+ //self.listeners.remove(&listener);
+ }
+}
-} \ No newline at end of file
+impl Default for ConnectionDetails {
+ fn default() -> Self {
+ ConnectionDetails {
+ adapter_set: None,
+ client_ip: None,
+ server_address: None,
+ server_instance_address: None,
+ server_socket_name: None,
+ session_id: None,
+ user: None,
+ password: None,
+ listeners: Vec::new(),
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index c7ea164..3ae6463 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,27 @@ pub mod proxy;
pub mod subscription;
#[derive(Debug)]
+pub struct IllegalArgumentException(String);
+
+impl IllegalArgumentException {
+ pub fn new(msg: &str) -> IllegalArgumentException {
+ IllegalArgumentException(msg.to_string())
+ }
+}
+
+impl fmt::Display for IllegalArgumentException {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl Error for IllegalArgumentException {
+ fn description(&self) -> &str {
+ &self.0
+ }
+}
+
+#[derive(Debug)]
pub struct IllegalStateException {
details: String
}
diff --git a/src/lightstreamer_client.rs b/src/lightstreamer_client.rs
index 2012c28..f91e843 100644
--- a/src/lightstreamer_client.rs
+++ b/src/lightstreamer_client.rs
@@ -45,8 +45,8 @@ use cookie::Cookie;
/// * `IllegalArgumentException`: if a not valid address is passed. See `ConnectionDetails.setServerAddress()`
/// for details.
pub struct LightstreamerClient {
- server_address: Option<String>,
- adapter_set: Option<String>,
+ server_address: String,
+ adapter_set: 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.
@@ -134,10 +134,6 @@ impl LightstreamerClient {
///
/// See also `ConnectionDetails.setServerAddress()`
pub fn connect(&mut self) -> Result<(), IllegalStateException> {
- if self.server_address.is_none() {
- return Err(IllegalStateException::new("No server address was configured."));
- }
-
// Implementation for connect
Ok(())
}
@@ -236,6 +232,23 @@ 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(),
+ );
+ 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()),
+ connection_details,
+ connection_options,
+ listeners: Vec::new(),
+ subscriptions: Vec::new(),
+ })
+ }
+
/// Removes a listener from the `LightstreamerClient` instance so that it will not receive
/// events anymore.
///
diff --git a/src/main.rs b/src/main.rs
index d782d2b..07a3bf4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,20 @@
+use crate::item_update::ItemUpdate;
+use crate::subscription::{Subscription, SubscriptionMode};
+use crate::subscription_listener::SubscriptionListener;
+
use futures::stream::StreamExt;
use futures::SinkExt;
+use lightstreamer_client::lightstreamer_client::LightstreamerClient;
use reqwest::Client;
use serde_urlencoded;
use std::error::Error;
use std::sync::Arc;
-use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use tokio::sync::Mutex;
+use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
+
+mod item_update;
+mod subscription;
+mod subscription_listener;
async fn establish_persistent_http_connection(
session_id_shared: Arc<Mutex<String>>,
@@ -116,7 +125,12 @@ async fn subscribe_to_channel(session_id: String) -> Result<(), reqwest::Error>
// Function to subscribe to a channel using WebSocket
async fn subscribe_to_channel_ws(
session_id: String,
- mut write: futures::stream::SplitSink<tokio_tungstenite::WebSocketStream<tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>>, tokio_tungstenite::tungstenite::protocol::Message>,
+ mut write: futures::stream::SplitSink<
+ tokio_tungstenite::WebSocketStream<
+ tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
+ >,
+ tokio_tungstenite::tungstenite::protocol::Message,
+ >,
) -> Result<(), Box<dyn Error>> {
// Example subscription to ITEM1 in MERGE mode from the DEMO adapter set
let sub_params = [
@@ -131,15 +145,14 @@ async fn subscribe_to_channel_ws(
let encoded_sub_params = serde_urlencoded::to_string(&sub_params)?;
// Send the subscription message
- write
- .send(Message::Text(encoded_sub_params))
- .await?;
+ write.send(Message::Text(encoded_sub_params)).await?;
println!("Subscribed to channel with session ID: {}", session_id);
Ok(())
}
+/*
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
@@ -172,4 +185,34 @@ async fn main() -> Result<(), Box<dyn Error>> {
task2.await?;
Ok(())
-} \ No newline at end of file
+}
+*/
+
+pub struct MySubscriptionListener {}
+
+impl SubscriptionListener for MySubscriptionListener {
+ fn on_item_update(&mut self, update: ItemUpdate) {
+ println!(
+ "UPDATE {} {}",
+ update.get_value("stock_name").unwrap(),
+ update.get_value("last_price").unwrap()
+ );
+ }
+}
+
+#[tokio::main]
+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()]),
+ )?;
+
+ subscription.add_listener(Box::new(MySubscriptionListener {}));
+
+ let client = LightstreamerClient::new("http://push.lightstreamer.com/lightstreamer", "DEMO")?;
+
+ println!("Subscription: {:?}", subscription);
+
+ Ok(())
+}
diff --git a/src/subscription.rs b/src/subscription.rs
index 035614d..f7e0d88 100644
--- a/src/subscription.rs
+++ b/src/subscription.rs
@@ -1,5 +1,6 @@
use crate::subscription_listener::SubscriptionListener;
use std::collections::HashMap;
+use std::fmt::{self, Debug, Formatter};
/// Enum representing the subscription mode
#[derive(Debug, PartialEq, Eq)]
@@ -837,4 +838,26 @@ impl Subscription {
}
}
*/
+}
+
+impl Debug for Subscription {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.debug_struct("Subscription")
+ .field("mode", &self.mode)
+ .field("item_group", &self.item_group)
+ .field("items", &self.items)
+ .field("field_schema", &self.field_schema)
+ .field("fields", &self.fields)
+ .field("data_adapter", &self.data_adapter)
+ .field("command_second_level_data_adapter", &self.command_second_level_data_adapter)
+ .field("command_second_level_field_schema", &self.command_second_level_field_schema)
+ .field("command_second_level_fields", &self.command_second_level_fields)
+ .field("requested_buffer_size", &self.requested_buffer_size)
+ .field("requested_max_frequency", &self.requested_max_frequency)
+ .field("requested_snapshot", &self.requested_snapshot)
+ .field("selector", &self.selector)
+ .field("is_active", &self.is_active)
+ .field("is_subscribed", &self.is_subscribed)
+ .finish()
+ }
} \ No newline at end of file
diff --git a/src/subscription_listener.rs b/src/subscription_listener.rs
index 5fb6f85..aaadfd9 100644
--- a/src/subscription_listener.rs
+++ b/src/subscription_listener.rs
@@ -32,7 +32,9 @@ pub trait SubscriptionListener {
/// - `item_name`: name of the involved item. If the Subscription was initialized using an
/// "Item Group" then a `None` value is supplied.
/// - `item_pos`: 1-based position of the item within the "Item List" or "Item Group".
- fn on_clear_snapshot(&mut self, item_name: Option<&str>, item_pos: usize);
+ fn on_clear_snapshot(&mut self, item_name: Option<&str>, item_pos: usize) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer to notify that, due to internal resource
/// limitations, Lightstreamer Server dropped one or more updates for an item that was
@@ -52,7 +54,9 @@ pub trait SubscriptionListener {
/// - `Subscription::set_requested_max_frequency()`
/// - `Subscription::set_command_second_level_fields()`
/// - `Subscription::set_command_second_level_field_schema()`
- fn on_command_second_level_item_lost_updates(&mut self, lost_updates: u32, key: &str);
+ fn on_command_second_level_item_lost_updates(&mut self, lost_updates: u32, key: &str) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called when the Server notifies an error on a second-level subscription.
///
@@ -83,7 +87,9 @@ pub trait SubscriptionListener {
/// - `ConnectionDetails::set_adapter_set()`
/// - `Subscription::set_command_second_level_fields()`
/// - `Subscription::set_command_second_level_field_schema()`
- fn on_command_second_level_subscription_error(&mut self, code: i32, message: Option<&str>, key: &str);
+ fn on_command_second_level_subscription_error(&mut self, code: i32, message: Option<&str>, key: &str) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer to notify that all snapshot events for an item
/// in the Subscription have been received, so that real time events are now going to be received.
@@ -108,7 +114,9 @@ pub trait SubscriptionListener {
///
/// - `Subscription::set_requested_snapshot()`
/// - `ItemUpdate::is_snapshot()`
- fn on_end_of_snapshot(&mut self, item_name: Option<&str>, item_pos: usize);
+ fn on_end_of_snapshot(&mut self, item_name: Option<&str>, item_pos: usize) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer to notify that, due to internal resource
/// limitations, Lightstreamer Server dropped one or more updates for an item in the Subscription.
@@ -131,7 +139,9 @@ pub trait SubscriptionListener {
/// # See also
///
/// - `Subscription::set_requested_max_frequency()`
- fn on_item_lost_updates(&mut self, item_name: Option<&str>, item_pos: usize, lost_updates: u32);
+ fn on_item_lost_updates(&mut self, item_name: Option<&str>, item_pos: usize, lost_updates: u32) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer each time an update pertaining to an item
/// in the Subscription has been received from the Server.
@@ -141,17 +151,23 @@ pub trait SubscriptionListener {
/// - `update`: a value object containing the updated values for all the fields, together with
/// meta-information about the update itself and some helper methods that can be used to
/// iterate through all or new values.
- fn on_item_update(&mut self, update: ItemUpdate);
+ fn on_item_update(&mut self, update: ItemUpdate) {
+ // Default implementation does nothing.
+ }
/// Event handler that receives a notification when the `SubscriptionListener` instance is
/// removed from a `Subscription` through `Subscription::remove_listener()`. This is the last
/// event to be fired on the listener.
- fn on_listen_end(&mut self);
+ fn on_listen_end(&mut self) {
+ // Default implementation does nothing.
+ }
/// Event handler that receives a notification when the `SubscriptionListener` instance is
/// added to a `Subscription` through `Subscription::add_listener()`. This is the first event
/// to be fired on the listener.
- fn on_listen_start(&mut self);
+ fn on_listen_start(&mut self) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer to notify the client with the real maximum
/// update frequency of the Subscription. It is called immediately after the Subscription is
@@ -173,7 +189,9 @@ pub trait SubscriptionListener {
/// - `frequency`: A decimal number, representing the maximum frequency applied by the Server
/// (expressed in updates per second), or the string "unlimited". A `None` value is possible in
/// rare cases, when the frequency can no longer be determined.
- fn on_real_max_frequency(&mut self, frequency: Option<f64>);
+ fn on_real_max_frequency(&mut self, frequency: Option<f64>) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer to notify that a Subscription has been successfully
/// subscribed to through the Server. This can happen multiple times in the life of a Subscription
@@ -190,7 +208,9 @@ pub trait SubscriptionListener {
/// If the involved Subscription has a two-level behavior enabled
/// (see `Subscription::set_command_second_level_fields()` and
/// `Subscription::set_command_second_level_field_schema()`), second-level subscriptions are not notified.
- fn on_subscription(&mut self);
+ fn on_subscription(&mut self) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called when the Server notifies an error on a Subscription.
/// By implementing this method it is possible to perform recovery actions.
@@ -224,7 +244,9 @@ pub trait SubscriptionListener {
/// # See also
///
/// - `ConnectionDetails::set_adapter_set()`
- fn on_subscription_error(&mut self, code: i32, message: Option<&str>);
+ fn on_subscription_error(&mut self, code: i32, message: Option<&str>) {
+ // Default implementation does nothing.
+ }
/// Event handler that is called by Lightstreamer to notify that a Subscription has been successfully
/// unsubscribed from. This can happen multiple times in the life of a Subscription instance, in case
@@ -240,5 +262,7 @@ pub trait SubscriptionListener {
/// If the involved Subscription has a two-level behavior enabled
/// (see `Subscription::set_command_second_level_fields()` and
/// `Subscription::set_command_second_level_field_schema()`), second-level unsubscriptions are not notified.
- fn on_unsubscription(&mut self);
+ fn on_unsubscription(&mut self) {
+ // Default implementation does nothing.
+ }
} \ No newline at end of file