actr_runtime/lifecycle/
actr_system.rs1use actr_config::Config;
4use actr_framework::Workload;
5use actr_protocol::ActorResult;
6use std::sync::Arc;
7
8use super::ActrNode;
9use crate::context_factory::ContextFactory;
10
11use crate::wire::webrtc::{
13 ReconnectConfig, SignalingClient, SignalingConfig, WebSocketSignalingClient,
14};
15use actr_mailbox::{DeadLetterQueue, Mailbox};
16
17pub struct ActrSystem {
24 config: Config,
26
27 mailbox: Arc<dyn Mailbox>,
29
30 dlq: Arc<dyn DeadLetterQueue>,
32
33 context_factory: ContextFactory,
35
36 signaling_client: Arc<dyn SignalingClient>,
38}
39
40impl ActrSystem {
41 pub async fn new(config: Config) -> ActorResult<Self> {
47 tracing::info!("🚀 Initializing ActrSystem");
48
49 let mailbox_path = config
51 .mailbox_path
52 .as_ref()
53 .map(|p| p.to_string_lossy().to_string())
54 .unwrap_or_else(|| ":memory:".to_string());
55
56 tracing::info!("📂 Mailbox database path: {}", mailbox_path);
57
58 let mailbox: Arc<dyn Mailbox> = Arc::new(
59 actr_mailbox::SqliteMailbox::new(&mailbox_path)
60 .await
61 .map_err(|e| {
62 actr_protocol::ProtocolError::TransportError(format!(
63 "Mailbox init failed: {e}"
64 ))
65 })?,
66 );
67
68 let dlq_path = if mailbox_path == ":memory:" {
71 ":memory:".to_string() } else {
73 format!("{mailbox_path}.dlq") };
75
76 let dlq: Arc<dyn DeadLetterQueue> = Arc::new(
77 actr_mailbox::SqliteDeadLetterQueue::new_standalone(&dlq_path)
78 .await
79 .map_err(|e| {
80 actr_protocol::ProtocolError::TransportError(format!("DLQ init failed: {e}"))
81 })?,
82 );
83 tracing::info!("✅ Dead Letter Queue initialized");
84
85 let signaling_config = SignalingConfig {
87 server_url: config.signaling_url.clone(),
88 connection_timeout: 30,
89 heartbeat_interval: 30,
90 reconnect_config: ReconnectConfig::default(),
91 auth_config: None,
92 };
93 let signaling_client: Arc<dyn SignalingClient> =
94 Arc::new(WebSocketSignalingClient::new(signaling_config));
95
96 use crate::outbound::{InprocOutGate, OutGate};
100 use crate::transport::InprocTransportManager;
101
102 let shell_to_workload = Arc::new(InprocTransportManager::new());
107 tracing::debug!("✨ Created shell_to_workload InprocTransportManager");
108
109 let workload_to_shell = Arc::new(InprocTransportManager::new());
111 tracing::debug!("✨ Created workload_to_shell InprocTransportManager");
112
113 let inproc_gate =
115 OutGate::InprocOut(Arc::new(InprocOutGate::new(shell_to_workload.clone())));
116
117 let data_stream_registry = Arc::new(crate::inbound::DataStreamRegistry::new());
119 tracing::debug!("✨ Created DataStreamRegistry");
120
121 let media_frame_registry = Arc::new(crate::inbound::MediaFrameRegistry::new());
123 tracing::debug!("✨ Created MediaFrameRegistry");
124
125 let context_factory = ContextFactory::new(
127 inproc_gate,
128 shell_to_workload.clone(),
129 workload_to_shell.clone(),
130 data_stream_registry,
131 media_frame_registry,
132 signaling_client.clone(),
133 );
134
135 tracing::info!("✅ Inproc infrastructure initialized (bidirectional Shell ↔ Workload)");
136
137 tracing::info!("✅ ActrSystem initialized");
138
139 Ok(Self {
140 config,
141 mailbox,
142 dlq,
143 context_factory,
144 signaling_client,
145 })
146 }
147
148 pub fn attach<W: Workload>(self, workload: W) -> ActrNode<W> {
159 tracing::info!("📦 Attaching workload");
160
161 ActrNode {
162 config: self.config,
163 workload: Arc::new(workload),
164 mailbox: self.mailbox,
165 dlq: self.dlq,
166 context_factory: Some(self.context_factory), signaling_client: self.signaling_client,
168 actor_id: None, credential_state: None, psk: None, webrtc_coordinator: None, webrtc_gate: None, inproc_mgr: None, workload_to_shell_mgr: None, shutdown_token: tokio_util::sync::CancellationToken::new(),
176 }
177 }
178}