1use std::sync::Arc;
7
8use tokio::sync::broadcast;
9
10use crate::audit::helper::AuditHelper;
11use crate::audit::AuditEventSender;
12use crate::command_sender::CommandSender;
13use crate::config::Settings;
14use crate::ipc::server::IpcServer;
15use crate::state::SharedState;
16
17use super::events::CoreEvent;
18
19const EVENT_CHANNEL_CAPACITY: usize = 256;
21
22pub struct TmaiCore {
26 state: SharedState,
28 command_sender: Option<Arc<CommandSender>>,
30 settings: Arc<Settings>,
32 ipc_server: Option<Arc<IpcServer>>,
34 event_tx: broadcast::Sender<CoreEvent>,
36 audit_helper: AuditHelper,
38}
39
40impl TmaiCore {
41 pub(crate) fn new(
43 state: SharedState,
44 command_sender: Option<Arc<CommandSender>>,
45 settings: Arc<Settings>,
46 ipc_server: Option<Arc<IpcServer>>,
47 audit_tx: Option<AuditEventSender>,
48 ) -> Self {
49 let (event_tx, _) = broadcast::channel(EVENT_CHANNEL_CAPACITY);
50 let audit_helper = AuditHelper::new(audit_tx, state.clone());
51 Self {
52 state,
53 command_sender,
54 settings,
55 ipc_server,
56 event_tx,
57 audit_helper,
58 }
59 }
60
61 #[deprecated(note = "Use TmaiCore query/action methods instead of direct state access")]
70 pub fn raw_state(&self) -> &SharedState {
71 &self.state
72 }
73
74 #[deprecated(note = "Use TmaiCore action methods instead of direct CommandSender access")]
79 pub fn raw_command_sender(&self) -> Option<&Arc<CommandSender>> {
80 self.command_sender.as_ref()
81 }
82
83 pub fn settings(&self) -> &Settings {
85 &self.settings
86 }
87
88 pub fn ipc_server(&self) -> Option<&Arc<IpcServer>> {
90 self.ipc_server.as_ref()
91 }
92
93 pub(crate) fn event_sender(&self) -> broadcast::Sender<CoreEvent> {
97 self.event_tx.clone()
98 }
99
100 pub(crate) fn state(&self) -> &SharedState {
106 &self.state
107 }
108
109 pub(crate) fn command_sender_ref(&self) -> Option<&Arc<CommandSender>> {
111 self.command_sender.as_ref()
112 }
113
114 pub(crate) fn audit_helper(&self) -> &AuditHelper {
116 &self.audit_helper
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::state::AppState;
124
125 #[test]
126 fn test_tmai_core_creation() {
127 let state = AppState::shared();
128 let settings = Arc::new(Settings::default());
129 let core = TmaiCore::new(state, None, settings.clone(), None, None);
130
131 assert_eq!(core.settings().poll_interval_ms, 500);
132 assert!(core.ipc_server().is_none());
133 assert!(core.command_sender_ref().is_none());
134 }
135
136 #[test]
137 #[allow(deprecated)]
138 fn test_escape_hatches() {
139 let state = AppState::shared();
140 let settings = Arc::new(Settings::default());
141 let core = TmaiCore::new(state.clone(), None, settings, None, None);
142
143 let raw = core.raw_state();
145 assert!(Arc::ptr_eq(raw, &state));
146
147 assert!(core.raw_command_sender().is_none());
149 }
150}