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. /// /// An instance of this class is attached to every `LightstreamerClient` as `LightstreamerClient.connectionDetails` /// /// See also `LightstreamerClient` pub struct ConnectionDetails { adapter_set: Option, client_ip: Option, server_address: Option, server_instance_address: Option, server_socket_name: Option, session_id: Option, user: Option, password: Option, listeners: Vec>, } 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) -> Option<&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 `` /// or `` 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<&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() } } /// 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 `` 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) { 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) { 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, ) -> 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) { 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) { 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) { unimplemented!("Implement mechanism to remove listener from ConnectionDetails."); //self.listeners.remove(&listener); } } 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 { 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(), } } }