Modifica la definición de apps como un módulo más
This commit is contained in:
parent
61813a44e5
commit
5c65642ec0
13 changed files with 384 additions and 137 deletions
|
|
@ -1,24 +1,31 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
pub_const_handler!(APP_DRUST);
|
||||
|
||||
struct Drust;
|
||||
|
||||
impl AppTrait for Drust {
|
||||
fn enable_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
impl ModuleTrait for Drust {
|
||||
fn handler(&self) -> Handler {
|
||||
APP_DRUST
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![
|
||||
&pagetop_admin::Admin,
|
||||
&pagetop_user::User,
|
||||
&pagetop_node::Node,
|
||||
&pagetop::base::module::homepage::DefaultHomePage,
|
||||
]
|
||||
}
|
||||
|
||||
fn disable_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
fn uninstall_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![
|
||||
// &pagetop_node::Node,
|
||||
// &pagetop_node::Node
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
Application::prepare(Drust).await?.run()?.await
|
||||
Application::prepare(&Drust).await?.run()?.await
|
||||
}
|
||||
|
|
|
|||
19
pagetop-mdbook/Cargo.toml
Normal file
19
pagetop-mdbook/Cargo.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "pagetop-mdbook"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
||||
authors = [
|
||||
"Manuel Cillero <manuel@cillero.es>"
|
||||
]
|
||||
description = """\
|
||||
...\
|
||||
"""
|
||||
homepage = "https://suitepro.cillero.es/projects/pagetop"
|
||||
repository = "https://gitlab.com/manuelcillero/pagetop"
|
||||
license = "Apache-2.0 or MIT"
|
||||
|
||||
[dependencies]
|
||||
pagetop = { path = "../pagetop" }
|
||||
static-files = "0.2.3"
|
||||
maud = { git = "https://github.com/lambda-fairy/maud", rev = "e6787cd6" }
|
||||
191
pagetop-mdbook/src/lib.rs
Normal file
191
pagetop-mdbook/src/lib.rs
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
pub type BookMapResources = std::collections::HashMap<&'static str, static_files::Resource>;
|
||||
|
||||
pub_const_handler!(MODULE_MDBOOK);
|
||||
|
||||
pub struct MdBook;
|
||||
|
||||
impl ModuleTrait for MdBook {
|
||||
fn handler(&self) -> Handler {
|
||||
MODULE_MDBOOK
|
||||
}
|
||||
}
|
||||
|
||||
impl MdBook {
|
||||
pub fn configure_service_mdbook(
|
||||
cfg: &mut app::web::ServiceConfig,
|
||||
mdbook_path: &'static str,
|
||||
mdbook_map: &'static BookMapResources,
|
||||
) {
|
||||
let path = mdbook_path.trim_end_matches('/');
|
||||
cfg.service(
|
||||
app::web::scope(path)
|
||||
.route(
|
||||
"{tail:.*html$}",
|
||||
app::web::get().to(move |request: app::HttpRequest| {
|
||||
mdbook_page(request, path, mdbook_map)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
"{tail:.*$}",
|
||||
app::web::get().to(move |request: app::HttpRequest| {
|
||||
mdbook_resource(request, path, mdbook_map)
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async fn mdbook_page(
|
||||
request: app::HttpRequest,
|
||||
mdbook_path: &'static str,
|
||||
mdbook_map: &'static BookMapResources,
|
||||
) -> ResultPage<Markup, FatalError> {
|
||||
let path_len = mdbook_path.len() + 1;
|
||||
if let Some(content) = mdbook_map.get(&request.path()[path_len..]) {
|
||||
if let Ok(html) = std::str::from_utf8(content.data) {
|
||||
let _lang = extract("Lang", html);
|
||||
let title = match extract("Title", html) {
|
||||
Some(title) => title,
|
||||
_ => "Documentación",
|
||||
};
|
||||
let _print = matches!(extract("Print", html), Some("enabled"));
|
||||
let _mathjax = matches!(extract("MathJax", html), Some("supported"));
|
||||
let beginning = {
|
||||
let separator = "<!-- mdBook -->";
|
||||
match html.find(separator) {
|
||||
Some(pos) => pos + separator.len(),
|
||||
_ => 0,
|
||||
}
|
||||
};
|
||||
|
||||
Page::new()
|
||||
.with_title(title)
|
||||
.with_context(PageOp::AddMetadata("theme-color", "#ffffff"))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/css/variables.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/css/general.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/css/chrome.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(
|
||||
StyleSheet::located("/doc/css/print.css").for_media(TargetMedia::Print),
|
||||
))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/FontAwesome/css/font-awesome.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/fonts/fonts.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/highlight.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/tomorrow-night.css",
|
||||
)))
|
||||
.with_context(PageOp::AddStyleSheet(StyleSheet::located(
|
||||
"/doc/ayu-highlight.css",
|
||||
)))
|
||||
.add_to(
|
||||
"region-content",
|
||||
Container::new()
|
||||
.with_id("mdbook")
|
||||
.with_component(Html::with(html! { (PreEscaped(&html[beginning..])) })),
|
||||
)
|
||||
.render()
|
||||
} else {
|
||||
Err(FatalError::NotFound)
|
||||
}
|
||||
} else {
|
||||
Err(FatalError::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
async fn mdbook_resource(
|
||||
request: app::HttpRequest,
|
||||
mdbook_path: &'static str,
|
||||
mdbook_map: &'static BookMapResources,
|
||||
) -> app::HttpResponse {
|
||||
let path_len = mdbook_path.len() + 1;
|
||||
// From https://github.com/kilork/actix-web-static-files/blob/master/src/resource_files.rs, see
|
||||
// functions respond_to(), any_match() and none_match().
|
||||
if let Some(file) = &mdbook_map.get(&request.path()[path_len..]) {
|
||||
let etag = Some(app::http::header::EntityTag::new_strong(format!(
|
||||
"{:x}:{:x}",
|
||||
file.data.len(),
|
||||
file.modified
|
||||
)));
|
||||
|
||||
let precondition_failed = !any_match(etag.as_ref(), &request);
|
||||
|
||||
let not_modified = !none_match(etag.as_ref(), &request);
|
||||
|
||||
let mut resp = app::HttpResponse::build(app::http::StatusCode::OK);
|
||||
resp.insert_header((app::http::header::CONTENT_TYPE, file.mime_type));
|
||||
|
||||
if let Some(etag) = etag {
|
||||
resp.insert_header(app::http::header::ETag(etag));
|
||||
}
|
||||
|
||||
if precondition_failed {
|
||||
return FatalError::PreconditionFailed.error_response();
|
||||
} else if not_modified {
|
||||
return FatalError::NotModified.error_response();
|
||||
}
|
||||
|
||||
resp.body(file.data)
|
||||
} else {
|
||||
FatalError::NotFound.error_response()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if `request` has no `If-Match` header or one which matches `etag`.
|
||||
fn any_match(etag: Option<&app::http::header::EntityTag>, request: &app::HttpRequest) -> bool {
|
||||
match request.get_header::<app::http::header::IfMatch>() {
|
||||
None | Some(app::http::header::IfMatch::Any) => true,
|
||||
Some(app::http::header::IfMatch::Items(ref items)) => {
|
||||
if let Some(some_etag) = etag {
|
||||
for item in items {
|
||||
if item.strong_eq(some_etag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if `request` doesn't have an `If-None-Match` header matching `req`.
|
||||
fn none_match(etag: Option<&app::http::header::EntityTag>, request: &app::HttpRequest) -> bool {
|
||||
match request.get_header::<app::http::header::IfNoneMatch>() {
|
||||
Some(app::http::header::IfNoneMatch::Any) => false,
|
||||
Some(app::http::header::IfNoneMatch::Items(ref items)) => {
|
||||
if let Some(some_etag) = etag {
|
||||
for item in items {
|
||||
if item.weak_eq(some_etag) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn extract(attr: &'static str, from: &'static str) -> Option<&'static str> {
|
||||
let search = concat_string!("<!-- ", attr, ":");
|
||||
if let Some(ini) = from.find(&search) {
|
||||
let ini = ini + search.len() + 1;
|
||||
if let Some(end) = from[ini..].find("-->").map(|i| i + ini) {
|
||||
let end = end - 1;
|
||||
return Some(&from[ini..end]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
@ -13,9 +13,6 @@ pub mod locale;
|
|||
#[cfg(feature = "database")]
|
||||
pub mod db;
|
||||
|
||||
mod definition;
|
||||
pub use definition::AppTrait;
|
||||
|
||||
pub mod application;
|
||||
|
||||
pub mod fatal_error;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use super::{fatal_error::FatalError, AppTrait};
|
||||
use super::fatal_error::FatalError;
|
||||
use crate::config::SETTINGS;
|
||||
use crate::core::module::ModuleStaticRef;
|
||||
use crate::core::{module, theme};
|
||||
use crate::html::Markup;
|
||||
use crate::response::page::ResultPage;
|
||||
use crate::{base, trace, LazyStatic};
|
||||
use crate::LazyStatic;
|
||||
|
||||
use actix_web::dev::Server;
|
||||
|
||||
use std::io::Error;
|
||||
|
||||
pub struct Application {
|
||||
|
|
@ -13,7 +15,7 @@ pub struct Application {
|
|||
}
|
||||
|
||||
impl Application {
|
||||
pub async fn prepare(app: impl AppTrait) -> Result<Self, Error> {
|
||||
pub async fn prepare(app: ModuleStaticRef) -> Result<Self, Error> {
|
||||
// Rótulo de presentación.
|
||||
super::banner::print_on_startup();
|
||||
|
||||
|
|
@ -23,40 +25,25 @@ impl Application {
|
|||
// Valida el identificador de idioma.
|
||||
LazyStatic::force(&super::locale::LANGID);
|
||||
|
||||
// Conecta con la base de datos (opcional).
|
||||
#[cfg(feature = "database")]
|
||||
// Conecta con la base de datos.
|
||||
LazyStatic::force(&super::db::DBCONN);
|
||||
|
||||
// Deshabilita los módulos indicados por la aplicación.
|
||||
module::all::disable_modules(app.disable_modules());
|
||||
// Habilita los módulos predeterminados.
|
||||
module::all::enable_modules(vec![&base::module::homepage::DefaultHomePage]);
|
||||
// Habilita los módulos de la aplicación.
|
||||
module::all::enable_modules(app.enable_modules());
|
||||
// Registra los módulos de la aplicación.
|
||||
module::all::register_modules(app);
|
||||
|
||||
// Registra los temas predeterminados.
|
||||
theme::all::register_themes(vec![
|
||||
&base::theme::aliner::Aliner,
|
||||
&base::theme::minimal::Minimal,
|
||||
&base::theme::bootsier::Bootsier,
|
||||
&base::theme::bulmix::Bulmix,
|
||||
]);
|
||||
// Registra los temas de la aplicación.
|
||||
theme::all::register_themes(app.themes());
|
||||
// Registra los temas de los módulos.
|
||||
module::all::register_themes();
|
||||
|
||||
// Registra las acciones de todos los módulos.
|
||||
// Registra acciones de los módulos.
|
||||
module::all::register_actions();
|
||||
|
||||
// Ejecuta actualizaciones pendientes de la base de datos (opcional).
|
||||
#[cfg(feature = "database")]
|
||||
module::all::run_migrations();
|
||||
|
||||
// Inicializa los módulos que lo requieran.
|
||||
// Inicializa los módulos.
|
||||
module::all::init_modules();
|
||||
|
||||
// Ejecuta la función de inicio de la aplicación.
|
||||
trace::info!("Calling application bootstrap");
|
||||
app.bootstrap();
|
||||
#[cfg(feature = "database")]
|
||||
// Ejecuta actualizaciones pendientes de la base de datos.
|
||||
module::all::run_migrations();
|
||||
|
||||
// Prepara el servidor web.
|
||||
let server = super::HttpServer::new(move || {
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
use crate::core::module::ModuleStaticRef;
|
||||
use crate::core::theme::ThemeStaticRef;
|
||||
|
||||
pub trait AppTrait: Send + Sync {
|
||||
fn bootstrap(&self) {}
|
||||
|
||||
fn enable_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn disable_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn themes(&self) -> Vec<ThemeStaticRef> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use super::ModuleStaticRef;
|
||||
use crate::core::hook::add_action;
|
||||
use crate::core::theme;
|
||||
use crate::{app, trace, LazyStatic};
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
|
|
@ -7,47 +8,42 @@ use crate::{db::*, run_now};
|
|||
|
||||
use std::sync::RwLock;
|
||||
|
||||
// DISABLED MODULES ********************************************************************************
|
||||
|
||||
static DISABLED_MODULES: LazyStatic<RwLock<Vec<ModuleStaticRef>>> =
|
||||
LazyStatic::new(|| RwLock::new(Vec::new()));
|
||||
|
||||
pub fn disable_modules(modules: Vec<ModuleStaticRef>) {
|
||||
let mut disabled_modules = DISABLED_MODULES.write().unwrap();
|
||||
for module in modules {
|
||||
if !disabled_modules
|
||||
.iter()
|
||||
.any(|m| m.handler() == module.handler())
|
||||
{
|
||||
trace::debug!("Disabling the \"{}\" module", module.single_name());
|
||||
disabled_modules.push(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ENABLED MODULES *********************************************************************************
|
||||
// REGISTER MODULES ********************************************************************************
|
||||
|
||||
static ENABLED_MODULES: LazyStatic<RwLock<Vec<ModuleStaticRef>>> =
|
||||
LazyStatic::new(|| RwLock::new(Vec::new()));
|
||||
|
||||
pub fn enable_modules(modules: Vec<ModuleStaticRef>) {
|
||||
for module in modules {
|
||||
static DISCARDED_MODULES: LazyStatic<RwLock<Vec<ModuleStaticRef>>> =
|
||||
LazyStatic::new(|| RwLock::new(Vec::new()));
|
||||
|
||||
pub fn register_modules(app: ModuleStaticRef) {
|
||||
// Revisa los módulos a deshabilitar.
|
||||
let mut list: Vec<ModuleStaticRef> = Vec::new();
|
||||
add_to_enabled(&mut list, module);
|
||||
add_to_discarded(&mut list, app);
|
||||
DISCARDED_MODULES.write().unwrap().append(&mut list);
|
||||
|
||||
// Habilita los módulos de la aplicación.
|
||||
let mut list: Vec<ModuleStaticRef> = Vec::new();
|
||||
add_to_enabled(&mut list, app);
|
||||
list.reverse();
|
||||
ENABLED_MODULES.write().unwrap().append(&mut list);
|
||||
}
|
||||
|
||||
fn add_to_discarded(list: &mut Vec<ModuleStaticRef>, module: ModuleStaticRef) {
|
||||
for u in module.uninstall_modules().iter() {
|
||||
if !list.iter().any(|m| m.handler() == u.handler()) {
|
||||
list.push(*u);
|
||||
trace::debug!("Module \"{}\" discarded", u.single_name());
|
||||
}
|
||||
}
|
||||
for d in module.dependencies().iter() {
|
||||
add_to_discarded(list, *d);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_to_enabled(list: &mut Vec<ModuleStaticRef>, module: ModuleStaticRef) {
|
||||
if !ENABLED_MODULES
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|m| m.handler() == module.handler())
|
||||
&& !list.iter().any(|m| m.handler() == module.handler())
|
||||
{
|
||||
if DISABLED_MODULES
|
||||
if !list.iter().any(|m| m.handler() == module.handler()) {
|
||||
if DISCARDED_MODULES
|
||||
.read()
|
||||
.unwrap()
|
||||
.iter()
|
||||
|
|
@ -58,7 +54,6 @@ fn add_to_enabled(list: &mut Vec<ModuleStaticRef>, module: ModuleStaticRef) {
|
|||
module.single_name()
|
||||
);
|
||||
} else {
|
||||
trace::debug!("Enabling the \"{}\" module", module.single_name());
|
||||
list.push(module);
|
||||
|
||||
let mut dependencies = module.dependencies();
|
||||
|
|
@ -66,23 +61,21 @@ fn add_to_enabled(list: &mut Vec<ModuleStaticRef>, module: ModuleStaticRef) {
|
|||
for d in dependencies.iter() {
|
||||
add_to_enabled(list, *d);
|
||||
}
|
||||
|
||||
trace::debug!("Enabling \"{}\" module", module.single_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CONFIGURE MODULES *******************************************************************************
|
||||
// REGISTER THEMES *********************************************************************************
|
||||
|
||||
pub fn init_modules() {
|
||||
pub fn register_themes() {
|
||||
for m in ENABLED_MODULES.read().unwrap().iter() {
|
||||
m.init_module();
|
||||
theme::all::register_themes(m.themes());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configure_services(cfg: &mut app::web::ServiceConfig) {
|
||||
for m in ENABLED_MODULES.read().unwrap().iter() {
|
||||
m.configure_service(cfg);
|
||||
}
|
||||
}
|
||||
// REGISTER ACTIONS ********************************************************************************
|
||||
|
||||
pub fn register_actions() {
|
||||
for m in ENABLED_MODULES.read().unwrap().iter() {
|
||||
|
|
@ -92,23 +85,10 @@ pub fn register_actions() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
pub(crate) fn run_migrations() {
|
||||
run_now({
|
||||
struct Migrator;
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<MigrationItem> {
|
||||
let mut migrations = vec![];
|
||||
for m in DISABLED_MODULES.read().unwrap().iter() {
|
||||
migrations.append(&mut m.migrations());
|
||||
}
|
||||
migrations
|
||||
}
|
||||
}
|
||||
Migrator::down(&app::db::DBCONN, None)
|
||||
})
|
||||
.unwrap();
|
||||
// RUN MIGRATIONS **********************************************************************************
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
pub fn run_migrations() {
|
||||
run_now({
|
||||
struct Migrator;
|
||||
impl MigratorTrait for Migrator {
|
||||
|
|
@ -123,4 +103,36 @@ pub(crate) fn run_migrations() {
|
|||
Migrator::up(&app::db::DBCONN, None)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
run_now({
|
||||
struct Migrator;
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<MigrationItem> {
|
||||
let mut migrations = vec![];
|
||||
for m in DISCARDED_MODULES.read().unwrap().iter() {
|
||||
migrations.append(&mut m.migrations());
|
||||
}
|
||||
migrations
|
||||
}
|
||||
}
|
||||
Migrator::down(&app::db::DBCONN, None)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// INIT MODULES ************************************************************************************
|
||||
|
||||
pub fn init_modules() {
|
||||
trace::info!("Calling application bootstrap");
|
||||
for m in ENABLED_MODULES.read().unwrap().iter() {
|
||||
m.init();
|
||||
}
|
||||
}
|
||||
|
||||
// CONFIGURE SERVICES ******************************************************************************
|
||||
|
||||
pub fn configure_services(cfg: &mut app::web::ServiceConfig) {
|
||||
for m in ENABLED_MODULES.read().unwrap().iter() {
|
||||
m.configure_service(cfg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::app;
|
||||
use crate::core::hook::HookAction;
|
||||
use crate::core::theme::ThemeStaticRef;
|
||||
use crate::util::{single_type_name, Handler};
|
||||
|
||||
#[cfg(feature = "database")]
|
||||
|
|
@ -27,10 +28,13 @@ pub trait ModuleTrait: BaseModule + Send + Sync {
|
|||
vec![]
|
||||
}
|
||||
|
||||
fn init_module(&self) {}
|
||||
fn uninstall_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn configure_service(&self, cfg: &mut app::web::ServiceConfig) {}
|
||||
fn themes(&self) -> Vec<ThemeStaticRef> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn actions(&self) -> Vec<HookAction> {
|
||||
vec![]
|
||||
|
|
@ -41,6 +45,11 @@ pub trait ModuleTrait: BaseModule + Send + Sync {
|
|||
fn migrations(&self) -> Vec<MigrationItem> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn init(&self) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn configure_service(&self, cfg: &mut app::web::ServiceConfig) {}
|
||||
}
|
||||
|
||||
impl<M: ?Sized + ModuleTrait> BaseModule for M {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
use super::ThemeStaticRef;
|
||||
use crate::{app, theme_static_files, trace, LazyStatic};
|
||||
use crate::{app, base, theme_static_files, trace, LazyStatic};
|
||||
|
||||
use std::sync::RwLock;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/theme.rs"));
|
||||
|
||||
// Temas registrados.
|
||||
static THEMES: LazyStatic<RwLock<Vec<ThemeStaticRef>>> =
|
||||
LazyStatic::new(|| RwLock::new(Vec::new()));
|
||||
static THEMES: LazyStatic<RwLock<Vec<ThemeStaticRef>>> = LazyStatic::new(|| {
|
||||
RwLock::new(vec![
|
||||
&base::theme::aliner::Aliner,
|
||||
&base::theme::minimal::Minimal,
|
||||
&base::theme::bootsier::Bootsier,
|
||||
&base::theme::bulmix::Bulmix,
|
||||
])
|
||||
});
|
||||
|
||||
pub fn register_themes(themes: Vec<ThemeStaticRef>) {
|
||||
let mut registered_themes = THEMES.write().unwrap();
|
||||
|
|
|
|||
|
|
@ -19,12 +19,13 @@ pub use crate::{db, db::*, migration_item, pub_migration};
|
|||
pub use crate::app;
|
||||
pub use crate::app::application::Application;
|
||||
pub use crate::app::fatal_error::FatalError;
|
||||
pub use crate::app::{AppTrait, HttpMessage};
|
||||
pub use crate::app::HttpMessage;
|
||||
|
||||
pub use crate::core::{component::*, hook::*, module::*, theme::*};
|
||||
|
||||
pub use crate::{hook_action, hook_before_render_component};
|
||||
|
||||
pub use crate::response::page::*;
|
||||
pub use crate::response::ResponseError;
|
||||
|
||||
pub use crate::base::component::*;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ path = "../pagetop"
|
|||
[dependencies]
|
||||
actix-web = "4.1.0"
|
||||
static-files = "0.2.3"
|
||||
#pagetop-mdbook = { path = "../pagetop-mdbook" }
|
||||
maud = { git = "https://github.com/lambda-fairy/maud", rev = "e6787cd6" }
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
|||
|
|
@ -1,16 +1,25 @@
|
|||
use pagetop::prelude::*;
|
||||
|
||||
pub_const_handler!(APP_PAGETOP_WEBSITE);
|
||||
|
||||
mod mdbook;
|
||||
|
||||
struct PageTopWebSite;
|
||||
|
||||
impl AppTrait for PageTopWebSite {
|
||||
fn enable_modules(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![&mdbook::MdBook]
|
||||
impl ModuleTrait for PageTopWebSite {
|
||||
fn handler(&self) -> Handler {
|
||||
APP_PAGETOP_WEBSITE
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<ModuleStaticRef> {
|
||||
vec![
|
||||
&mdbook::MdBook,
|
||||
&pagetop::base::module::homepage::DefaultHomePage,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
Application::prepare(PageTopWebSite).await?.run()?.await
|
||||
Application::prepare(&PageTopWebSite).await?.run()?.await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ use static_files::Resource;
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub_const_handler!(MODULE_MDBOOK);
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/mdbook.rs"));
|
||||
|
||||
static MDBOOK: LazyStatic<HashMap<&'static str, Resource>> = LazyStatic::new(generate);
|
||||
|
||||
pub_const_handler!(MODULE_MDBOOK);
|
||||
|
||||
pub struct MdBook;
|
||||
|
||||
impl ModuleTrait for MdBook {
|
||||
|
|
@ -19,19 +19,41 @@ impl ModuleTrait for MdBook {
|
|||
}
|
||||
|
||||
fn configure_service(&self, cfg: &mut app::web::ServiceConfig) {
|
||||
cfg.service(
|
||||
app::web::scope("/doc")
|
||||
.route("{tail:.*html$}", app::web::get().to(mdbook_page))
|
||||
.route("{tail:.*$}", app::web::get().to(mdbook_resource)),
|
||||
);
|
||||
configure_mdbook_service(cfg, "/doc/", &MDBOOK);
|
||||
}
|
||||
}
|
||||
|
||||
async fn mdbook_page(request: app::HttpRequest) -> ResultPage<Markup, FatalError> {
|
||||
// Remove initial "/doc/" from path:
|
||||
let path = &request.path()[5..];
|
||||
fn configure_mdbook_service(
|
||||
cfg: &mut app::web::ServiceConfig,
|
||||
url_root: &'static str,
|
||||
book: &'static HashMap<&'static str, Resource>,
|
||||
) {
|
||||
let url = url_root.trim_end_matches('/');
|
||||
let url_len = url.len() + 1;
|
||||
cfg.service(
|
||||
app::web::scope(url)
|
||||
.route(
|
||||
"{tail:.*html$}",
|
||||
app::web::get()
|
||||
.to(move |request: app::HttpRequest| mdbook_page(request, url_len, book)),
|
||||
)
|
||||
.route(
|
||||
"{tail:.*$}",
|
||||
app::web::get()
|
||||
.to(move |request: app::HttpRequest| mdbook_resource(request, url_len, book)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(content) = MDBOOK.get(path) {
|
||||
async fn mdbook_page(
|
||||
request: app::HttpRequest,
|
||||
v: usize,
|
||||
book: &HashMap<&'static str, Resource>,
|
||||
) -> ResultPage<Markup, FatalError> {
|
||||
// Remove initial "/doc/" from path:
|
||||
let path = &request.path()[v..];
|
||||
|
||||
if let Some(content) = book.get(path) {
|
||||
if let Ok(html) = std::str::from_utf8(content.data) {
|
||||
let _lang = extract("Lang", html);
|
||||
let title = match extract("Title", html) {
|
||||
|
|
@ -93,13 +115,17 @@ async fn mdbook_page(request: app::HttpRequest) -> ResultPage<Markup, FatalError
|
|||
}
|
||||
}
|
||||
|
||||
async fn mdbook_resource(request: app::HttpRequest) -> app::HttpResponse {
|
||||
async fn mdbook_resource(
|
||||
request: app::HttpRequest,
|
||||
v: usize,
|
||||
book: &HashMap<&'static str, Resource>,
|
||||
) -> app::HttpResponse {
|
||||
// Remove initial "/doc/" from path:
|
||||
let path = &request.path()[5..];
|
||||
let path = &request.path()[v..];
|
||||
|
||||
// From https://github.com/kilork/actix-web-static-files/blob/master/src/resource_files.rs, see
|
||||
// functions respond_to(), any_match() and none_match().
|
||||
if let Some(file) = &MDBOOK.get(path) {
|
||||
if let Some(file) = &book.get(path) {
|
||||
let etag = Some(app::http::header::EntityTag::new_strong(format!(
|
||||
"{:x}:{:x}",
|
||||
file.data.len(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue