diff --git a/drust/src/main.rs b/drust/src/main.rs index 6916d3b1..ac96b1ed 100644 --- a/drust/src/main.rs +++ b/drust/src/main.rs @@ -1,4 +1,6 @@ +use pagetop::prelude::*; + #[actix_web::main] async fn main() -> std::io::Result<()> { - pagetop::Application::build(None).await?.run()?.await + Application::prepare(essence).await?.run()?.await } diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index b828e58f..e6cbc75e 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -27,16 +27,16 @@ categories = [ doc-comment = "0.3.3" downcast-rs = "1.2.0" figlet-rs = "0.1.3" -futures = "0.3" -once_cell = "1.9.0" +futures = "0.3.21" +once_cell = "1.10.0" url = "2.2.2" 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 = "0.1.32" +tracing-appender = "0.2.1" +tracing-subscriber = { version = "0.3.9", features = ["json", "env-filter"] } +tracing-unwrap = { version = "0.9.2", default-features = false } tracing-actix-web = "0.2" fluent-templates = "0.6.1" @@ -51,17 +51,20 @@ sycamore = { version = "0.7.1", features = ["ssr"] } serde = { version = "1.0", features = ["derive"] } [dependencies.sea-orm] -version = "0.6" +version = "0.6.0" features = ["debug-print", "macros", "runtime-async-std-native-tls"] default-features = false optional = true [dependencies.sea-schema] -version = "0.5" +version = "0.6.0" features = ["debug-print", "migration"] default-features = false optional = true +[dev-dependencies] +tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } + [features] default = [] mysql = ["sea-orm", "sea-schema", "sea-orm/sqlx-mysql"] diff --git a/pagetop/src/base/module/admin/mod.rs b/pagetop/src/base/module/admin/mod.rs index 0bb1202d..808aa75e 100644 --- a/pagetop/src/base/module/admin/mod.rs +++ b/pagetop/src/base/module/admin/mod.rs @@ -6,7 +6,7 @@ mod summary; pub struct AdminModule; -impl Module for AdminModule { +impl ModuleTrait for AdminModule { fn name(&self) -> &'static str { "admin" } diff --git a/pagetop/src/base/module/homepage/mod.rs b/pagetop/src/base/module/homepage/mod.rs index de4b98ce..b6aac4fe 100644 --- a/pagetop/src/base/module/homepage/mod.rs +++ b/pagetop/src/base/module/homepage/mod.rs @@ -4,7 +4,7 @@ localize!("en-US", "src/base/module/homepage/locales"); pub struct HomepageModule; -impl Module for HomepageModule { +impl ModuleTrait for HomepageModule { fn name(&self) -> &'static str { "homepage" } diff --git a/pagetop/src/base/module/user/mod.rs b/pagetop/src/base/module/user/mod.rs index 7dc3c043..99096377 100644 --- a/pagetop/src/base/module/user/mod.rs +++ b/pagetop/src/base/module/user/mod.rs @@ -7,7 +7,7 @@ mod migration; pub struct UserModule; -impl Module for UserModule { +impl ModuleTrait for UserModule { fn name(&self) -> &'static str { "user" } diff --git a/pagetop/src/base/theme/aliner/mod.rs b/pagetop/src/base/theme/aliner/mod.rs index b678d4b7..18df448f 100644 --- a/pagetop/src/base/theme/aliner/mod.rs +++ b/pagetop/src/base/theme/aliner/mod.rs @@ -4,7 +4,7 @@ include!(concat!(env!("OUT_DIR"), "/aliner.rs")); pub struct AlinerTheme; -impl Theme for AlinerTheme { +impl ThemeTrait for AlinerTheme { fn name(&self) -> &'static str { "aliner" } diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index 3a340a84..dd16d71c 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -6,7 +6,7 @@ localize!("en-US", "src/base/theme/bootsier/locales"); pub struct BootsierTheme; -impl Theme for BootsierTheme { +impl ThemeTrait for BootsierTheme { fn name(&self) -> &'static str { "bootsier" } diff --git a/pagetop/src/base/theme/minimal/mod.rs b/pagetop/src/base/theme/minimal/mod.rs index c6780005..b3a50906 100644 --- a/pagetop/src/base/theme/minimal/mod.rs +++ b/pagetop/src/base/theme/minimal/mod.rs @@ -2,7 +2,7 @@ use crate::prelude::*; pub struct MinimalTheme; -impl Theme for MinimalTheme { +impl ThemeTrait for MinimalTheme { fn name(&self) -> &'static str { "minimal" } diff --git a/pagetop/src/core/global.rs b/pagetop/src/core/all.rs similarity index 53% rename from pagetop/src/core/global.rs rename to pagetop/src/core/all.rs index dd9aa909..b48e0684 100644 --- a/pagetop/src/core/global.rs +++ b/pagetop/src/core/all.rs @@ -1,21 +1,19 @@ use crate::{Lazy, trace}; -use crate::core::theme::Theme; -use crate::core::module::Module; -use crate::core::response::page::PageContainer; +use crate::core::theme::ThemeTrait; +use crate::core::module::ModuleTrait; use crate::core::server; use std::sync::RwLock; -use std::collections::HashMap; include!(concat!(env!("OUT_DIR"), "/theme.rs")); // ----------------------------------------------------------------------------- -// Temas registrados y tema por defecto. +// Temas registrados y tema predeterminado. // ----------------------------------------------------------------------------- -pub static THEMES: Lazy>> = Lazy::new(|| { - RwLock::new(Vec::new()) -}); +pub static THEMES: Lazy>> = Lazy::new( + || { RwLock::new(Vec::new()) } +); pub fn themes(cfg: &mut server::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( @@ -32,9 +30,9 @@ pub fn themes(cfg: &mut server::web::ServiceConfig) { // Módulos registrados. // ----------------------------------------------------------------------------- -pub static MODULES: Lazy>> = Lazy::new(|| { - RwLock::new(Vec::new()) -}); +pub static MODULES: Lazy>> = Lazy::new( + || { RwLock::new(Vec::new()) } +); pub fn modules(cfg: &mut server::web::ServiceConfig) { for m in MODULES.read().unwrap().iter() { @@ -43,19 +41,9 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub fn run_migrations() { - trace::info!("Checking migrations."); +pub fn migrations() { + trace::info!("Checking migrations"); for m in MODULES.read().unwrap().iter() { - m.migrations( - &*server::db::DBCONN.read().unwrap() - ).expect("Failed to run migrations"); + m.migrations(&*server::db::DBCONN).expect("Failed to run migrations"); } } - -// ----------------------------------------------------------------------------- -// Componentes globales. -// ----------------------------------------------------------------------------- - -pub static COMPONENTS: Lazy>> = Lazy::new( - || { RwLock::new(HashMap::new()) } -); diff --git a/pagetop/src/core/html.rs b/pagetop/src/core/html.rs new file mode 100644 index 00000000..ba885bb3 --- /dev/null +++ b/pagetop/src/core/html.rs @@ -0,0 +1 @@ +pub use maud::{DOCTYPE, Markup, PreEscaped, html}; diff --git a/pagetop/src/core/mod.rs b/pagetop/src/core/mod.rs index 26618959..8db86b83 100644 --- a/pagetop/src/core/mod.rs +++ b/pagetop/src/core/mod.rs @@ -1,7 +1,8 @@ pub use actix_web::dev::Server; -mod global; +mod all; +pub mod html; pub mod theme; pub mod module; pub mod response; diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index 7dc6252b..011ef083 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -4,7 +4,7 @@ use crate::core::server; use crate::db; /// Los módulos deben implementar este *trait*. -pub trait Module: Send + Sync { +pub trait ModuleTrait: Send + Sync { fn name(&self) -> &'static str; fn fullname(&self) -> String; diff --git a/pagetop/src/core/module/mod.rs b/pagetop/src/core/module/mod.rs index 439cff79..2a42352a 100644 --- a/pagetop/src/core/module/mod.rs +++ b/pagetop/src/core/module/mod.rs @@ -1,14 +1,14 @@ -use crate::core::global; +use crate::core::all; mod definition; -pub use definition::Module; +pub use definition::ModuleTrait; -pub fn register_module(m: &'static (dyn Module + 'static)) { - global::MODULES.write().unwrap().push(m); +pub fn register_module(m: &'static (dyn ModuleTrait + 'static)) { + all::MODULES.write().unwrap().push(m); } -pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { - let modules = global::MODULES.write().unwrap(); +pub fn find_module(name: &str) -> Option<&'static (dyn ModuleTrait + 'static)> { + let modules = all::MODULES.write().unwrap(); match modules.iter().find(|t| t.name() == name) { Some(module) => Some(*module), _ => None, diff --git a/pagetop/src/core/response/page/assets.rs b/pagetop/src/core/response/page/assets.rs index 11cdd35c..2bd96fc2 100644 --- a/pagetop/src/core/response/page/assets.rs +++ b/pagetop/src/core/response/page/assets.rs @@ -1,10 +1,11 @@ use crate::{Lazy, base}; use crate::config::SETTINGS; -use crate::core::global; -use crate::core::theme::{Markup, PreEscaped, Theme, find_theme, html}; +use crate::core::all; +use crate::core::html::{Markup, PreEscaped, html}; +use crate::core::theme::*; -static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { - for t in global::THEMES.read().unwrap().iter() { +static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { + for t in all::THEMES.read().unwrap().iter() { if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { return *t; } @@ -184,7 +185,7 @@ impl JavaScript { // ----------------------------------------------------------------------------- pub struct PageAssets { - theme : &'static dyn Theme, + theme : &'static dyn ThemeTrait, favicon : Option, metadata : Vec<(String, String)>, stylesheets: Vec, @@ -259,7 +260,7 @@ impl PageAssets { /// Assets GETTERS. - pub fn theme(&mut self) -> &'static dyn Theme { + pub fn theme(&mut self) -> &'static dyn ThemeTrait { self.theme } diff --git a/pagetop/src/core/response/page/component.rs b/pagetop/src/core/response/page/component.rs index 1472ffe2..78925468 100644 --- a/pagetop/src/core/response/page/component.rs +++ b/pagetop/src/core/response/page/component.rs @@ -1,4 +1,4 @@ -use crate::core::theme::{Markup, html}; +use crate::core::html::{Markup, html}; use crate::core::response::page::PageAssets; use downcast_rs::{Downcast, impl_downcast}; diff --git a/pagetop/src/core/response/page/container.rs b/pagetop/src/core/response/page/container.rs index 6bf5e56a..4a577b2d 100644 --- a/pagetop/src/core/response/page/container.rs +++ b/pagetop/src/core/response/page/container.rs @@ -1,4 +1,4 @@ -use crate::core::theme::{Markup, html}; +use crate::core::html::{Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, render_component}; use std::sync::Arc; diff --git a/pagetop/src/core/response/page/page.rs b/pagetop/src/core/response/page/page.rs index 8052683d..d47a33f1 100644 --- a/pagetop/src/core/response/page/page.rs +++ b/pagetop/src/core/response/page/page.rs @@ -1,12 +1,17 @@ use crate::{Lazy, trace, util}; use crate::config::SETTINGS; -use crate::core::{global, server}; -use crate::core::theme::{DOCTYPE, Markup, html}; +use crate::core::html::{DOCTYPE, Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; +use crate::core::server; use std::borrow::Cow; +use std::sync::RwLock; use std::collections::HashMap; +static COMPONENTS: Lazy>> = Lazy::new(|| { + RwLock::new(HashMap::new()) +}); + static DEFAULT_LANGUAGE: Lazy> = Lazy::new(|| { let language = SETTINGS.app.language[..2].to_lowercase(); if !language.is_empty() { @@ -25,9 +30,9 @@ static DEFAULT_DIRECTION: Lazy> = Lazy::new(|| { "" => None, _ => { trace::warn!( - "Text direction \"{}\" not valid. {}.", + "Text direction \"{}\" not valid, {}", SETTINGS.app.direction, - "Check the settings file" + "check the settings file" ); None } @@ -63,7 +68,7 @@ impl<'a> Page<'a> { description : None, body_classes: "body".into(), assets : PageAssets::new(), - regions : global::COMPONENTS.read().unwrap().clone(), + regions : COMPONENTS.read().unwrap().clone(), template : "default".to_owned(), } } @@ -208,7 +213,7 @@ pub fn render_component( } pub fn add_component_to(region: &'static str, component: impl PageComponent) { - let mut hmap = global::COMPONENTS.write().unwrap(); + let mut hmap = COMPONENTS.write().unwrap(); if let Some(regions) = hmap.get_mut(region) { regions.add(component); } else { diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/core/server/app.rs index 7338aa3b..cbca9979 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -1,6 +1,6 @@ use crate::{Lazy, base, trace}; use crate::config::SETTINGS; -use crate::core::{Server, global, server}; +use crate::core::{Server, all, server}; use crate::core::theme::register_theme; use crate::core::module::register_module; @@ -11,8 +11,12 @@ pub struct Application { server: Server, } +pub fn essence() { + trace::info!("No bootstrap configured"); +} + impl Application { - pub async fn build(bootstrap: Option) -> Result { + pub async fn prepare(bootstrap: fn()) -> Result { // Imprime un rótulo de presentación (opcional). if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( @@ -61,10 +65,8 @@ impl Application { register_module(&base::module::user::UserModule); // Ejecuta la función de inicio de la aplicación. - if bootstrap != None { - trace::info!("Calling application bootstrap."); - let _ = &(bootstrap.unwrap())(); - } + trace::info!("Calling application bootstrap"); + let _ = &bootstrap(); // Registra el módulo para la página de inicio de PageTop. // Al ser el último, puede sobrecargarse con la función de inicio. @@ -72,15 +74,15 @@ impl Application { // Comprueba actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - global::run_migrations(); + all::migrations(); // Prepara el servidor web. let server = server::HttpServer::new(move || { server::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) - .configure(&global::themes) - .configure(&global::modules) + .configure(&all::themes) + .configure(&all::modules) }) .bind(format!("{}:{}", &SETTINGS.webserver.bind_address, diff --git a/pagetop/src/core/server/db.rs b/pagetop/src/core/server/db.rs index 8c5c9f1f..9d196970 100644 --- a/pagetop/src/core/server/db.rs +++ b/pagetop/src/core/server/db.rs @@ -1,13 +1,12 @@ 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(|| { +pub static DBCONN: Lazy = Lazy::new(|| { trace::info!( - "Connecting to database \"{}\" using a pool of {} connections.", + "Connecting to database \"{}\" using a pool of {} connections", &SETTINGS.database.db_name, &SETTINGS.database.max_pool_size ); @@ -41,20 +40,18 @@ pub static DBCONN: Lazy> = Lazy::new(|| { ).as_str()).unwrap(), _ => { trace::error!( - "Unrecognized database type \"{}\".", + "Unrecognized database type \"{}\"", &SETTINGS.database.db_type ); db::DbUri::parse("").unwrap() } }; - let db_conn = run_now( + 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) + ).expect_or_log("Failed to connect to database") }); diff --git a/pagetop/src/core/server/locale.rs b/pagetop/src/core/server/locale.rs index 8bc6fc10..59fc8468 100644 --- a/pagetop/src/core/server/locale.rs +++ b/pagetop/src/core/server/locale.rs @@ -11,11 +11,12 @@ pub static LANGID: Lazy = Lazy::new(|| { Ok(language) => language, Err(_) => { trace::warn!( - "Failed to parse language \"{}\". {}. {}. {}.", + "{}, {} \"{}\"! {}, {}", + "Failed to parse language", + "unrecognized Unicode Language Identifier", SETTINGS.app.language, - "Unrecognized Unicode Language Identifier", "Using \"en-US\"", - "Check the settings file", + "check the settings file", ); "en-US".parse().unwrap() } diff --git a/pagetop/src/core/theme/definition.rs b/pagetop/src/core/theme/definition.rs index 12d9e05f..eb67ec10 100644 --- a/pagetop/src/core/theme/definition.rs +++ b/pagetop/src/core/theme/definition.rs @@ -1,11 +1,11 @@ use crate::config::SETTINGS; -use crate::core::server; -use crate::core::theme::{Markup, html}; +use crate::core::html::{Markup, html}; use crate::core::response::page::{Page, PageAssets, PageComponent}; +use crate::core::server; use crate::base::component::Chunck; /// Los temas deben implementar este "trait". -pub trait Theme: Send + Sync { +pub trait ThemeTrait: Send + Sync { fn name(&self) -> &'static str; fn fullname(&self) -> String; diff --git a/pagetop/src/core/theme/mod.rs b/pagetop/src/core/theme/mod.rs index 8292ade6..e83f4307 100644 --- a/pagetop/src/core/theme/mod.rs +++ b/pagetop/src/core/theme/mod.rs @@ -1,16 +1,14 @@ -use crate::core::global; - -pub use maud::{DOCTYPE, Markup, PreEscaped, html}; +use crate::core::all; mod definition; -pub use definition::Theme; +pub use definition::ThemeTrait; -pub fn register_theme(t: &'static (dyn Theme + 'static)) { - global::THEMES.write().unwrap().push(t); +pub fn register_theme(t: &'static (dyn ThemeTrait + 'static)) { + all::THEMES.write().unwrap().push(t); } -pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { - let themes = global::THEMES.write().unwrap(); +pub fn find_theme(name: &str) -> Option<&'static (dyn ThemeTrait + 'static)> { + let themes = all::THEMES.write().unwrap(); match themes.iter().find(|t| t.name() == name) { Some(theme) => Some(*theme), _ => None, diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index b8485f96..daf0577d 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -20,5 +20,3 @@ 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::app::Application; diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index 22a01ba6..eac11472 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -37,8 +37,8 @@ macro_rules! localize { fn e( key: &str, args: &std::collections::HashMap - ) -> crate::core::theme::PreEscaped { - crate::core::theme::PreEscaped( + ) -> crate::core::html::PreEscaped { + crate::core::html::PreEscaped( LOCALES.lookup_with_args(&LANGID, key, args) ) } diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index f0a4b031..1dd8bd79 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -8,10 +8,12 @@ pub use crate::localize; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub use crate::{db, db_migrations}; +pub use crate::core::html::*; pub use crate::core::theme::*; pub use crate::core::module::*; pub use crate::core::response::page::*; pub use crate::core::server; +pub use crate::core::server::app::{Application, essence}; pub use crate::base::component::*; diff --git a/pagetop/tests/health_check.rs b/pagetop/tests/health_check.rs index 0c309bea..dd980796 100644 --- a/pagetop/tests/health_check.rs +++ b/pagetop/tests/health_check.rs @@ -1,7 +1,8 @@ -use pagetop::core::server; - -fn spawn_app() { - let server = server::run(None).expect("Failed to bind address"); +async fn spawn_app() { + let server = pagetop::Application::prepare(None) + .await? + .run()? + .expect("Failed to prepare server"); let _ = tokio::spawn(server); }