lexa_framework/application/
default.rs1use std::path;
12
13use console::style;
14use lexa_wildcard_matching::WildcardMatching;
15
16use super::{env, interface, settings, ApplicationLoggerInterface};
17use crate::{ApplicationError, ApplicationInterface, Server};
18
19pub struct DefaultApplication<UserEnv, UserCLI, UserState> {
24 name: &'static str,
26
27 version: &'static str,
29
30 root_dir: path::PathBuf,
32
33 process_mode: env::EnvProcessMode,
35
36 env_vars: Option<UserEnv>,
38
39 cli_args: Option<UserCLI>,
41
42 settings: settings::Settings,
44
45 pub server: Server<UserState>,
47}
48
49impl<UE, UC, US> DefaultApplication<UE, UC, US>
54where
55 UE: 'static,
56 UE: interface::ApplicationEnvInterface,
57 UC: 'static,
58 UC: interface::ApplicationCLIInterface,
59 US: 'static,
60 US: crate::state::StateInterface,
61{
62 pub async fn create(
64 name: &'static str,
65 version: &'static str,
66 root_dir: impl AsRef<path::Path>,
67 loader_extension: impl Into<settings::SettingsLoaderExtension>,
68 ) -> Result<Self, ApplicationError> {
69 let path_root_dir = root_dir.as_ref();
70
71 let process_env_mode = if option_env!("DOCKER").is_some() {
72 env::EnvProcessMode::DEVELOPMENT
73 } else if cfg!(test) {
74 env::EnvProcessMode::TEST
75 } else if cfg!(debug_assertions) {
76 env::EnvProcessMode::LOCAL
77 } else {
78 env::EnvProcessMode::PRODUCTION
79 };
80
81 let settings = settings::Settings {
82 root_dir: path_root_dir.to_owned(),
83 config_dir: path_root_dir.join("config"),
84 loader_extension: loader_extension.into(),
85 process_env_mode,
86 };
87
88 let mut application = Self {
89 name,
90 version,
91 root_dir: path_root_dir.to_owned(),
92 server: Server::new(settings.clone()).await?,
93 settings,
94 process_mode: Default::default(),
95 cli_args: Default::default(),
96 env_vars: Default::default(),
97 };
98
99 application = application
100 .define_process_mode(process_env_mode)
101 .using_logger()?
102 .with_cli_args()
103 .with_env_vars()?;
104
105 Ok(application)
106 }
107
108 pub fn routes(&self) -> impl Iterator<Item = &crate::routing::Route<US>> {
109 self.server.routes.all()
110 }
111
112 pub fn state(&self) -> crate::state::State<US> {
113 self.server.state.clone()
114 }
115
116 pub async fn run(mut self) -> Result<(), ApplicationError> {
117 log::debug!(
118 "Application: {}@{} ({})",
119 self.name,
120 style(self.version).blue(),
121 style(self.root_dir.display()).yellow(),
122 );
123
124 if let Some(cli_args) = self.cli_args {
125 self.server.router =
126 self.server.router.layer(axum::Extension(cli_args));
127 }
128
129 if let Some(env_vars) = self.env_vars {
130 self.server.router =
131 self.server.router.layer(axum::Extension(env_vars));
132 }
133
134 Ok(self.server.run().await?)
135 }
136}
137
138#[async_trait::async_trait]
143impl<UE, UC, US> ApplicationInterface for DefaultApplication<UE, UC, US>
144where
145 UE: interface::ApplicationEnvInterface,
146 UC: interface::ApplicationCLIInterface,
147{
148 type CLI = UC;
149 type ENV = UE;
150
151 fn define_process_mode(mut self, mode: env::EnvProcessMode) -> Self
153 where
154 Self: Sized,
155 {
156 self.process_mode = mode;
157 self
158 }
159
160 fn with_cli_args(mut self) -> Self {
161 let args = Self::CLI::arguments();
162 self.cli_args = Some(args);
163 self
164 }
165
166 fn with_env_vars(mut self) -> Result<Self, ApplicationError> {
167 let vars = Self::ENV::setup(&self.settings)?;
168 self.env_vars = Some(vars);
169 Ok(self)
170 }
171
172 fn cli_args(&self) -> &Self::CLI {
173 self.cli_args.as_ref().unwrap()
174 }
175
176 fn env_vars(&self) -> &Self::ENV {
177 self.env_vars.as_ref().unwrap()
178 }
179}
180
181impl<UE, UC, US> ApplicationLoggerInterface for DefaultApplication<UE, UC, US> {
182 fn using_logger(self) -> Result<Self, ApplicationError> {
183 let logger_settings: settings::LoggerSettings =
184 lexa_fs::load_or_default(
185 &self.settings.config_dir,
186 "logger",
187 self.settings.loader_extension,
188 );
189 let logger_settings = logger_settings.settings();
190
191 let mut logger = lexa_logger::stdout::Logger::builder();
192
193 logger = logger.with_level(logger_settings.max_level);
194
195 if logger_settings.colorized {
196 logger = logger.with_color();
197 }
198 if logger_settings.timestamp {
199 logger = logger.with_timestamp();
200 }
201
202 for filter in logger_settings.target_filters {
203 logger =
204 logger.filter(move |metadata| metadata.target().iswm(&filter));
205 }
206
207 logger.build_stdout()?;
208
209 Ok(self)
210 }
211}