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 {
87 RuntimeLifecycleState::Booting => "Booting",
88 RuntimeLifecycleState::LoadingConfig => "LoadingConfig",
89 RuntimeLifecycleState::CheckingSecurity => "CheckingSecurity",
90 RuntimeLifecycleState::OpeningStorage => "OpeningStorage",
91 RuntimeLifecycleState::StartingApi => "StartingApi",
92 RuntimeLifecycleState::Running => "Running",
93 RuntimeLifecycleState::Degraded => "Degraded",
94 RuntimeLifecycleState::Restricted => "Restricted",
95 RuntimeLifecycleState::ShuttingDown => "ShuttingDown",
96 RuntimeLifecycleState::Stopped => "Stopped",
97 })
98 .unwrap()
99 }
100
101 fn from_state_name(state: &StateName) -> RuntimeResult<Self> {
102 match state.as_str() {
103 "Booting" => Ok(Self::Booting),
104 "LoadingConfig" => Ok(Self::LoadingConfig),
105 "CheckingSecurity" => Ok(Self::CheckingSecurity),
106 "OpeningStorage" => Ok(Self::OpeningStorage),
107 "StartingApi" => Ok(Self::StartingApi),
108 "Running" => Ok(Self::Running),
109 "Degraded" => Ok(Self::Degraded),
110 "Restricted" => Ok(Self::Restricted),
111 "ShuttingDown" => Ok(Self::ShuttingDown),
112 "Stopped" => Ok(Self::Stopped),
113 _ => Err(RuntimeError::InvalidStateTransition),
114 }
115 }
116}
117
118impl RuntimeLifecycleEvent {
119 fn as_event_name(self) -> EventName {
120 EventName::new(match self {
122 RuntimeLifecycleEvent::ConfigLoaded => "ConfigLoaded",
123 RuntimeLifecycleEvent::SecurityChecked => "SecurityChecked",
124 RuntimeLifecycleEvent::StorageOpened => "StorageOpened",
125 RuntimeLifecycleEvent::ApiStarted => "ApiStarted",
126 RuntimeLifecycleEvent::DegradedDetected => "DegradedDetected",
127 RuntimeLifecycleEvent::RestrictedDetected => "RestrictedDetected",
128 RuntimeLifecycleEvent::ShutdownRequested => "ShutdownRequested",
129 RuntimeLifecycleEvent::ShutdownCompleted => "ShutdownCompleted",
130 RuntimeLifecycleEvent::RecoveryCompleted => "RecoveryCompleted",
131 })
132 .unwrap()
133 }
134}
135
136impl RuntimeLifecycle {
137 pub fn new() -> Self {
139 let mut machine = StateMachine::new(RuntimeLifecycleState::Booting.as_state_name());
143 let transitions = vec![
144 (
145 RuntimeLifecycleState::Booting,
146 RuntimeLifecycleEvent::ConfigLoaded,
147 RuntimeLifecycleState::CheckingSecurity,
148 ),
149 (
150 RuntimeLifecycleState::CheckingSecurity,
151 RuntimeLifecycleEvent::SecurityChecked,
152 RuntimeLifecycleState::OpeningStorage,
153 ),
154 (
155 RuntimeLifecycleState::OpeningStorage,
156 RuntimeLifecycleEvent::StorageOpened,
157 RuntimeLifecycleState::StartingApi,
158 ),
159 (
160 RuntimeLifecycleState::StartingApi,
161 RuntimeLifecycleEvent::ApiStarted,
162 RuntimeLifecycleState::Running,
163 ),
164 (
165 RuntimeLifecycleState::Running,
166 RuntimeLifecycleEvent::DegradedDetected,
167 RuntimeLifecycleState::Degraded,
168 ),
169 (
170 RuntimeLifecycleState::Running,
171 RuntimeLifecycleEvent::RestrictedDetected,
172 RuntimeLifecycleState::Restricted,
173 ),
174 (
175 RuntimeLifecycleState::Degraded,
176 RuntimeLifecycleEvent::RecoveryCompleted,
177 RuntimeLifecycleState::Running,
178 ),
179 (
180 RuntimeLifecycleState::Restricted,
181 RuntimeLifecycleEvent::RecoveryCompleted,
182 RuntimeLifecycleState::Running,
183 ),
184 (
185 RuntimeLifecycleState::Running,
186 RuntimeLifecycleEvent::ShutdownRequested,
187 RuntimeLifecycleState::ShuttingDown,
188 ),
189 (
190 RuntimeLifecycleState::Degraded,
191 RuntimeLifecycleEvent::ShutdownRequested,
192 RuntimeLifecycleState::ShuttingDown,
193 ),
194 (
195 RuntimeLifecycleState::Restricted,
196 RuntimeLifecycleEvent::ShutdownRequested,
197 RuntimeLifecycleState::ShuttingDown,
198 ),
199 (
200 RuntimeLifecycleState::ShuttingDown,
201 RuntimeLifecycleEvent::ShutdownCompleted,
202 RuntimeLifecycleState::Stopped,
203 ),
204 ];
205
206 for (from, event, to) in transitions {
207 let _ = machine.add_transition(StateTransition {
208 from: from.as_state_name(),
209 event: event.as_event_name(),
210 to: to.as_state_name(),
211 });
212 }
213
214 Self {
215 machine: Mutex::new(machine),
216 }
217 }
218
219 pub fn current(&self) -> RuntimeLifecycleState {
221 let guard = self.machine.lock();
222 match RuntimeLifecycleState::from_state_name(guard.current()) {
223 Ok(state) => state,
224 Err(_) => RuntimeLifecycleState::Booting,
225 }
226 }
227
228 pub fn apply(&self, event: RuntimeLifecycleEvent) -> RuntimeResult<RuntimeLifecycleState> {
230 let mut guard = self.machine.lock();
231 let next = guard.apply(&event.as_event_name())?;
232 RuntimeLifecycleState::from_state_name(next)
233 }
234
235 pub fn is_running(&self) -> bool {
237 self.current() == RuntimeLifecycleState::Running
238 }
239
240 pub fn is_stopped(&self) -> bool {
242 self.current() == RuntimeLifecycleState::Stopped
243 }
244
245 pub fn is_restricted(&self) -> bool {
247 self.current() == RuntimeLifecycleState::Restricted
248 }
249}
250
251impl Default for RuntimeLifecycle {
252 fn default() -> Self {
253 Self::new()
254 }
255}
256
257#[cfg(test)]
258#[path = "lifecycle_tests.rs"]
259mod tests;