Skip to main content

bacnet_rs/client/
config.rs

1//! Configuration and builder for the high-level BACnet client.
2//!
3//! [`ClientConfig`] holds the parameters used to construct a
4//! [`BacnetClient`](super::BacnetClient): the local interface/port to bind, the
5//! per-request timeout, and how many times to retry. Use
6//! [`BacnetClient::builder`](super::BacnetClient::builder) to construct a client
7//! fluently:
8//!
9//! ```rust,no_run
10//! use bacnet_rs::client::BacnetClient;
11//! use std::time::Duration;
12//!
13//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
14//! let client = BacnetClient::builder()
15//!     .local_addr("0.0.0.0")
16//!     .port(0)
17//!     .timeout(Duration::from_secs(3))
18//!     .retries(2)
19//!     .build()?;
20//! # let _ = client;
21//! # Ok(())
22//! # }
23//! ```
24
25use std::time::Duration;
26
27use super::{BacnetClient, ClientError};
28
29/// Default per-request timeout used when none is configured.
30pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
31
32/// Default host to bind to (all interfaces, OS-assigned ephemeral port).
33pub const DEFAULT_HOST: &str = "0.0.0.0";
34
35/// Configuration parameters for a [`BacnetClient`](super::BacnetClient).
36///
37/// Construct one via [`BacnetClient::builder`](super::BacnetClient::builder)
38/// rather than directly; the builder applies sensible defaults.
39#[derive(Debug, Clone)]
40pub struct ClientConfig {
41    /// Local host/interface to bind the UDP socket to.
42    pub host: String,
43    /// Local UDP port to bind. `0` lets the OS assign an ephemeral port.
44    pub port: u16,
45    /// How long to wait for a response before giving up.
46    pub timeout: Duration,
47    /// Number of times to retry a request after the first attempt times out.
48    ///
49    /// Currently stored for use by later request paths; the existing methods
50    /// do not yet retry.
51    pub retries: u8,
52}
53
54impl Default for ClientConfig {
55    fn default() -> Self {
56        Self {
57            host: DEFAULT_HOST.to_string(),
58            port: 0,
59            timeout: DEFAULT_TIMEOUT,
60            retries: 0,
61        }
62    }
63}
64
65impl ClientConfig {
66    /// The address string (`host:port`) the socket will bind to.
67    pub fn bind_addr(&self) -> String {
68        format!("{}:{}", self.host, self.port)
69    }
70}
71
72/// Fluent builder for a [`BacnetClient`](super::BacnetClient).
73///
74/// Obtain one from [`BacnetClient::builder`](super::BacnetClient::builder).
75#[derive(Debug, Clone, Default)]
76pub struct ClientBuilder {
77    config: ClientConfig,
78}
79
80impl ClientBuilder {
81    /// Create a builder with default configuration.
82    pub fn new() -> Self {
83        Self::default()
84    }
85
86    /// Set the local host/interface to bind to (default `"0.0.0.0"`).
87    pub fn local_addr(mut self, host: impl Into<String>) -> Self {
88        self.config.host = host.into();
89        self
90    }
91
92    /// Set the local UDP port to bind (default `0`, an OS-assigned port).
93    pub fn port(mut self, port: u16) -> Self {
94        self.config.port = port;
95        self
96    }
97
98    /// Set the per-request timeout (default 5 seconds).
99    pub fn timeout(mut self, timeout: Duration) -> Self {
100        self.config.timeout = timeout;
101        self
102    }
103
104    /// Set the number of retries after an initial timeout (default `0`).
105    pub fn retries(mut self, retries: u8) -> Self {
106        self.config.retries = retries;
107        self
108    }
109
110    /// Consume the builder and bind the client's socket.
111    pub fn build(self) -> Result<BacnetClient, ClientError> {
112        BacnetClient::from_config(self.config)
113    }
114}