1use crate::audit::AuditLog;
14use crate::bus::CommandBus;
15use crate::command::CommandRegistry;
16use crate::decision::{DecisionEngine, DecisionRegistry};
17use crate::error::{RuntimeError, RuntimeResult};
18use crate::event::EventRegistry;
19use crate::event_bus::EventBus;
20use crate::identity::RuntimeIdentity;
21use crate::ids::NodeId;
22use crate::lifecycle::RuntimeLifecycle;
23use crate::plugin::AppPlugin;
24use crate::runtime::RuntimeInstance;
25use crate::state::StateRegistry;
26use appcore_contracts::ApplicationManifestV1;
27
28#[derive(Debug, Default)]
30pub struct RuntimeBuilder {
31 application_manifest: Option<ApplicationManifestV1>,
32 identity: Option<RuntimeIdentity>,
33 command_registry: CommandRegistry,
34 event_registry: EventRegistry,
35 state_registry: StateRegistry,
36 decision_registry: DecisionRegistry,
37 decision_engine: DecisionEngine,
38 command_bus: CommandBus,
39 event_bus: EventBus,
40 audit_log: AuditLog,
41 lifecycle: RuntimeLifecycle,
42}
43
44impl RuntimeBuilder {
45 pub fn new() -> Self {
47 Self::default()
48 }
49
50 pub fn with_plugin<P: AppPlugin + ?Sized>(
52 &mut self,
53 plugin: &P,
54 node_id: NodeId,
55 ) -> RuntimeResult<&mut Self> {
56 if self.application_manifest.is_some() {
57 return Err(RuntimeError::PluginAlreadyRegistered);
58 }
59
60 let application_manifest = plugin.application_manifest();
61 let identity = plugin.identity(node_id);
62 plugin.register_commands(&mut self.command_registry)?;
63 plugin.register_events(&mut self.event_registry)?;
64 plugin.register_states(&mut self.state_registry)?;
65 plugin.register_decisions(&mut self.decision_registry)?;
66 plugin.register_decision_nodes(&mut self.decision_engine)?;
67 self.sync_decision_registry_with_engine()?;
68 plugin.register_handlers(&mut self.command_bus)?;
69 self.application_manifest = Some(application_manifest);
70 self.identity = Some(identity);
71
72 Ok(self)
73 }
74
75 pub fn with_additional_plugin<P: AppPlugin + ?Sized>(
77 &mut self,
78 plugin: &P,
79 ) -> RuntimeResult<&mut Self> {
80 plugin.register_commands(&mut self.command_registry)?;
81 plugin.register_events(&mut self.event_registry)?;
82 plugin.register_states(&mut self.state_registry)?;
83 plugin.register_decisions(&mut self.decision_registry)?;
84 plugin.register_decision_nodes(&mut self.decision_engine)?;
85 self.sync_decision_registry_with_engine()?;
86 plugin.register_handlers(&mut self.command_bus)?;
87 Ok(self)
88 }
89
90 fn sync_decision_registry_with_engine(&mut self) -> RuntimeResult<()> {
91 for name in self.decision_engine.node_names() {
92 if !self.decision_registry.contains(name) {
93 self.decision_registry.register_name(name)?;
94 }
95 }
96 Ok(())
97 }
98
99 pub fn application_manifest(&self) -> Option<&ApplicationManifestV1> {
101 self.application_manifest.as_ref()
102 }
103
104 pub fn commands(&self) -> &CommandRegistry {
106 &self.command_registry
107 }
108
109 pub fn events(&self) -> &EventRegistry {
111 &self.event_registry
112 }
113
114 pub fn states(&self) -> &StateRegistry {
116 &self.state_registry
117 }
118
119 pub fn decisions(&self) -> &DecisionRegistry {
121 &self.decision_registry
122 }
123
124 pub fn command_bus(&self) -> &CommandBus {
126 &self.command_bus
127 }
128
129 pub fn build(self) -> RuntimeResult<RuntimeInstance> {
131 let application_manifest = self
132 .application_manifest
133 .ok_or(RuntimeError::MissingManifest)?;
134 let identity = self.identity.ok_or(RuntimeError::MissingManifest)?;
135
136 Ok(RuntimeInstance {
137 application_manifest,
138 identity,
139 command_registry: self.command_registry,
140 event_registry: self.event_registry,
141 state_registry: self.state_registry,
142 decision_registry: self.decision_registry,
143 decision_engine: self.decision_engine,
144 command_bus: self.command_bus,
145 event_bus: self.event_bus,
146 audit_log: self.audit_log,
147 lifecycle: self.lifecycle,
148 })
149 }
150}
151
152#[cfg(test)]
153mod builder_tests;