1use std::{
2 any::Any,
3 fmt::Display,
4 future::Future,
5 sync::{Arc, OnceLock},
6};
7
8use config::Config;
9use dashmap::DashMap;
10use fusion_common::ahash::HashSet;
11use log::{debug, info};
12use mea::{
13 mutex::Mutex,
14 shutdown::{ShutdownRecv, ShutdownSend},
15};
16use serde::de::DeserializeOwned;
17
18use fusion_common::time::OffsetDateTime;
19
20use crate::{
21 Result,
22 component::{ComponentArc, ComponentError, ComponentResult, DynComponentArc, auto_inject_component},
23 configuration::{ConfigRegistry, Configurable, ConfigureResult, FusionConfigRegistry, FusionSetting},
24 log::LogPlugin,
25 plugin::{Plugin, PluginRef},
26};
27
28type Registry<T> = DashMap<String, T>;
29type Task<T> = dyn FnOnce(Application) -> Box<dyn Future<Output = Result<T>> + Send>;
30
31pub(crate) struct ApplicationInner {
32 config_registry: FusionConfigRegistry,
33 components: Registry<DynComponentArc>,
34 start_time: OffsetDateTime,
35 pub(crate) shutdown: Mutex<Option<(ShutdownSend, ShutdownRecv)>>,
36}
37
38#[derive(Clone)]
40pub struct Application(pub(crate) Arc<ApplicationInner>);
41
42impl Display for Application {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "Application({}|{})", self.fusion_setting().app().name(), self.0.start_time)
45 }
46}
47
48impl Application {
49 pub fn builder() -> ApplicationBuilder {
50 ApplicationBuilder::default()
51 }
52
53 pub fn global() -> Application {
54 GLOBAL_APPLICATION.get().expect("Application is not initialized").clone()
55 }
56
57 pub fn set_global(application: Application) {
58 match GLOBAL_APPLICATION.set(application) {
59 Ok(_) => (),
60 Err(old) => {
61 panic!("Global application was already set to {}", old)
62 }
63 }
64 }
65
66 pub async fn shutdown() {
67 let app = Self::global();
68 if let Some((shutdown_tx, _)) = app.0.shutdown.lock().await.as_ref() {
69 shutdown_tx.shutdown();
70 }
71 }
72
73 pub async fn await_shutdown() -> bool {
74 let app = Self::global();
75 if let Some((shutdown_tx, shutdown_rx)) = app.0.shutdown.lock().await.take() {
76 drop(shutdown_rx);
77 shutdown_tx.await_shutdown().await;
78 true
79 } else {
80 false
81 }
82 }
83
84 pub async fn is_shutdown(&self) -> bool {
85 self.0.shutdown.lock().await.is_none()
86 }
87
88 pub async fn shutdown_recv(&self) -> ShutdownRecv {
89 let maybe = self.0.shutdown.lock().await;
90 let tuple = maybe.as_ref().unwrap();
91 tuple.1.clone()
92 }
93
94 pub fn config_registry(&self) -> &FusionConfigRegistry {
95 &self.0.config_registry
96 }
97
98 #[inline]
100 pub fn get_component_arc<T>(&self) -> ComponentResult<ComponentArc<T>>
101 where
102 T: Any + Send + Sync,
103 {
104 self.get_component_ref_by_name(std::any::type_name::<T>())
105 }
106
107 pub fn component_arc<T>(&self) -> ComponentArc<T>
108 where
109 T: Any + Send + Sync,
110 {
111 let component_name = std::any::type_name::<T>();
112 match self.get_component_ref_by_name(component_name) {
113 Ok(c) => c,
114 Err(e) => panic!("{:?}", e),
115 }
116 }
117
118 pub fn get_component_ref_by_name<T>(&self, component_name: &str) -> ComponentResult<ComponentArc<T>>
119 where
120 T: Any + Send + Sync,
121 {
122 let pair = match self.0.components.get(component_name) {
123 Some(pair) => pair,
124 None => return Err(ComponentError::ComponentNotFound(component_name.to_string())),
125 };
126 let component_ref = pair.value().clone();
127 component_ref.downcast::<T>()
128 }
129
130 pub fn component<T>(&self) -> T
131 where
132 T: Clone + Send + Sync + 'static,
133 {
134 match self.get_component() {
135 Ok(c) => c,
136 Err(e) => panic!("{:?}", e),
137 }
138 }
139
140 pub fn get_component<T>(&self) -> ComponentResult<T>
142 where
143 T: Clone + Send + Sync + 'static,
144 {
145 let component_ref = self.get_component_arc();
146 component_ref.map(|c| T::clone(&c))
147 }
148
149 pub fn get_component_names(&self) -> Vec<String> {
151 self.0.components.iter().map(|e| e.key().clone()).collect()
152 }
153
154 pub fn add_component<T>(&self, component: T)
155 where
156 T: Clone + Any + Send + Sync,
157 {
158 let component_name = std::any::type_name::<T>();
159 if self.0.components.contains_key(component_name) {
160 panic!("Error adding component {component_name}: component was already added in application")
161 }
162 self.0.components.insert(component_name.to_string(), DynComponentArc::new(component));
163
164 debug!("added component: {}", component_name);
165 }
166
167 pub fn fusion_setting(&self) -> Arc<FusionSetting> {
168 self.0.config_registry.fusion_setting()
169 }
170
171 pub fn underlying_config(&self) -> Arc<Config> {
173 self.0.config_registry.config()
174 }
175
176 pub fn start_time(&self) -> &OffsetDateTime {
177 &self.0.start_time
178 }
179}
180
181impl ConfigRegistry for Application {
182 fn get_config<T>(&self) -> ConfigureResult<T>
183 where
184 T: DeserializeOwned + Configurable,
185 {
186 self.0.config_registry.get_config()
187 }
188
189 fn get_config_by_path<T>(&self, path: &str) -> ConfigureResult<T>
190 where
191 T: DeserializeOwned,
192 {
193 self.0.config_registry.get_config_by_path(path)
194 }
195}
196
197static GLOBAL_APPLICATION: OnceLock<Application> = OnceLock::new();
198
199#[derive(Default)]
200pub struct ApplicationBuilder {
201 config_registry: FusionConfigRegistry,
202
203 pub(crate) plugin_registry: Registry<PluginRef>,
205
206 pub(crate) components: Registry<DynComponentArc>,
208
209 shutdown_hooks: Vec<Box<Task<String>>>,
211}
212
213unsafe impl Send for ApplicationBuilder {}
214unsafe impl Sync for ApplicationBuilder {}
215
216impl ApplicationBuilder {
217 pub fn get_fusion_config(&self) -> Arc<FusionSetting> {
218 self.config_registry.fusion_setting()
219 }
220
221 pub fn with_config_registry(&mut self, config_registry: FusionConfigRegistry) -> &Self {
222 self.config_registry = config_registry;
223 self
224 }
225
226 pub fn add_config_source<T>(&mut self, source: T) -> &mut Self
228 where
229 T: config::Source + Send + Sync + 'static,
230 {
231 self.config_registry.add_config_source(source).expect("Add config source failed");
232 self
233 }
234
235 pub fn add_plugin<T: Plugin>(&mut self, plugin: T) -> &mut Self {
237 let plugin_name = plugin.name().to_string();
238 debug!("added plugin: {plugin_name}");
239
240 if plugin.immediately() {
241 plugin.immediately_build(self);
242 return self;
243 }
244 if self.plugin_registry.contains_key(plugin.name()) {
245 panic!("Error adding plugin {plugin_name}: plugin was already added in application")
246 }
247 self.plugin_registry.insert(plugin_name, PluginRef::new(plugin));
248 self
249 }
250
251 #[inline]
253 pub fn contains_plugin<T: Plugin>(&self) -> bool {
254 self.plugin_registry.contains_key(std::any::type_name::<T>())
255 }
256
257 pub fn add_component<T>(&mut self, component: T) -> &mut Self
259 where
260 T: Clone + Any + Send + Sync,
261 {
262 let component_name = std::any::type_name::<T>();
263 if self.components.contains_key(component_name) {
264 panic!("Error adding component {component_name}: component was already added in application builder")
265 }
266 self.components.insert(component_name.to_string(), DynComponentArc::new(component));
267
268 debug!("added component: {}", component_name);
269 self
270 }
271
272 pub fn get_component_ref<T>(&self) -> ComponentResult<ComponentArc<T>>
274 where
275 T: Any + Send + Sync,
276 {
277 let component_name = std::any::type_name::<T>();
278 let pair = match self.components.get(component_name) {
279 Some(pair) => pair,
280 None => return Err(ComponentError::ComponentNotFound(component_name.to_string())),
281 };
282 let component_ref = pair.value().clone();
283 component_ref.downcast::<T>()
284 }
285
286 pub fn component<T>(&self) -> T
287 where
288 T: Clone + Send + Sync + 'static,
289 {
290 match self.get_component() {
291 Ok(c) => c,
292 Err(e) => panic!("{:?}", e),
293 }
294 }
295
296 pub fn get_component<T>(&self) -> ComponentResult<T>
298 where
299 T: Clone + Send + Sync + 'static,
300 {
301 let component_ref = self.get_component_ref();
302 component_ref.map(|c| T::clone(&c))
303 }
304
305 pub fn add_shutdown_hook<T>(&mut self, hook: T) -> &mut Self
307 where
308 T: FnOnce(Application) -> Box<dyn Future<Output = Result<String>> + Send> + 'static,
309 {
310 self.shutdown_hooks.push(Box::new(hook));
311 self
312 }
313
314 pub async fn run(&mut self) -> Result<Application> {
318 self.inner_run().await
319 }
320
321 async fn inner_run(&mut self) -> Result<Application> {
322 let app = self.build().await?;
323
324 Ok(app)
328 }
329
330 pub async fn build(&mut self) -> Result<Application> {
333 self.build_plugins().await?;
338
339 auto_inject_component(self)?;
341
342 let application = self.build_application();
344
345 Application::set_global(application);
346 Ok(Application::global())
347 }
348
349 async fn build_plugins(&mut self) -> Result<()> {
351 self.add_plugin(LogPlugin);
352
353 let registry = std::mem::take(&mut self.plugin_registry);
354 let mut to_register = registry.iter().map(|e| e.value().to_owned()).collect::<Vec<_>>();
355 let mut registered: HashSet<String> = HashSet::default();
356
357 while !to_register.is_empty() {
358 let mut progress = false;
359 let mut next_round = vec![];
360
361 for plugin in to_register {
362 let deps = plugin.dependencies();
363 if deps.iter().all(|dep| registered.contains(*dep)) {
364 plugin.build(self).await;
365 registered.insert(plugin.name().to_string());
366 info!("{} plugin registered", plugin.name());
367 progress = true;
368 } else {
369 next_round.push(plugin);
370 }
371 }
372
373 if !progress {
374 panic!("Cyclic dependency detected or missing dependencies for some plugins");
375 }
376
377 to_register = next_round;
378 }
379
380 self.plugin_registry = registry;
381 Ok(())
382 }
383
384 fn build_application(&mut self) -> Application {
385 let components = std::mem::take(&mut self.components);
386 let configuration_state = std::mem::take(&mut self.config_registry);
387 let init_time = configuration_state.fusion_setting().app().time_now();
388 let shutdown = Mutex::new(Some(mea::shutdown::new_pair()));
389 Application(Arc::new(ApplicationInner {
390 config_registry: configuration_state,
391 components,
392 start_time: init_time,
393 shutdown,
394 }))
395 }
396}
397
398impl ConfigRegistry for ApplicationBuilder {
399 fn get_config<T>(&self) -> ConfigureResult<T>
400 where
401 T: DeserializeOwned + Configurable,
402 {
403 self.config_registry.get_config::<T>()
404 }
405
406 fn get_config_by_path<T>(&self, path: &str) -> ConfigureResult<T>
407 where
408 T: DeserializeOwned,
409 {
410 self.config_registry.get_config_by_path::<T>(path)
411 }
412}
413#[cfg(test)]
414mod tests {
415 use fusion_common::env::remove_envs;
416
417 use super::*;
418
419 #[tokio::test]
420 async fn test_application_run() {
421 remove_envs(&[
422 "FUSION__APP__NAME",
423 "FUSION__WEB__SERVER_ADDR",
424 "FUSION__SECURITY__TOKEN__SECRET_KEY",
425 "FUSION__SECURITY__PWD__PWD_KEY",
426 ])
427 .unwrap();
428 Application::builder().run().await.unwrap();
429 let app = Application::global();
430 assert_eq!(app.fusion_setting().app().name(), "fusion");
431 }
432}