use actix_web::{web, App, HttpServer, middleware::Logger}; use actix_files as fs; use tera::Tera; use std::{io, env}; use dotenv::dotenv; mod config; mod controllers; mod middleware; mod models; mod routes; mod services; pub mod utils; // Session key for cookie store use actix_web::cookie::Key; use lazy_static::lazy_static; lazy_static! { static ref SESSION_KEY: Key = { // Load key from environment variable or generate a random one match env::var("SECRET_KEY") { Ok(key) if key.as_bytes().len() >= 32 => { Key::from(key.as_bytes()) } _ => { eprintln!("Warning: generating random key (sessions will be invalidated on restart)"); Key::generate() // Generates a secure 32-byte key } } }; } #[actix_web::main] async fn main() -> io::Result<()> { // Initialize environment dotenv().ok(); env_logger::init_from_env(env_logger::Env::default().default_filter_or("info")); // Load configuration let config = config::get_config(); // Check for port override from command line arguments let args: Vec = env::args().collect(); let mut port = config.server.port; for i in 1..args.len() { if args[i] == "--port" && i + 1 < args.len() { if let Ok(p) = args[i + 1].parse::() { port = p; break; } } } let bind_address = format!("{}:{}", config.server.host, port); // Create and configure the HTTP server HttpServer::new(move || { // Initialize Tera templates let mut tera = match Tera::new(&format!("{}/**/*.html", config.templates.dir)) { Ok(t) => t, Err(e) => { eprintln!("Tera initialization error: {}", e); ::std::process::exit(1); } }; // Register custom Tera functions utils::register_tera_functions(&mut tera); App::new() // Enable logger middleware .wrap(Logger::default()) // Add custom middleware .wrap(middleware::RequestTimer) .wrap(middleware::SecurityHeaders) // Re-enabled with improved error handling // Note: JWT middleware removed from global scope - now applied selectively in routes // Configure static files .service(fs::Files::new("/static", "./src/static")) // Add Tera template engine .app_data(web::Data::new(tera)) // Configure routes .configure(routes::configure_routes) }) .workers(config.server.workers.unwrap_or_else(|| num_cpus::get() as u32) as usize) .bind(bind_address)? .run() .await }