158 lines
5.2 KiB
Rust
158 lines
5.2 KiB
Rust
//! Prepare and run an application created with **Pagetop**.
|
|
|
|
mod figfont;
|
|
|
|
use crate::core::{package, package::PackageRef};
|
|
use crate::html::Markup;
|
|
use crate::response::page::{ErrorPage, ResultPage};
|
|
use crate::service::HttpRequest;
|
|
use crate::{global, locale, service, trace};
|
|
|
|
use actix_session::config::{BrowserSession, PersistentSession, SessionLifecycle};
|
|
use actix_session::storage::CookieSessionStore;
|
|
use actix_session::SessionMiddleware;
|
|
|
|
use substring::Substring;
|
|
|
|
use std::io::Error;
|
|
use std::sync::LazyLock;
|
|
|
|
pub struct Application;
|
|
|
|
impl Default for Application {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl Application {
|
|
/// Creates a new application instance without any package.
|
|
pub fn new() -> Self {
|
|
Self::internal_prepare(None)
|
|
}
|
|
|
|
/// Prepares an application instance with a specific package.
|
|
pub fn prepare(root_package: PackageRef) -> Self {
|
|
Self::internal_prepare(Some(root_package))
|
|
}
|
|
|
|
// Internal method to prepare the application, optionally with a package.
|
|
fn internal_prepare(root_package: Option<PackageRef>) -> Self {
|
|
// On startup, show the application banner.
|
|
Self::show_banner();
|
|
|
|
// Starts logging and event tracing.
|
|
LazyLock::force(&trace::TRACING);
|
|
|
|
// Validates the default language identifier.
|
|
LazyLock::force(&locale::LANGID_DEFAULT);
|
|
|
|
// Registers the application's packages.
|
|
package::all::register_packages(root_package);
|
|
|
|
// Registers package actions.
|
|
package::all::register_actions();
|
|
|
|
// Initializes the packages.
|
|
package::all::init_packages();
|
|
|
|
Self
|
|
}
|
|
|
|
// Displays the application banner based on the configuration.
|
|
fn show_banner() {
|
|
use terminal_size::{terminal_size, Width};
|
|
|
|
if global::SETTINGS.app.startup_banner.to_lowercase() != "off" {
|
|
// Application name, formatted for the terminal width if necessary.
|
|
let mut app_name = global::SETTINGS.app.name.to_string();
|
|
if let Some((Width(term_width), _)) = terminal_size() {
|
|
if term_width >= 80 {
|
|
let maxlen: usize = ((term_width / 10) - 2).into();
|
|
let mut app = app_name.substring(0, maxlen).to_owned();
|
|
if app_name.len() > maxlen {
|
|
app = format!("{app}...");
|
|
}
|
|
if let Some(ff) = figfont::FIGFONT.convert(&app) {
|
|
app_name = ff.to_string();
|
|
}
|
|
}
|
|
}
|
|
println!("\n{app_name}");
|
|
|
|
// Application description.
|
|
if !global::SETTINGS.app.description.is_empty() {
|
|
println!("{}\n", global::SETTINGS.app.description);
|
|
};
|
|
|
|
// PageTop version.
|
|
println!("Powered by PageTop {}\n", env!("CARGO_PKG_VERSION"));
|
|
}
|
|
}
|
|
|
|
/// Starts the web server.
|
|
pub fn run(self) -> Result<service::Server, Error> {
|
|
// Generate the cookie key.
|
|
let secret_key = service::cookie::Key::generate();
|
|
|
|
// Prepares the web server.
|
|
Ok(service::HttpServer::new(move || {
|
|
Self::service_app()
|
|
.wrap(tracing_actix_web::TracingLogger::default())
|
|
.wrap(
|
|
SessionMiddleware::builder(CookieSessionStore::default(), secret_key.clone())
|
|
.session_lifecycle(match global::SETTINGS.server.session_lifetime {
|
|
0 => SessionLifecycle::BrowserSession(BrowserSession::default()),
|
|
_ => SessionLifecycle::PersistentSession(
|
|
PersistentSession::default().session_ttl(
|
|
service::cookie::time::Duration::seconds(
|
|
global::SETTINGS.server.session_lifetime,
|
|
),
|
|
),
|
|
),
|
|
})
|
|
.build(),
|
|
)
|
|
})
|
|
.bind(format!(
|
|
"{}:{}",
|
|
&global::SETTINGS.server.bind_address,
|
|
&global::SETTINGS.server.bind_port
|
|
))?
|
|
.run())
|
|
}
|
|
|
|
/// Method for testing, returns a service application instance.
|
|
pub fn test(
|
|
self,
|
|
) -> service::App<
|
|
impl service::Factory<
|
|
service::Request,
|
|
Config = (),
|
|
Response = service::Response<service::BoxBody>,
|
|
Error = service::Error,
|
|
InitError = (),
|
|
>,
|
|
> {
|
|
Self::service_app()
|
|
}
|
|
|
|
// Configures the service application.
|
|
fn service_app() -> service::App<
|
|
impl service::Factory<
|
|
service::Request,
|
|
Config = (),
|
|
Response = service::Response<service::BoxBody>,
|
|
Error = service::Error,
|
|
InitError = (),
|
|
>,
|
|
> {
|
|
service::App::new()
|
|
.configure(package::all::configure_services)
|
|
.default_service(service::web::route().to(service_not_found))
|
|
}
|
|
}
|
|
|
|
async fn service_not_found(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
|
|
Err(ErrorPage::NotFound(request))
|
|
}
|