webringer 1.0.3

A bin/lib crate for a webring site
Documentation
#![warn(clippy::pedantic, clippy::all, clippy::cargo)]
#![allow(clippy::module_name_repetitions, clippy::multiple_crate_versions)]
use axum::{
	Router,
	routing::{get, post},
};
use axum_login::AuthManagerLayerBuilder;
use axum_login::tower_sessions::{MemoryStore, SessionManagerLayer};
use axum_messages::MessagesManagerLayer;
use clap::Parser;
use tokio::signal;
use tracing::{Instrument, error, info, info_span, instrument, warn};

use webringer::ring;
use webringer::site;

mod args;
mod database;
mod embed;

#[tokio::main(flavor = "current_thread")]
#[instrument]
async fn main() {
	tracing_subscriber::fmt::init();
	let args = args::Args::parse();

	if let Err(e) = dotenvy::dotenv() {
		warn!("No .env file found: {}", e);
	}

	let address = format!("{}:{}", args.address, args.port);

	let db_pool = database::get_db_pool();

	let session_store = MemoryStore::default();
	let session_layer = SessionManagerLayer::new(session_store);
	let backend = ring::RingState::new(db_pool.await);
	let auth_layer = AuthManagerLayerBuilder::new(backend.clone(), session_layer).build();

	let router = Router::new()
		.route("/", get(site::index))
		.route("/join", get(site::join::get))
		.route("/join", post(site::join::post))
		.route("/leave", get(site::leave::get))
		.route("/leave", post(site::leave::post))
		.route("/next", get(site::ring::next))
		.route("/prev", get(site::ring::prev))
		.route("/random", get(site::ring::random))
		.route("/list", get(site::ring::list))
		.route("/login", get(site::login::get))
		.route("/login", post(site::login::post))
		.with_state(backend.clone())
		.nest("/admin", site::admin::router(backend))
		.layer(MessagesManagerLayer)
		.layer(auth_layer)
		.route("/static/{*file}", get(embed::static_handler))
		.fallback_service(get(embed::not_found));

	info!("Binding to {}", address);
	let listener = match tokio::net::TcpListener::bind(address)
		.instrument(info_span!("TcpListener bind"))
		.await
	{
		Ok(listener) => listener,
		Err(e) => {
			error!("Tcp binding error: {}", e);
			panic!()
		}
	};
	if let Err(e) = axum::serve(listener, router)
		.with_graceful_shutdown(async {
			if let Err(e) = signal::ctrl_c().await {
				error!("Failed to listen for ctrl_c signal: {}", e);
				panic!()
			}
			info!("Gracefully shutting down from SIGINT");
		})
		.await
	{
		error!("Axum serving error: {}", e);
	}
}