adminx/configs/
initializer.rs

1// src/configs/initializer.rs
2use log::{info, debug, warn};
3use mongodb::Database;
4use anyhow::{Error as AnyhowError};
5use actix_web::{web};
6use actix_session::{SessionMiddleware, storage::CookieSessionStore, config::PersistentSession};
7use actix_web::cookie::{Key, SameSite};
8use env_logger::Env;
9use std::{env, time::Duration};
10use crate::router::register_all_admix_routes;
11use crate::utils::{
12    database::{
13        initiate_database
14    },
15};
16
17#[derive(Debug, Clone)]
18pub struct AdminxConfig {
19    pub jwt_secret: String,
20    pub session_secret: String,
21    pub environment: String,
22    pub log_level: String,
23    pub session_timeout: Duration,
24}
25
26impl AdminxConfig {
27    pub fn from_env() -> Result<Self, Box<dyn std::error::Error>> {
28        Ok(Self {
29            jwt_secret: env::var("JWT_SECRET")
30                .map_err(|_| "JWT_SECRET is required")?,
31            session_secret: env::var("SESSION_SECRET")
32                .unwrap_or_else(|_| {
33                    if cfg!(debug_assertions) {
34                        warn!("⚠️  SESSION_SECRET not set, using generated key - NOT suitable for production!");
35                        String::new() // Will trigger key generation
36                    } else {
37                        panic!("SESSION_SECRET is required in production");
38                    }
39                }),
40            environment: env::var("ENVIRONMENT")
41                .unwrap_or_else(|_| "development".to_string()),
42            log_level: env::var("RUST_LOG")
43                .unwrap_or_else(|_| "debug".to_string()),
44            session_timeout: Duration::from_secs(
45                env::var("SESSION_TIMEOUT")
46                    .unwrap_or_else(|_| "86400".to_string())
47                    .parse()
48                    .unwrap_or(86400)
49            ),
50        })
51    }
52    
53    pub fn is_production(&self) -> bool {
54        self.environment == "production"
55    }
56}
57
58fn load_session_key(config: &AdminxConfig) -> Key {
59    if config.session_secret.is_empty() {
60        if cfg!(debug_assertions) {
61            warn!("⚠️  Using generated session key - NOT suitable for production!");
62            Key::generate()
63        } else {
64            panic!("SESSION_SECRET environment variable is required in production");
65        }
66    } else {
67        if config.session_secret.len() < 64 {
68            panic!("SESSION_SECRET must be at least 64 characters long");
69        }
70        Key::from(config.session_secret.as_bytes())
71    }
72}
73
74fn create_session_middleware(config: &AdminxConfig) -> SessionMiddleware<CookieSessionStore> {
75    let secret_key = load_session_key(config);
76    
77    // Convert std::time::Duration to actix_web::cookie::time::Duration
78    let session_ttl = actix_web::cookie::time::Duration::seconds(config.session_timeout.as_secs() as i64);
79    
80    SessionMiddleware::builder(
81        CookieSessionStore::default(),
82        secret_key
83    )
84    .cookie_name("adminx_session".to_string())
85    .cookie_secure(config.is_production())
86    .cookie_http_only(true)
87    .cookie_same_site(if config.is_production() { 
88        SameSite::Strict 
89    } else { 
90        SameSite::Lax 
91    })
92    .session_lifecycle(
93        PersistentSession::default()
94            .session_ttl(session_ttl)
95    )
96    .build()
97}
98
99// Component-based approach - much cleaner!
100pub fn get_adminx_config() -> AdminxConfig {
101    AdminxConfig::from_env().unwrap_or_else(|e| {
102        eprintln!("❌ AdminX configuration error: {}", e);
103        std::process::exit(1);
104    })
105}
106
107pub fn setup_adminx_logging(config: &AdminxConfig) {
108    if env::var("ADMINX_LOGGING_INITIALIZED").is_err() {
109        let _ = env_logger::Builder::from_env(Env::default().default_filter_or(&config.log_level))
110            .format_timestamp_millis()
111            .try_init();
112        
113        env::set_var("ADMINX_LOGGING_INITIALIZED", "true");
114        info!("✅ AdminX logging initialized");
115        info!("🔧 AdminX environment: {}", config.environment);
116        debug!("🔍 AdminX debug logging active");
117    }
118}
119
120pub fn get_adminx_session_middleware(config: &AdminxConfig) -> SessionMiddleware<CookieSessionStore> {
121    create_session_middleware(config)
122}
123
124// Alternative using service configuration
125pub fn configure_adminx_services(cfg: &mut web::ServiceConfig) {
126    let config = get_adminx_config();
127    cfg.app_data(web::Data::new(config));
128    cfg.service(register_all_admix_routes());
129
130}
131
132pub async fn adminx_initialize(db: Database) -> Result<(), AnyhowError> {
133    let _ = initiate_database(db);
134    // let _ = ADMINX_TEMPLATES.len();
135    info!("AdminX initialized successfully");
136    Ok(())
137}