From dce2573f8cd121eee483eacb08816ec3e2b08c3b Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Mon, 14 Mar 2022 23:59:48 +0100 Subject: [PATCH] Actualiza el uso opcional de la base de datos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Por defecto PageTop no hace uso de la base de datos. Se deberá indicar explícitamente qué tipo de base de datos usará para que tenga en cuenta la configuración utilizada. --- config/default.toml | 6 +-- drust/Cargo.toml | 6 ++- pagetop/Cargo.toml | 10 +++-- pagetop/config/settings.default.toml | 24 ++++++----- pagetop/src/base/module/mod.rs | 2 + pagetop/src/config.rs | 12 +++--- pagetop/src/core/global.rs | 10 +++-- pagetop/src/core/module/definition.rs | 5 ++- pagetop/src/core/server/app.rs | 52 +++++------------------ pagetop/src/core/server/db.rs | 60 +++++++++++++++++++++++++++ pagetop/src/core/server/locale.rs | 23 ++++++++++ pagetop/src/core/server/mod.rs | 8 +++- pagetop/src/db.rs | 11 +++++ pagetop/src/lib.rs | 5 ++- pagetop/src/locale.rs | 25 +---------- pagetop/src/prelude.rs | 9 ++-- pagetop/src/util.rs | 11 ----- 17 files changed, 166 insertions(+), 113 deletions(-) create mode 100644 pagetop/src/core/server/db.rs create mode 100644 pagetop/src/core/server/locale.rs diff --git a/config/default.toml b/config/default.toml index 26676acb..33280fbd 100644 --- a/config/default.toml +++ b/config/default.toml @@ -9,12 +9,10 @@ language = "es-ES" theme = "Bootsier" [database] +db_type = "mysql" db_name = "drust" db_user = "drust" db_pass = "DrU__#3T" [log] -tracing = "Info" -#Info,actix_server::builder=Error,tracing_actix_web=Warn" -rolling = "Stdout" -format = "Compact" +tracing = "Info,sqlx::query=Warn" diff --git a/drust/Cargo.toml b/drust/Cargo.toml index 0a579e5f..cfa4a264 100644 --- a/drust/Cargo.toml +++ b/drust/Cargo.toml @@ -13,7 +13,11 @@ homepage = "https://suitepro.cillero.es/projects/drust" repository = "https://gitlab.com/manuelcillero/drust" [dependencies] -pagetop = { path = "../pagetop" } actix-web = "3.3.3" maud = { version = "0.23.0" } serde = { version = "1.0", features = ["derive"] } + +[dependencies.pagetop] +path = "../pagetop" +features = ["mysql"] +default-features = false diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index 278b6ba0..0b6c5d7d 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -36,6 +36,7 @@ config_rs = { package = "config", version = "0.11.0", features = ["toml"] } tracing = "0.1" tracing-appender = "0.2" tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } +tracing-unwrap = { version = "0.9", default-features = false } tracing-actix-web = "0.2" fluent-templates = "0.6.1" @@ -53,16 +54,19 @@ serde = { version = "1.0", features = ["derive"] } version = "0.6" features = ["debug-print", "macros", "runtime-async-std-native-tls"] default-features = false +optional = true [dependencies.sea-schema] version = "0.5" features = ["debug-print", "migration"] default-features = false +optional = true [features] -default = ["mysql"] -mysql = ["sea-orm/sqlx-mysql"] -postgres = ["sea-orm/sqlx-postgres"] +default = [] +mysql = ["sea-orm", "sea-schema", "sea-orm/sqlx-mysql"] +postgres = ["sea-orm", "sea-schema", "sea-orm/sqlx-postgres"] +sqlite = ["sea-orm", "sea-schema", "sea-orm/sqlx-sqlite"] [build-dependencies] actix-web-static-files = "3.0.5" diff --git a/pagetop/config/settings.default.toml b/pagetop/config/settings.default.toml index f22868d2..b9c329cf 100644 --- a/pagetop/config/settings.default.toml +++ b/pagetop/config/settings.default.toml @@ -15,24 +15,26 @@ startup_banner = "Small" # Ejemplos: "Error,actix_server::builder=Info,tracing_actix_web=Debug". tracing = "Info" # En terminal ("Stdout") o archivos "Daily", "Hourly", "Minutely" o "Endless". -rolling = "Daily" +rolling = "Stdout" # Directorio para los archivos de traza (si rolling != "Stdout"). path = "log" # Prefijo para los archivos de traza (si rolling != "Stdout"). prefix = "tracing.log" -# Presentación de las trazas: "Json", "Full", "Compact" o "Pretty". -format = "Json" +# Presentación de las trazas: "Full", "Compact", "Pretty" o "Json". +format = "Full" [database] -# Ajustes para conectar con la base de datos. -# El tipo de base de datos es una característica de compilación. -# Nombre (mysql/postgres) o referencia (sqlite) de la base de datos. -db_name = "dbname" -# Usuario y contraseña (mysql/postgres). -db_user = "dbuser" -db_pass = "dbpass" -# Servidor (mysql/postgres) y puerto predeterminado (0 para 3306 ó 5432). +# Conecta con una base de datos (opcional). +# Tipo de la base de datos (mysql, postgres ó sqlite). +db_type = "" +# Nombre (para mysql/postgres) o referencia (para sqlite) de la base de datos. +db_name = "" +# Usuario y contraseña (para mysql/postgres). +db_user = "" +db_pass = "" +# Servidor (para mysql/postgres). db_host = "localhost" +# Puerto (para mysql/postgres), siendo 0 el puerto predeterminado (3306 ó 5432). db_port = 0 # Número máximo de conexiones habilitadas. max_pool_size = 5 diff --git a/pagetop/src/base/module/mod.rs b/pagetop/src/base/module/mod.rs index 3a4e2d51..ab1169b4 100644 --- a/pagetop/src/base/module/mod.rs +++ b/pagetop/src/base/module/mod.rs @@ -1,3 +1,5 @@ pub mod admin; pub mod homepage; + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod user; diff --git a/pagetop/src/config.rs b/pagetop/src/config.rs index c6232c7a..fedffc21 100644 --- a/pagetop/src/config.rs +++ b/pagetop/src/config.rs @@ -89,6 +89,7 @@ pub struct Log { #[derive(Debug, Deserialize)] pub struct Database { + pub db_type : String, pub db_name : String, pub db_user : String, pub db_pass : String, @@ -127,15 +128,16 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, // [log] "log.tracing" => "Info", - "log.rolling" => "Daily", + "log.rolling" => "Stdout", "log.path" => "log", "log.prefix" => "tracing.log", - "log.format" => "json", + "log.format" => "Full", // [database] - "database.db_name" => "dbname", - "database.db_user" => "dbuser", - "database.db_pass" => "dbpass", + "database.db_type" => "", + "database.db_name" => "", + "database.db_user" => "", + "database.db_pass" => "", "database.db_host" => "localhost", "database.db_port" => 0, "database.max_pool_size" => 5, diff --git a/pagetop/src/core/global.rs b/pagetop/src/core/global.rs index 0879fe4c..0b307c56 100644 --- a/pagetop/src/core/global.rs +++ b/pagetop/src/core/global.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, db}; +use crate::{Lazy, trace}; use crate::core::theme::Theme; use crate::core::module::Module; use crate::core::response::page::PageContainer; @@ -42,9 +42,13 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } } -pub fn migrations(dbconn: &db::DbConn) { +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub fn check_migrations() { + trace::info!("Checking migrations."); for m in MODULES.read().unwrap().iter() { - m.migrations(dbconn).expect("Failed to run migrations"); + m.migrations( + &*server::db::DBCONN.read().unwrap() + ).expect("Failed to run migrations"); } } diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index e11efd2e..7dc6252b 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -1,6 +1,8 @@ -use crate::db; use crate::core::server; +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +use crate::db; + /// Los módulos deben implementar este *trait*. pub trait Module: Send + Sync { fn name(&self) -> &'static str; @@ -15,6 +17,7 @@ pub trait Module: Send + Sync { fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { } + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] #[allow(unused_variables)] fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> { Ok(()) diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/core/server/app.rs index b23b38f2..dd794a68 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, base, db, locale, trace}; +use crate::{Lazy, base, trace}; use crate::config::SETTINGS; use crate::core::{Server, global, server}; use crate::core::theme::register_theme; @@ -13,7 +13,7 @@ pub struct Application { impl Application { pub async fn build(bootstrap: Option) -> Result { - // Imprime rótulo (opcional) de bienvenida. + // Imprime un rótulo de presentación (opcional). if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( match SETTINGS.app.startup_banner.to_lowercase().as_str() { @@ -43,42 +43,11 @@ impl Application { Lazy::force(&server::tracing::TRACING); // Valida el identificador de idioma. - Lazy::force(&locale::LANGID); + Lazy::force(&server::locale::LANGID); - // Inicializa la conexión con la base de datos. - trace::info!( - "Connecting to database \"{}\" using a pool of {} connections.", - &SETTINGS.database.db_name, - &SETTINGS.database.max_pool_size - ); - - #[cfg(feature = "mysql")] - let db_type = "mysql"; - - #[cfg(feature = "postgres")] - let db_type = "postgres"; - - // https://github.com/launchbadge/sqlx/issues/1624 - let mut db_uri = db::DbUri::parse(format!( - "{}://{}/{}", - db_type, - &SETTINGS.database.db_host, - &SETTINGS.database.db_name - ).as_str()).unwrap(); - db_uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap(); - db_uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap(); - if SETTINGS.database.db_port != 0 { - db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); - } - - let mut db_options = sea_orm::ConnectOptions::new(db_uri.to_string()); - db_options.max_connections(SETTINGS.database.max_pool_size); - - let dbconn = sea_orm::Database::connect::( - db_options.into() - ) - .await - .expect("Failed to connect to database"); + // Conecta con la base de datos (opcional). + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] + Lazy::force(&server::db::DBCONN); // Registra los temas predefinidos. register_theme(&base::theme::aliner::AlinerTheme); @@ -87,6 +56,8 @@ impl Application { // Registra los módulos predeterminados. register_module(&base::module::admin::AdminModule); + // Registra los módulos que requieren base de datos. + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] register_module(&base::module::user::UserModule); // Ejecuta la función de inicio de la aplicación. @@ -99,16 +70,15 @@ impl Application { // Al ser el último, puede sobrecargarse con la función de inicio. register_module(&base::module::homepage::HomepageModule); - // Run migrations. - trace::info!("Running migrations."); - global::migrations(&dbconn); + // Comprueba actualizaciones pendientes de la base de datos (opcional). + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] + global::check_migrations(); // Prepara el servidor web. let server = server::HttpServer::new(move || { server::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) - .data(dbconn.clone()) .configure(&global::themes) .configure(&global::modules) }) diff --git a/pagetop/src/core/server/db.rs b/pagetop/src/core/server/db.rs new file mode 100644 index 00000000..8c5c9f1f --- /dev/null +++ b/pagetop/src/core/server/db.rs @@ -0,0 +1,60 @@ +use crate::{Lazy, db, run_now, trace}; +use crate::config::SETTINGS; + +use std::sync::RwLock; +use sea_orm::{ConnectOptions, Database}; +use tracing_unwrap::ResultExt; + +pub static DBCONN: Lazy> = Lazy::new(|| { + trace::info!( + "Connecting to database \"{}\" using a pool of {} connections.", + &SETTINGS.database.db_name, + &SETTINGS.database.max_pool_size + ); + + let db_uri = match SETTINGS.database.db_type.as_str() { + "mysql" | "postgres" => { + let mut tmp_uri = db::DbUri::parse(format!( + "{}://{}/{}", + &SETTINGS.database.db_type, + &SETTINGS.database.db_host, + &SETTINGS.database.db_name + ).as_str()).unwrap(); + tmp_uri.set_username( + &SETTINGS.database.db_user.as_str() + ).unwrap(); + // https://github.com/launchbadge/sqlx/issues/1624 + tmp_uri.set_password( + Some(&SETTINGS.database.db_pass.as_str()) + ).unwrap(); + if SETTINGS.database.db_port != 0 { + tmp_uri.set_port( + Some(SETTINGS.database.db_port) + ).unwrap(); + } + tmp_uri + }, + "sqlite" => db::DbUri::parse( + format!("{}://{}", + &SETTINGS.database.db_type, + &SETTINGS.database.db_name + ).as_str()).unwrap(), + _ => { + trace::error!( + "Unrecognized database type \"{}\".", + &SETTINGS.database.db_type + ); + db::DbUri::parse("").unwrap() + } + }; + + let db_conn = run_now( + Database::connect::({ + let mut db_opt = ConnectOptions::new(db_uri.to_string()); + db_opt.max_connections(SETTINGS.database.max_pool_size); + db_opt.into() + }) + ).expect_or_log("Failed to connect to database"); + + RwLock::new(db_conn) +}); diff --git a/pagetop/src/core/server/locale.rs b/pagetop/src/core/server/locale.rs new file mode 100644 index 00000000..8bc6fc10 --- /dev/null +++ b/pagetop/src/core/server/locale.rs @@ -0,0 +1,23 @@ +use crate::{Lazy, trace}; +use crate::config::SETTINGS; + +use unic_langid::LanguageIdentifier; + +/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] +/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de +/// la aplicación, obtenido de `SETTINGS.app.language`. +pub static LANGID: Lazy = Lazy::new(|| { + match SETTINGS.app.language.parse() { + Ok(language) => language, + Err(_) => { + trace::warn!( + "Failed to parse language \"{}\". {}. {}. {}.", + SETTINGS.app.language, + "Unrecognized Unicode Language Identifier", + "Using \"en-US\"", + "Check the settings file", + ); + "en-US".parse().unwrap() + } + } +}); diff --git a/pagetop/src/core/server/mod.rs b/pagetop/src/core/server/mod.rs index ef85b53c..394886b4 100644 --- a/pagetop/src/core/server/mod.rs +++ b/pagetop/src/core/server/mod.rs @@ -4,5 +4,9 @@ pub use actix_web::{ mod tracing; -mod app; -pub use app::Application; +pub mod locale; + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub mod db; + +pub mod app; diff --git a/pagetop/src/db.rs b/pagetop/src/db.rs index fb3f789e..b487cc19 100644 --- a/pagetop/src/db.rs +++ b/pagetop/src/db.rs @@ -12,3 +12,14 @@ pub mod entity { pub mod migration { pub use sea_schema::migration::prelude::*; } + +#[macro_export] +macro_rules! db_migrations { + ( $DBCONN:ident ) => {{ + $crate::run_now({ + use $crate::db::migration::MigratorTrait; + + migration::Migrator::up($DBCONN, None) + }) + }}; +} diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 8d75fb08..b8485f96 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -11,11 +11,14 @@ pub use futures::executor::block_on as run_now; pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod db; // Acceso a la base de datos. + pub mod core; // Servidor web y APIs para Temas, Módulos y Respuestas web. pub mod base; // Temas, Módulos y Componentes base. pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. -pub use crate::core::server::Application; +pub use crate::core::server::app::Application; diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index 07cb0d8e..22a01ba6 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -2,35 +2,12 @@ pub use fluent_templates::{static_loader as static_locale, Loader as Locale}; pub use fluent_templates; pub use fluent_templates::fluent_bundle::FluentValue; -use crate::{Lazy, trace}; -use crate::config::SETTINGS; - -use unic_langid::LanguageIdentifier; - -/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] -/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de -/// la aplicación, obtenido de `SETTINGS.app.language`. -pub static LANGID: Lazy = Lazy::new(|| { - match SETTINGS.app.language.parse() { - Ok(language) => language, - Err(_) => { - trace::warn!( - "Failed to parse language \"{}\". {}. {}. {}.", - SETTINGS.app.language, - "Unicode Language Identifier not recognized", - "Using \"en-US\"", - "Check the settings file", - ); - "en-US".parse().unwrap() - } - } -}); - #[macro_export] /// Permite integrar fácilmente localización en temas, módulos y componentes. macro_rules! localize { ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; + use $crate::core::server::locale::LANGID; static_locale! { static LOCALES = { diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index bcff745b..f0a4b031 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -1,15 +1,12 @@ //! Re-exporta recursos comunes. -pub use crate::{ - args, - db_migrations, -}; - +pub use crate::args; pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; -pub use crate::db; +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub use crate::{db, db_migrations}; pub use crate::core::theme::*; pub use crate::core::module::*; diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index 5150d517..c56d2146 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -18,17 +18,6 @@ macro_rules! args { }}; } -#[macro_export] -macro_rules! db_migrations { - ( $DBCONN:ident ) => {{ - $crate::run_now({ - use $crate::db::migration::MigratorTrait; - - migration::Migrator::up($DBCONN, None) - }) - }}; -} - pub fn valid_id(id: &str) -> Option { let id = id.trim().replace(" ", "_").to_lowercase(); match id.is_empty() {