lexa_framework/application/
default.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ Copyright: (c) 2023, Mike 'PhiSyX' S. (https://github.com/PhiSyX)         ┃
3// ┃ SPDX-License-Identifier: MPL-2.0                                          ┃
4// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
5// ┃                                                                           ┃
6// ┃  This Source Code Form is subject to the terms of the Mozilla Public      ┃
7// ┃  License, v. 2.0. If a copy of the MPL was not distributed with this      ┃
8// ┃  file, You can obtain one at https://mozilla.org/MPL/2.0/.                ┃
9// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
10
11use std::path;
12
13use console::style;
14use lexa_wildcard_matching::WildcardMatching;
15
16use super::{env, interface, settings, ApplicationLoggerInterface};
17use crate::{ApplicationError, ApplicationInterface, Server};
18
19// --------- //
20// Structure //
21// --------- //
22
23pub struct DefaultApplication<UserEnv, UserCLI, UserState> {
24	/// Nom de l'application.
25	name: &'static str,
26
27	/// Version de l'application.
28	version: &'static str,
29
30	/// Répertoire racine de l'application
31	root_dir: path::PathBuf,
32
33	/// Mode d'exécution du programme.
34	process_mode: env::EnvProcessMode,
35
36	/// Les variables d'environnement de l'application.
37	env_vars: Option<UserEnv>,
38
39	/// Les arguments de utilisateur passé par la CLI.
40	cli_args: Option<UserCLI>,
41
42	/// Paramètres de la configuration
43	settings: settings::Settings,
44
45	/// Serveur
46	pub server: Server<UserState>,
47}
48
49// -------------- //
50// Implémentation //
51// -------------- //
52
53impl<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	/// Crée l'application par défaut.
63	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// -------------- //
139// Implémentation // -> Interface
140// -------------- //
141
142#[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	/// Définit le mode d'exécution du programme.
152	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}