Habilita a módulos inicializar su conf. predet.

This commit is contained in:
Manuel Cillero 2022-10-19 23:41:45 +02:00
parent 466ea97186
commit 81852a66c8
5 changed files with 86 additions and 42 deletions

View file

@ -38,6 +38,9 @@ impl Application {
// Registra acciones de los módulos. // Registra acciones de los módulos.
module::all::register_actions(); module::all::register_actions();
// Inicializa valores predefinidos de configuración.
module::all::init_settings();
// Inicializa los módulos. // Inicializa los módulos.
module::all::init_modules(); module::all::init_modules();

View file

@ -1,34 +1,32 @@
//! Gestión de la configuración. //! Gestión de la configuración.
//! //!
//! Carga la configuración de la aplicación en forma de pares `clave = valor` incluidos en archivos //! Carga durante el arranque la configuración de la aplicación en forma de pares `clave = valor`
//! [TOML](https://toml.io). //! recogidos en archivos [TOML](https://toml.io).
//! //!
//! La metodología [The Twelve-Factor App](https://12factor.net/es/) define **la configuración de //! La metodología [The Twelve-Factor App](https://12factor.net/es/) define **la configuración de
//! una aplicación como todo lo que puede variar entre despliegues**, distinguiendo entornos de //! una aplicación como todo lo que puede variar entre despliegues**, diferenciando entre entornos
//! desarrollo, pre-producción, producción, etc. //! de desarrollo, pre-producción, producción, etc.
//! //!
//! A veces las aplicaciones guardan configuraciones como constantes en el código, lo que supone una //! A veces las aplicaciones guardan configuraciones como constantes en el código, lo que supone una
//! violación de esta metodología. Es necesaria una **estricta separación de configuración y //! violación de esta metodología. Debe existir una **estricta separación entre la configuración y
//! código**. La configuración varía sustancialmente en cada despliegue, el código no. //! el código**. La configuración variará sustancialmente en cada despliegue, el código no.
//! //!
//! PageTop aplica estos principios cargando la configuración asociada al modo de ejecución activo. //! # Cómo usar archivos de configuración
//! //!
//! # ¿Cómo usar los archivos de configuración? //! Si tu aplicación requiere archivos de configuración debes crear un directorio llamado *config* al
//!
//! Si tu aplicación requiere ajustes de configuración debes crear un directorio llamado *config* al
//! mismo nivel del archivo *Cargo.toml* de tu proyecto (o del ejecutable binario de la aplicación). //! mismo nivel del archivo *Cargo.toml* de tu proyecto (o del ejecutable binario de la aplicación).
//! //!
//! Guarda la configuración usando archivos TOML asumiendo el siguiente orden de lectura secuencial //! Guarda la configuración usando archivos TOML asumiendo el siguiente orden de lectura secuencial
//! (todos los archivos son opcionales): //! (todos los archivos son opcionales):
//! //!
//! 1. *config/common.toml*, útil para asignar los valores comunes a cualquier entorno. Estos //! 1. *config/common.toml*, útil para los ajustes comunes para cualquier entorno. Estos valores
//! valores pueden ser modificados al fusionar los archivos de configuración siguientes. //! podrán ser sobrescritos al fusionar los archivos de configuración siguientes.
//! //!
//! 2. *config/{archivo}.toml*, donde *{archivo}* puede definirse mediante la variable de entorno //! 2. *config/{archivo}.toml*, donde *{archivo}* puede definirse mediante la variable de entorno
//! PAGETOP_RUN_MODE: //! PAGETOP_RUN_MODE:
//! //!
//! * Si no está definida, se asumirá *default* como nombre predeterminado y PageTop cargará el //! * Si no está definida, se asumirá *default* por defecto, y PageTop cargará el archivo de
//! archivo de configuración *config/default.toml* si existe. //! configuración *config/default.toml* si existe.
//! //!
//! * De esta manera, se pueden tener diferentes ajustes de configuración para diferentes //! * De esta manera, se pueden tener diferentes ajustes de configuración para diferentes
//! entornos de ejecución. Por ejemplo, para *devel.toml*, *staging.toml* o *production.toml*. //! entornos de ejecución. Por ejemplo, para *devel.toml*, *staging.toml* o *production.toml*.
@ -40,30 +38,53 @@
//! //!
//! 3. *config/local.toml*, para añadir o sobrescribir ajustes. //! 3. *config/local.toml*, para añadir o sobrescribir ajustes.
//! //!
//! # ¿Cómo añadir valores de configuración predeterminados? //! # Cómo añadir valores predefinidos de configuración
//!
//! Si nuestra **aplicación** o **módulo** requiere sus propios ajustes de configuración, es
//! recomendable (aunque no imprescindible) inicializarlos antes de su uso.
//!
//! Sólo tienes que añadir el método [`settings()`](crate::core::module::ModuleTrait::settings) al
//! implementar [`ModuleTrait`](crate::core::module::ModuleTrait) para tu módulo, devolviendo los
//! nuevos valores predefinidos con la macro [`predefined_settings!`].
//!
//! Cuando se carga la configuración de la aplicación, estos valores podrán ser sobrescritos con los
//! ajustes personalizados del entorno. Y sólo será realmente necesario incluir en los archivos de
//! configuración los ajustes que difieran de los predefinidos.
//! //!
//! ``` //! ```
//! use pagetop::{config, default_settings}; //! use pagetop::prelude::*;
//! //!
//! // Una aplicación o un módulo podrá añadir nuevos valores de configuración predeterminados. //! pub_const_handler!(MY_MODULE_HANDLER);
//! config::add_defaults(default_settings![ //!
//! // [my_app] //! pub struct MyModule;
//! "my_app.test_1" => "Test 1", //!
//! "my_app.test_2" => "Test 2", //! impl ModuleTrait for MyModule {
//! "my_app.passwd" => "Pass_1234", //! fn handler(&self) -> Handler {
//! ]); //! MY_MODULE_HANDLER
//! }
//!
//! fn settings(&self) -> PredefinedSettings {
//! predefined_settings![
//! // Valores predefinidos para "my_module".
//! "my_module.name" => "Name",
//! "my_module.desc" => "Description",
//! // Valores predefinidos para "my_module.database".
//! "my_module.database.db_port" => "3306"
//! ]
//! }
//! }
//! ``` //! ```
//! //!
//! # ¿Cómo leer los valores de configuración? //! # Cómo obtener los valores de configuración
//! //!
//! ``` //! ```
//! use pagetop::config; //! use pagetop::config;
//! //!
//! // Obtiene el valor (String) de una clave. //! // Obtiene el valor (String) de una clave.
//! let app_name: String = config::get("app.name"); //! let name: String = config::get("my_module.name");
//! //!
//! // Obtiene el valor (del tipo especificado) de una clave. //! // Obtiene el valor (del tipo especificado) de una clave.
//! let db_port: u16 = config::get_value::<u16>("database.db_port"); //! let db_port: u16 = config::get_value::<u16>("my_module.database.db_port");
//! ``` //! ```
use crate::{trace, LazyStatic}; use crate::{trace, LazyStatic};
@ -77,9 +98,12 @@ use std::fmt::Debug;
use std::str::FromStr; use std::str::FromStr;
use std::sync::RwLock; use std::sync::RwLock;
pub type PredefinedSettings = HashMap<&'static str, &'static str>;
#[macro_export] #[macro_export]
macro_rules! default_settings { macro_rules! predefined_settings {
( $($key:literal => $value:literal),* ) => {{ ( $($key:literal => $value:literal),* ) => {{
#[allow(unused_mut)]
let mut a = std::collections::HashMap::new(); let mut a = std::collections::HashMap::new();
$( $(
a.insert($key, $value); a.insert($key, $value);
@ -120,8 +144,8 @@ static CONFIG: LazyStatic<Config> = LazyStatic::new(|| {
.unwrap() .unwrap()
}); });
static DEFAULTS: LazyStatic<RwLock<HashMap<&str, &str>>> = LazyStatic::new(|| static DEFAULTS: LazyStatic<RwLock<PredefinedSettings>> = LazyStatic::new(||
RwLock::new(default_settings![ RwLock::new(predefined_settings![
// [app] // [app]
"app.name" => "PageTop Application", "app.name" => "PageTop Application",
"app.description" => "Developed with the amazing PageTop framework.", "app.description" => "Developed with the amazing PageTop framework.",
@ -155,8 +179,8 @@ static DEFAULTS: LazyStatic<RwLock<HashMap<&str, &str>>> = LazyStatic::new(||
]) ])
); );
/// Una aplicación o un módulo podrá añadir nuevos valores de configuración predeterminados. /// Una aplicación o módulo podrá añadir nuevos valores predefinidos de configuración.
pub fn add_defaults(defaults: HashMap<&'static str, &'static str>) { pub(crate) fn add_predefined_settings(defaults: PredefinedSettings) {
DEFAULTS.write().unwrap().extend(defaults); DEFAULTS.write().unwrap().extend(defaults);
} }

View file

@ -1,4 +1,5 @@
use super::ModuleStaticRef; use super::ModuleStaticRef;
use crate::config;
use crate::core::hook::add_action; use crate::core::hook::add_action;
use crate::core::theme; use crate::core::theme;
use crate::{app, trace, LazyStatic}; use crate::{app, trace, LazyStatic};
@ -85,6 +86,24 @@ pub fn register_actions() {
} }
} }
// INIT SETTINGS ***********************************************************************************
pub fn init_settings() {
trace::info!("initializing custom predefined settings");
for m in ENABLED_MODULES.read().unwrap().iter() {
config::add_predefined_settings(m.settings());
}
}
// INIT MODULES ************************************************************************************
pub fn init_modules() {
trace::info!("Calling application bootstrap");
for m in ENABLED_MODULES.read().unwrap().iter() {
m.init();
}
}
// RUN MIGRATIONS ********************************************************************************** // RUN MIGRATIONS **********************************************************************************
#[cfg(feature = "database")] #[cfg(feature = "database")]
@ -120,15 +139,6 @@ pub fn run_migrations() {
.unwrap(); .unwrap();
} }
// INIT MODULES ************************************************************************************
pub fn init_modules() {
trace::info!("Calling application bootstrap");
for m in ENABLED_MODULES.read().unwrap().iter() {
m.init();
}
}
// CONFIGURE SERVICES ****************************************************************************** // CONFIGURE SERVICES ******************************************************************************
pub fn configure_services(cfg: &mut app::web::ServiceConfig) { pub fn configure_services(cfg: &mut app::web::ServiceConfig) {

View file

@ -1,4 +1,6 @@
use crate::app; use crate::app;
use crate::predefined_settings;
use crate::config::PredefinedSettings;
use crate::core::hook::HookAction; use crate::core::hook::HookAction;
use crate::core::theme::ThemeStaticRef; use crate::core::theme::ThemeStaticRef;
use crate::util::{single_type_name, Handler}; use crate::util::{single_type_name, Handler};
@ -40,14 +42,18 @@ pub trait ModuleTrait: BaseModule + Send + Sync {
vec![] vec![]
} }
fn settings(&self) -> PredefinedSettings {
predefined_settings![]
}
fn init(&self) {}
#[cfg(feature = "database")] #[cfg(feature = "database")]
#[allow(unused_variables)] #[allow(unused_variables)]
fn migrations(&self) -> Vec<MigrationItem> { fn migrations(&self) -> Vec<MigrationItem> {
vec![] vec![]
} }
fn init(&self) {}
#[allow(unused_variables)] #[allow(unused_variables)]
fn configure_service(&self, cfg: &mut app::web::ServiceConfig) {} fn configure_service(&self, cfg: &mut app::web::ServiceConfig) {}
} }

View file

@ -6,6 +6,7 @@ pub use crate::{
}; };
pub use crate::config; pub use crate::config;
pub use crate::config::PredefinedSettings;
pub use crate::trace; pub use crate::trace;