use std::{net::SocketAddrV4, process::ExitCode}; use sqlx::sqlite::SqlitePool; use axum::Router; use leptos::prelude::*; use leptos_axum::{generate_route_list, LeptosRoutes}; use tokio::signal; use sparse_server::app::*; pub async fn serve_web(management_address: SocketAddrV4, db: SqlitePool) -> anyhow::Result { let conf = get_configuration(None).unwrap(); let leptos_options = conf.leptos_options; let routes = generate_route_list(App); let beacon_listeners = sparse_handler::BeaconListenerMap::default(); let compression_layer = tower_http::compression::CompressionLayer::new() .gzip(true) .deflate(true) .br(true) .zstd(true); sparse_handler::start_all_listeners(beacon_listeners.clone(), db.clone()).await?; let app = Router::new() .leptos_routes_with_context( &leptos_options, routes, move || { provide_context(beacon_listeners.clone()); provide_context::(db.clone()); }, { let leptos_options = leptos_options.clone(); move || shell(leptos_options.clone()) } ) .fallback(leptos_axum::file_and_error_handler::(shell)) .with_state(leptos_options) .layer( tower::ServiceBuilder::new() .layer(tower_http::trace::TraceLayer::new_for_http()) .layer(compression_layer) ); // run our app with hyper // `axum::Server` is a re-export of `hyper::Server` let management_listener = tokio::net::TcpListener::bind(&management_address).await?; tracing::info!("management interface listening on http://{}", &management_address); axum::serve(management_listener, app.into_make_service()) .with_graceful_shutdown(shutdown_signal()) .await?; Ok(ExitCode::SUCCESS) } async fn shutdown_signal() { let ctrl_c = async { signal::ctrl_c() .await .expect("failed to install Ctrl+C handler"); }; #[cfg(unix)] let terminate = async { signal::unix::signal(signal::unix::SignalKind::terminate()) .expect("failed to install signal handler") .recv() .await; }; #[cfg(not(unix))] let terminate = std::future::pending::<()>(); tokio::select! { _ = ctrl_c => { tracing::info!("Received Ctrl-C"); }, _ = terminate => { tracing::info!("Received terminate command"); }, } }