miniweb/src/main.rs

105 lines
3.0 KiB
Rust

mod admin;
mod howto;
mod service;
mod state;
use crate::admin::example;
use crate::service::{handlers, templates};
use crate::state::AppState;
use axum::{
extract::State, handler::HandlerWithoutStateExt, response::IntoResponse, routing::get, Router,
};
use dotenvy::dotenv;
use log::info;
use std::env;
use std::net::SocketAddr;
use std::sync::Arc;
async fn home(templates: State<templates::Templates>) -> impl IntoResponse {
templates.render_html("index.html", ())
}
async fn hello_world(templates: State<templates::Templates>) -> impl IntoResponse {
templates.render_html("hello_world.html", ())
}
#[tokio::main]
async fn main() {
// Load environment
dotenv().ok();
env_logger::init();
info!("Miniweb starting...");
// Prepare App State
let tmpl = templates::Templates::initialize().expect("Template Engine could not be loaded.");
let mut admin = admin::state::AdminRegistry::new("admin");
example::register_example(&mut admin);
let state: AppState = AppState {
templates: tmpl,
admin: Arc::new(admin),
};
// Application Route
let app = Router::new()
.route("/", get(home))
.route("/hello", get(hello_world))
//.merge(admin_router)
.nest("/admin", admin::routes())
.nest("/howto", howto::routes())
.route_service("/static/*file", handlers::static_handler.into_service())
.fallback(handlers::not_found_handler)
.with_state(state);
// Run Server
let app_host: std::net::IpAddr = env::var("APP_HOST")
.unwrap_or("0.0.0.0".to_string())
.parse()
.expect("IP Address expected in APP_HOST");
let app_port: u16 = env::var("APP_PORT")
.unwrap_or("3000".to_string())
.parse()
.expect("Port expected in APP_PORT");
// the listen_addr is the address we bind to. This might be multiple domains, like 0.0.0.0
let listen_addr = SocketAddr::from((app_host, app_port));
// the server addr is a concrete address the user can connect to.
let server_addr = if app_host.is_unspecified() {
SocketAddr::from(([127, 0, 0, 1], app_port))
} else {
listen_addr.clone()
};
info!("listening on {}", listen_addr);
info!("admin on: http://{}/admin", server_addr);
axum::Server::bind(&listen_addr)
.serve(app.into_make_service())
.with_graceful_shutdown(shutdown_signal())
.await
.unwrap();
}
async fn shutdown_signal() {
let ctrl_c = async {
tokio::signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
info!("shutting down...");
}