jae-blog/src/main.rs

162 lines
4.5 KiB
Rust
Raw Normal View History

2024-04-30 11:44:40 +03:00
#![feature(let_chains)]
2024-04-18 04:05:38 +03:00
2024-05-08 23:03:10 +03:00
mod app;
2024-04-18 04:05:38 +03:00
mod config;
mod error;
mod filters;
mod hash_arc_store;
mod markdown_render;
mod post;
mod ranged_i128_visitor;
mod systemtime_as_secs;
2024-04-18 04:05:38 +03:00
use std::future::IntoFuture;
use std::net::SocketAddr;
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;
use color_eyre::eyre::{self, Context};
use tokio::net::TcpListener;
use tokio::task::JoinSet;
use tokio::{select, signal};
2024-04-18 04:05:38 +03:00
use tokio_util::sync::CancellationToken;
use tracing::level_filters::LevelFilter;
2024-05-08 23:03:10 +03:00
use tracing::{debug, info, warn};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::{util::SubscriberInitExt, EnvFilter};
2024-04-18 04:05:38 +03:00
2024-05-08 23:03:10 +03:00
use crate::app::AppState;
use crate::post::{MarkdownPosts, PostManager};
2024-04-18 04:05:38 +03:00
#[tokio::main]
async fn main() -> eyre::Result<()> {
#[cfg(feature = "tokio-console")]
console_subscriber::init();
color_eyre::install()?;
#[cfg(not(feature = "tokio-console"))]
tracing_subscriber::registry()
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.with(tracing_subscriber::fmt::layer())
.init();
2024-05-08 23:03:10 +03:00
let config = Arc::new(
config::load()
.await
.context("couldn't load configuration")?,
);
2024-04-18 04:05:38 +03:00
2024-05-01 18:25:01 +03:00
let socket_addr = SocketAddr::new(config.http.host, config.http.port);
2024-04-18 04:05:38 +03:00
let mut tasks = JoinSet::new();
let cancellation_token = CancellationToken::new();
2024-04-18 04:05:38 +03:00
let posts = Arc::new(MarkdownPosts::new(Arc::clone(&config)).await?);
2024-05-08 23:03:10 +03:00
let state = AppState {
config: Arc::clone(&config),
2024-05-09 11:30:18 +03:00
posts: Arc::clone(&posts),
2024-04-18 04:05:38 +03:00
};
2024-05-08 23:03:10 +03:00
if config.cache.enable && config.cache.cleanup {
if let Some(t) = config.cache.cleanup_interval {
2024-05-09 11:30:18 +03:00
let posts = Arc::clone(&posts);
let token = cancellation_token.child_token();
debug!("setting up cleanup task");
tasks.spawn(async move {
let mut interval = tokio::time::interval(Duration::from_millis(t));
loop {
select! {
_ = token.cancelled() => break,
_ = interval.tick() => {
2024-05-09 11:30:18 +03:00
posts.cleanup().await
}
}
}
});
} else {
2024-05-09 11:30:18 +03:00
posts.cleanup().await;
}
}
let app = app::new(&config).with_state(state.clone());
2024-04-18 04:05:38 +03:00
2024-05-01 18:25:01 +03:00
let listener = TcpListener::bind(socket_addr)
2024-04-18 04:05:38 +03:00
.await
2024-05-01 18:25:01 +03:00
.with_context(|| format!("couldn't listen on {}", socket_addr))?;
2024-04-18 04:05:38 +03:00
let local_addr = listener
.local_addr()
2024-04-18 19:17:33 +03:00
.context("couldn't get socket address")?;
2024-04-18 04:05:38 +03:00
info!("listening on http://{}", local_addr);
let sigint = signal::ctrl_c();
#[cfg(unix)]
let mut sigterm_handler =
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())?;
#[cfg(unix)]
let sigterm = sigterm_handler.recv();
#[cfg(not(unix))] // TODO: kill all windows server users
let sigterm = std::future::pending::<()>();
let axum_token = cancellation_token.child_token();
2024-04-18 04:05:38 +03:00
let mut server = axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.with_graceful_shutdown(async move { axum_token.cancelled().await })
.into_future();
tokio::select! {
result = &mut server => {
2024-04-18 19:17:33 +03:00
result.context("failed to serve app")?;
2024-04-18 04:05:38 +03:00
},
_ = sigint => {
info!("received SIGINT, exiting gracefully");
},
_ = sigterm => {
info!("received SIGTERM, exiting gracefully");
}
};
let cleanup = async move {
// stop tasks
cancellation_token.cancel();
2024-04-18 19:17:33 +03:00
server.await.context("failed to serve app")?;
2024-04-18 04:05:38 +03:00
while let Some(task) = tasks.join_next().await {
2024-04-18 19:17:33 +03:00
task.context("failed to join task")?;
2024-04-18 04:05:38 +03:00
}
2024-05-08 23:03:10 +03:00
drop(state);
2024-04-18 04:05:38 +03:00
Ok::<(), color_eyre::Report>(())
};
let sigint = signal::ctrl_c();
#[cfg(unix)]
let mut sigterm_handler =
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())?;
#[cfg(unix)]
let sigterm = sigterm_handler.recv();
#[cfg(not(unix))]
let sigterm = std::future::pending::<()>();
tokio::select! {
result = cleanup => {
2024-04-18 19:17:33 +03:00
result.context("cleanup failed, oh well")?;
2024-04-18 04:05:38 +03:00
},
_ = sigint => {
warn!("received second signal, exiting");
exit(1);
},
_ = sigterm => {
warn!("received second signal, exiting");
exit(1);
}
}
Ok(())
}