1use crate::error::{RuntimeError, RuntimeResult};
14use crate::ids::{EventName, StateName};
15use crate::state::{StateMachine, StateTransition};
16use parking_lot::Mutex;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum RuntimeLifecycleState {
23 Booting,
25 LoadingConfig,
27 CheckingSecurity,
29 OpeningStorage,
31 StartingApi,
33 Running,
35 Degraded,
37 Restricted,
39 ShuttingDown,
41 Stopped,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum RuntimeLifecycleEvent {
48 ConfigLoaded,
50 SecurityChecked,
52 StorageOpened,
54 ApiStarted,
56 DegradedDetected,
58 RestrictedDetected,
60 ShutdownRequested,
62 ShutdownCompleted,
64 RecoveryCompleted,
66}
67
68#[derive(Debug)]
70pub struct RuntimeLifecycle {
71 machine: Mutex<StateMachine>,
72}
73
74impl Clone for RuntimeLifecycle {
75 fn clone(&self) -> Self {
76 let guard = self.machine.lock();
77 Self {
78 machine: Mutex::new(guard.clone()),
79 }
80 }
81}
82
83impl RuntimeLifecycleState {
84 fn as_state_name(self) -> StateName {
85 StateName::new(match self {
86 RuntimeLifecycleState::Booting => "Booting",
87 RuntimeLifecycleState::LoadingConfig => "LoadingConfig",
88 RuntimeLifecycleState::CheckingSecurity => "CheckingSecurity",
89 RuntimeLifecycleState::OpeningStorage => "OpeningStorage",
90 RuntimeLifecycleState::StartingApi => "StartingApi",
91 RuntimeLifecycleState::Running => "Running",
92 RuntimeLifecycleState::Degraded => "Degraded",
93 RuntimeLifecycleState::Restricted => "Restricted",
94 RuntimeLifecycleState::ShuttingDown => "ShuttingDown",
95 RuntimeLifecycleState::Stopped => "Stopped",
96 })
97 .unwrap()
98 }
99
100 fn from_state_name(state: &StateName) -> RuntimeResult<Self> {
101 match state.as_str() {
102 "Booting" => Ok(Self::Booting),
103 "LoadingConfig" => Ok(Self::LoadingConfig),
104 "CheckingSecurity" => Ok(Self::CheckingSecurity),
105 "OpeningStorage" => Ok(Self::OpeningStorage),
106 "StartingApi" => Ok(Self::StartingApi),
107 "Running" => Ok(Self::Running),
108 "Degraded" => Ok(Self::Degraded),
109 "Restricted" => Ok(Self::Restricted),
110 "ShuttingDown" => Ok(Self::ShuttingDown),
111 "Stopped" => Ok(Self::Stopped),
112 _ => Err(RuntimeError::InvalidStateTransition),
113 }
114 }
115}
116
117impl RuntimeLifecycleEvent {
118 fn as_event_name(self) -> EventName {
119 EventName::new(match self {
120 RuntimeLifecycleEvent::ConfigLoaded => "ConfigLoaded",
121 RuntimeLifecycleEvent::SecurityChecked => "SecurityChecked",
122 RuntimeLifecycleEvent::StorageOpened => "StorageOpened",
123 RuntimeLifecycleEvent::ApiStarted => "ApiStarted",
124 RuntimeLifecycleEvent::DegradedDetected => "DegradedDetected",
125 RuntimeLifecycleEvent::RestrictedDetected => "RestrictedDetected",
126 RuntimeLifecycleEvent::ShutdownRequested => "ShutdownRequested",
127 RuntimeLifecycleEvent::ShutdownCompleted => "ShutdownCompleted",
128 RuntimeLifecycleEvent::RecoveryCompleted => "RecoveryCompleted",
129 })
130 .unwrap()
131 }
132}
133
134impl RuntimeLifecycle {
135 pub fn new() -> Self {
137 let mut machine = StateMachine::new(RuntimeLifecycleState::Booting.as_state_name());
141 let transitions = vec![
142 (
143 RuntimeLifecycleState::Booting,
144 RuntimeLifecycleEvent::ConfigLoaded,
145 RuntimeLifecycleState::CheckingSecurity,
146 ),
147 (
148 RuntimeLifecycleState::CheckingSecurity,
149 RuntimeLifecycleEvent::SecurityChecked,
150 RuntimeLifecycleState::OpeningStorage,
151 ),
152 (
153 RuntimeLifecycleState::OpeningStorage,
154 RuntimeLifecycleEvent::StorageOpened,
155 RuntimeLifecycleState::StartingApi,
156 ),
157 (
158 RuntimeLifecycleState::StartingApi,
159 RuntimeLifecycleEvent::ApiStarted,
160 RuntimeLifecycleState::Running,
161 ),
162 (
163 RuntimeLifecycleState::Running,
164 RuntimeLifecycleEvent::DegradedDetected,
165 RuntimeLifecycleState::Degraded,
166 ),
167 (
168 RuntimeLifecycleState::Running,
169 RuntimeLifecycleEvent::RestrictedDetected,
170 RuntimeLifecycleState::Restricted,
171 ),
172 (
173 RuntimeLifecycleState::Degraded,
174 RuntimeLifecycleEvent::RecoveryCompleted,
175 RuntimeLifecycleState::Running,
176 ),
177 (
178 RuntimeLifecycleState::Restricted,
179 RuntimeLifecycleEvent::RecoveryCompleted,
180 RuntimeLifecycleState::Running,
181 ),
182 (
183 RuntimeLifecycleState::Running,
184 RuntimeLifecycleEvent::ShutdownRequested,
185 RuntimeLifecycleState::ShuttingDown,
186 ),
187 (
188 RuntimeLifecycleState::Degraded,
189 RuntimeLifecycleEvent::ShutdownRequested,
190 RuntimeLifecycleState::ShuttingDown,
191 ),
192 (
193 RuntimeLifecycleState::Restricted,
194 RuntimeLifecycleEvent::ShutdownRequested,
195 RuntimeLifecycleState::ShuttingDown,
196 ),
197 (
198 RuntimeLifecycleState::ShuttingDown,
199 RuntimeLifecycleEvent::ShutdownCompleted,
200 RuntimeLifecycleState::Stopped,
201 ),
202 ];
203
204 for (from, event, to) in transitions {
205 let _ = machine.add_transition(StateTransition {
206 from: from.as_state_name(),
207 event: event.as_event_name(),
208 to: to.as_state_name(),
209 });
210 }
211
212 Self {
213 machine: Mutex::new(machine),
214 }
215 }
216
217 pub fn current(&self) -> RuntimeLifecycleState {
219 let guard = self.machine.lock();
220 match RuntimeLifecycleState::from_state_name(guard.current()) {
221 Ok(state) => state,
222 Err(_) => RuntimeLifecycleState::Booting,
223 }
224 }
225
226 pub fn apply(&self, event: RuntimeLifecycleEvent) -> RuntimeResult<RuntimeLifecycleState> {
228 let mut guard = self.machine.lock();
229 let next = guard.apply(&event.as_event_name())?;
230 RuntimeLifecycleState::from_state_name(next)
231 }
232
233 pub fn is_running(&self) -> bool {
235 self.current() == RuntimeLifecycleState::Running
236 }
237
238 pub fn is_stopped(&self) -> bool {
240 self.current() == RuntimeLifecycleState::Stopped
241 }
242
243 pub fn is_restricted(&self) -> bool {
245 self.current() == RuntimeLifecycleState::Restricted
246 }
247}
248
249impl Default for RuntimeLifecycle {
250 fn default() -> Self {
251 Self::new()
252 }
253}
254
255#[cfg(test)]
256#[path = "lifecycle_tests.rs"]
257mod tests;