#![recursion_limit = "256"] mod assets; mod atproto; mod blobs; mod components; mod config; mod credits; mod deliverables; mod error; mod featured; mod form; mod forum; mod homepage; mod legal; mod mail; mod markdown; mod mods; mod oauth; mod page; mod profile; mod robots; mod s3; mod search; mod secrets; mod signup; mod sitemap; mod state; mod stats; mod transfer; use axum::Router; use config::{Command, Config}; use state::AppState; #[tokio::main] async fn main() { let config = Config::parse(); if let Some(Command::Feature { addresses }) = &config.command { if let Err(err) = featured::run(&config, addresses).await { eprintln!("{err:#}"); std::process::exit(1); } return; } let state = AppState::new(config) .await .expect("failed to initialize application state"); let listen = state.config.listen; atproto::tap::spawn(state.clone()); signup::spawn_cleanup(state.clone()); deliverables::spawn_sweep(state.clone()); let app = Router::new() .merge(oauth::router()) .merge(assets::router()) .merge(blobs::router()) .merge(deliverables::router()) .merge(mods::router()) .merge(transfer::router()) .merge(profile::router()) .merge(search::router()) .merge(homepage::router()) .merge(legal::router()) .merge(robots::router()) .merge(sitemap::router()) .merge(forum::router()) .merge(signup::router()) .with_state(state.clone()) .layer(axum::middleware::from_fn_with_state( state, oauth::refresh::renew_expiring_session, )); // Hot reloading. #[cfg(debug_assertions)] let app = app.layer(tower_livereload::LiveReloadLayer::new().request_predicate( |req: &axum::extract::Request| !req.headers().contains_key("hx-request"), )); #[cfg(debug_assertions)] let changes = tokio::sync::broadcast::channel(16).0; #[cfg(debug_assertions)] let _asset_watcher = assets::watch(changes.clone()); #[cfg(debug_assertions)] let app = app.merge(assets::reload_router(changes)); let listener = tokio::net::TcpListener::bind(listen).await.unwrap(); println!("listening on http://{}", listener.local_addr().unwrap()); // Sign-up rate-limits by the address each request came from. let app = app.into_make_service_with_connect_info::(); axum::serve(listener, app).await.unwrap(); }