155 lines
4.5 KiB
Rust
155 lines
4.5 KiB
Rust
mod frontend_api;
|
|
mod frontend_render;
|
|
mod manifest;
|
|
mod static_serve;
|
|
mod summary_proxy;
|
|
|
|
use crate::frontend_api::create_frontend_api;
|
|
use crate::frontend_render::{new_frontend_render_router, FrontendConfig};
|
|
use crate::manifest::handle_manifest;
|
|
use crate::static_serve::{static_serve, static_serve_svg, static_serve_sw};
|
|
use crate::summary_proxy::generate_summary;
|
|
use axum::routing::{any, get};
|
|
use axum::Router;
|
|
use axum_extra::TypedHeader;
|
|
use dotenvy::dotenv;
|
|
use headers::CacheControl;
|
|
use hyper::StatusCode;
|
|
use magnetar_common::config::MagnetarConfig;
|
|
use miette::{miette, IntoDiagnostic};
|
|
use std::net::SocketAddr;
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use tera::Tera;
|
|
use thiserror::Error;
|
|
use tokio::net::TcpListener;
|
|
use tokio::signal;
|
|
use tower_http::services::ServeFile;
|
|
use tower_http::trace::TraceLayer;
|
|
use tracing::error;
|
|
use tracing::log::info;
|
|
use tracing_subscriber::EnvFilter;
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum RouterSetupError {
|
|
#[error("Failed to load template: {0}")]
|
|
TemplateLoadError(#[from] tera::Error),
|
|
}
|
|
|
|
fn new_calckey_fe_router(config: &'static MagnetarConfig) -> Result<Router, RouterSetupError> {
|
|
let tera = Tera::new("fe_calckey/frontend/assets-be/template/**/*.html")?;
|
|
let frontend_renderer_config = FrontendConfig {
|
|
magnetar_config: config,
|
|
templater: Arc::new(tera),
|
|
};
|
|
|
|
Ok(Router::new()
|
|
.nest_service(
|
|
"/favicon.ico",
|
|
ServeFile::new("fe_calckey/frontend/assets/favicon.ico"),
|
|
)
|
|
.nest_service(
|
|
"/favicon.png",
|
|
ServeFile::new("fe_calckey/frontend/assets/favicon.png"),
|
|
)
|
|
.nest_service(
|
|
"/favicon.svg",
|
|
ServeFile::new("fe_calckey/frontend/assets/favicon.svg"),
|
|
)
|
|
.route("/manifest.json", get(handle_manifest).with_state(config))
|
|
.nest(
|
|
"/sw.js",
|
|
static_serve_sw("fe_calckey/frontend/built/_sw_dist_/sw.js"),
|
|
)
|
|
.nest("/static-assets", static_serve("fe_calckey/frontend/assets"))
|
|
.nest(
|
|
"/client-assets",
|
|
static_serve("fe_calckey/frontend/client/assets"),
|
|
)
|
|
.nest(
|
|
"/assets",
|
|
static_serve("fe_calckey/frontend/built/_client_dist_"),
|
|
)
|
|
.nest(
|
|
"/twemoji",
|
|
static_serve_svg("fe_calckey/frontend/assets-be/twemoji"),
|
|
)
|
|
.nest("/fe-api", create_frontend_api("fe_calckey/frontend/assets"))
|
|
.route("/url", get(generate_summary))
|
|
.route(
|
|
"/streaming",
|
|
any(|| async {
|
|
(
|
|
StatusCode::SERVICE_UNAVAILABLE,
|
|
TypedHeader(
|
|
CacheControl::new()
|
|
.with_max_age(Duration::from_secs(0))
|
|
.with_private(),
|
|
),
|
|
)
|
|
}),
|
|
)
|
|
.nest("", new_frontend_render_router(frontend_renderer_config)))
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> miette::Result<()> {
|
|
dotenv().ok();
|
|
|
|
let filter_layer = EnvFilter::try_from_default_env()
|
|
.or_else(|_| EnvFilter::try_new("info"))
|
|
.unwrap();
|
|
|
|
tracing_subscriber::fmt()
|
|
.with_env_filter(filter_layer)
|
|
.with_test_writer()
|
|
.init();
|
|
|
|
let config = &*Box::leak::<'static>(Box::new(
|
|
magnetar_common::config::load_config().map_err(|e| miette!(e))?,
|
|
));
|
|
info!("Loaded configuration: {config:#?}");
|
|
|
|
let app = Router::new()
|
|
.layer(TraceLayer::new_for_http())
|
|
.nest("", new_calckey_fe_router(config).into_diagnostic()?);
|
|
|
|
let addr = SocketAddr::from((
|
|
config.calckey_frontend.bind_addr,
|
|
config.calckey_frontend.port,
|
|
));
|
|
tracing::info!("Binding to: {addr}");
|
|
let listener = TcpListener::bind(addr).await.into_diagnostic()?;
|
|
tracing::info!("Serving...");
|
|
axum::serve(listener, app.into_make_service())
|
|
.with_graceful_shutdown(shutdown_signal())
|
|
.await
|
|
.map_err(|e| miette!("Error running server: {}", e))
|
|
}
|
|
|
|
async fn shutdown_signal() {
|
|
let ctrl_c = async {
|
|
if let Err(e) = signal::ctrl_c().await {
|
|
error!("Ctrl+C signal handler error: {}", e);
|
|
}
|
|
};
|
|
|
|
#[cfg(unix)]
|
|
let terminate = async {
|
|
signal::unix::signal(signal::unix::SignalKind::terminate())
|
|
.expect("SIGTERM handler error")
|
|
.recv()
|
|
.await;
|
|
};
|
|
|
|
#[cfg(not(unix))]
|
|
let terminate = std::future::pending::<()>();
|
|
|
|
tokio::select! {
|
|
_ = ctrl_c => {},
|
|
_ = terminate => {},
|
|
}
|
|
|
|
info!("Shutting down...");
|
|
}
|