Skip to main content

tmai_core/api/
builder.rs

1//! Builder for constructing a [`TmaiCore`] instance.
2//!
3//! ```ignore
4//! let core = TmaiCoreBuilder::new(settings)
5//!     .with_state(state)
6//!     .with_ipc_server(ipc)
7//!     .with_command_sender(cmd)
8//!     .build();
9//! ```
10
11use std::sync::Arc;
12
13use crate::audit::AuditEventSender;
14use crate::command_sender::CommandSender;
15use crate::config::Settings;
16use crate::ipc::server::IpcServer;
17use crate::state::{AppState, SharedState};
18
19use super::core::TmaiCore;
20
21/// Builder for constructing a [`TmaiCore`] Facade instance
22pub struct TmaiCoreBuilder {
23    settings: Arc<Settings>,
24    state: Option<SharedState>,
25    command_sender: Option<Arc<CommandSender>>,
26    ipc_server: Option<Arc<IpcServer>>,
27    audit_tx: Option<AuditEventSender>,
28}
29
30impl TmaiCoreBuilder {
31    /// Create a new builder with the given settings
32    pub fn new(settings: Settings) -> Self {
33        Self {
34            settings: Arc::new(settings),
35            state: None,
36            command_sender: None,
37            ipc_server: None,
38            audit_tx: None,
39        }
40    }
41
42    /// Create a new builder from an already-shared settings
43    pub fn from_shared_settings(settings: Arc<Settings>) -> Self {
44        Self {
45            settings,
46            state: None,
47            command_sender: None,
48            ipc_server: None,
49            audit_tx: None,
50        }
51    }
52
53    /// Use an existing shared state instead of creating a new one
54    pub fn with_state(mut self, state: SharedState) -> Self {
55        self.state = Some(state);
56        self
57    }
58
59    /// Set the IPC server for PTY wrapper communication
60    pub fn with_ipc_server(mut self, ipc_server: Arc<IpcServer>) -> Self {
61        self.ipc_server = Some(ipc_server);
62        self
63    }
64
65    /// Set the command sender
66    pub fn with_command_sender(mut self, sender: Arc<CommandSender>) -> Self {
67        self.command_sender = Some(sender);
68        self
69    }
70
71    /// Set the audit event sender for emitting audit events
72    pub fn with_audit_sender(mut self, tx: AuditEventSender) -> Self {
73        self.audit_tx = Some(tx);
74        self
75    }
76
77    /// Build the `TmaiCore` instance
78    ///
79    /// If no state was provided, a fresh `AppState::shared()` is created.
80    pub fn build(self) -> TmaiCore {
81        let state = self.state.unwrap_or_else(AppState::shared);
82
83        TmaiCore::new(
84            state,
85            self.command_sender,
86            self.settings,
87            self.ipc_server,
88            self.audit_tx,
89        )
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_builder_defaults() {
99        let core = TmaiCoreBuilder::new(Settings::default()).build();
100
101        assert_eq!(core.settings().poll_interval_ms, 500);
102        assert!(core.ipc_server().is_none());
103        assert!(core.command_sender_ref().is_none());
104    }
105
106    #[test]
107    fn test_builder_with_state() {
108        let state = AppState::shared();
109        let state_clone = state.clone();
110
111        let core = TmaiCoreBuilder::new(Settings::default())
112            .with_state(state)
113            .build();
114
115        #[allow(deprecated)]
116        let raw = core.raw_state();
117        assert!(Arc::ptr_eq(raw, &state_clone));
118    }
119
120    #[test]
121    fn test_builder_from_shared_settings() {
122        let settings = Arc::new(Settings::default());
123        let settings_clone = settings.clone();
124
125        let core = TmaiCoreBuilder::from_shared_settings(settings).build();
126
127        // Settings should be the same Arc
128        assert_eq!(
129            core.settings().poll_interval_ms,
130            settings_clone.poll_interval_ms
131        );
132    }
133}