Skip to main content

ironfix_engine/
builder.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 27/1/26
5******************************************************************************/
6
7//! Engine builder for fluent configuration.
8//!
9//! This module provides a builder API for configuring FIX engines.
10
11use crate::application::{Application, NoOpApplication};
12use ironfix_session::config::SessionConfig;
13use std::sync::Arc;
14use std::time::Duration;
15
16/// Builder for configuring a FIX engine.
17#[derive(Debug)]
18pub struct EngineBuilder<A: Application = NoOpApplication> {
19    /// Application callback handler.
20    application: Arc<A>,
21    /// Session configurations.
22    sessions: Vec<SessionConfig>,
23    /// Whether to use TLS.
24    use_tls: bool,
25    /// Connection timeout.
26    connect_timeout: Duration,
27    /// Reconnect interval.
28    reconnect_interval: Duration,
29    /// Maximum reconnect attempts.
30    max_reconnect_attempts: u32,
31}
32
33impl Default for EngineBuilder<NoOpApplication> {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl EngineBuilder<NoOpApplication> {
40    /// Creates a new engine builder with default settings.
41    #[must_use]
42    pub fn new() -> Self {
43        Self {
44            application: Arc::new(NoOpApplication),
45            sessions: Vec::new(),
46            use_tls: false,
47            connect_timeout: Duration::from_secs(30),
48            reconnect_interval: Duration::from_secs(5),
49            max_reconnect_attempts: 10,
50        }
51    }
52}
53
54impl<A: Application> EngineBuilder<A> {
55    /// Sets the application callback handler.
56    #[must_use]
57    pub fn with_application<B: Application>(self, application: B) -> EngineBuilder<B> {
58        EngineBuilder {
59            application: Arc::new(application),
60            sessions: self.sessions,
61            use_tls: self.use_tls,
62            connect_timeout: self.connect_timeout,
63            reconnect_interval: self.reconnect_interval,
64            max_reconnect_attempts: self.max_reconnect_attempts,
65        }
66    }
67
68    /// Adds a session configuration.
69    #[must_use]
70    pub fn add_session(mut self, config: SessionConfig) -> Self {
71        self.sessions.push(config);
72        self
73    }
74
75    /// Enables TLS for connections.
76    #[must_use]
77    pub const fn with_tls(mut self, enabled: bool) -> Self {
78        self.use_tls = enabled;
79        self
80    }
81
82    /// Sets the connection timeout.
83    #[must_use]
84    pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
85        self.connect_timeout = timeout;
86        self
87    }
88
89    /// Sets the reconnect interval.
90    #[must_use]
91    pub fn with_reconnect_interval(mut self, interval: Duration) -> Self {
92        self.reconnect_interval = interval;
93        self
94    }
95
96    /// Sets the maximum reconnect attempts.
97    #[must_use]
98    pub const fn with_max_reconnect_attempts(mut self, attempts: u32) -> Self {
99        self.max_reconnect_attempts = attempts;
100        self
101    }
102
103    /// Returns the configured sessions.
104    #[must_use]
105    pub fn sessions(&self) -> &[SessionConfig] {
106        &self.sessions
107    }
108
109    /// Returns whether TLS is enabled.
110    #[must_use]
111    pub const fn use_tls(&self) -> bool {
112        self.use_tls
113    }
114
115    /// Returns the connection timeout.
116    #[must_use]
117    pub const fn connect_timeout(&self) -> Duration {
118        self.connect_timeout
119    }
120
121    /// Returns the reconnect interval.
122    #[must_use]
123    pub const fn reconnect_interval(&self) -> Duration {
124        self.reconnect_interval
125    }
126
127    /// Returns the maximum reconnect attempts.
128    #[must_use]
129    pub const fn max_reconnect_attempts(&self) -> u32 {
130        self.max_reconnect_attempts
131    }
132
133    /// Returns the application handler.
134    #[must_use]
135    pub fn application(&self) -> Arc<A> {
136        Arc::clone(&self.application)
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use ironfix_core::types::CompId;
144
145    #[test]
146    fn test_engine_builder_default() {
147        let builder = EngineBuilder::new();
148        assert!(!builder.use_tls());
149        assert_eq!(builder.connect_timeout(), Duration::from_secs(30));
150        assert_eq!(builder.max_reconnect_attempts(), 10);
151        assert!(builder.sessions().is_empty());
152    }
153
154    #[test]
155    fn test_engine_builder_with_session() {
156        let config = SessionConfig::new(
157            CompId::new("SENDER").unwrap(),
158            CompId::new("TARGET").unwrap(),
159            "FIX.4.4",
160        );
161
162        let builder = EngineBuilder::new()
163            .add_session(config)
164            .with_tls(true)
165            .with_connect_timeout(Duration::from_secs(60));
166
167        assert_eq!(builder.sessions().len(), 1);
168        assert!(builder.use_tls());
169        assert_eq!(builder.connect_timeout(), Duration::from_secs(60));
170    }
171}