use std::env; use std::time::Duration; use actix_identity::IdentityMiddleware; use actix_session::SessionMiddleware; use actix_web::body::MessageBody; use actix_web::cookie::Key; use actix_web::dev::{ServiceFactory, ServiceRequest, ServiceResponse}; use actix_web::{web, App, HttpServer}; use actix_web_static_files::ResourceFiles; use brass_config::{get_env, load_config, Config}; use chrono::NaiveTime; use mail::Mailer; use sqlx::postgres::PgPool; use sqlx::{Pool, Postgres}; use tracing::info; use tracing_actix_web::TracingLogger; use tracing_panic::panic_hook; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{fmt, EnvFilter}; use utils::Customization; use crate::postgres_session_store::SqlxPostgresqlSessionStore; use crate::utils::manage_commands::{handle_command, parse_args}; mod endpoints; mod mail; mod middleware; mod models; mod utils; mod filters; mod postgres_session_store; include!(concat!(env!("OUT_DIR"), "/generated.rs")); include!(concat!(env!("OUT_DIR"), "/built.rs")); pub const START_OF_DAY: NaiveTime = NaiveTime::from_hms_opt(0, 0, 0).unwrap(); pub const END_OF_DAY: NaiveTime = NaiveTime::from_hms_opt(23, 59, 59).unwrap(); #[actix_web::main] async fn main() -> anyhow::Result<()> { let env = get_env()?; let config: Config = load_config(&env)?; init_tracing(); let args = parse_args()?; let pool = PgPool::connect(&config.database_url).await?; let mailer = Mailer::new(&config)?; let customization = Customization { webmaster_email: config.webmaster_email.clone(), }; handle_command(args.command, &pool, &mailer).await?; let address = config.server_address; let port = config.server_port; info!("Starting server on http://{address}:{port}."); HttpServer::new(move || { create_app( config.clone(), pool.clone(), mailer.clone(), customization.clone(), ) }) .bind((address, port))? .run() .await?; Ok(()) } pub fn create_app( config: Config, pool: Pool, mailer: Mailer, customization: Customization, ) -> App< impl ServiceFactory< ServiceRequest, Response = ServiceResponse, Config = (), InitError = (), Error = actix_web::error::Error, >, > { let generated = generate(); let secret_key = Key::from(config.secret_key.as_bytes()); let store = SqlxPostgresqlSessionStore::from_pool(pool.clone().into()); App::new() .app_data(web::Data::new(pool)) .app_data(web::Data::new(mailer)) .app_data(web::Data::new(customization)) .configure(endpoints::init) .wrap(middleware::ErrorAppender) .wrap(TracingLogger::default()) .wrap(middleware::RedirectToLogin) .wrap(middleware::LoadCurrentUser) .wrap( IdentityMiddleware::builder() .visit_deadline(Some(Duration::from_secs(300))) .build(), ) .wrap(SessionMiddleware::new(store.clone(), secret_key.clone())) .service(ResourceFiles::new("/static", generated)) } fn init_tracing() { let filter = EnvFilter::try_from_default_env() .or_else(|_| EnvFilter::try_new("info")) .unwrap(); tracing_subscriber::registry() .with(fmt::layer()) .with(filter) .init(); std::panic::set_hook(Box::new(panic_hook)); }