use server::config::Config; fn main() -> Result<(), Box> { println!("=== ROOT_PATH Configuration Example ===\n"); // Example 1: Using default root path (current directory) println!("1. Default ROOT_PATH behavior:"); let config = Config::load()?; println!(" Root path: {}", config.root_path); println!(" Assets dir: {}", config.static_files.assets_dir); println!(" Site root: {}", config.static_files.site_root); println!(" Logs dir: {}", config.server_dirs.logs_dir); println!(); // Example 2: Demonstrating path resolution with custom root println!("2. Path resolution with custom root:"); println!(" Note: ROOT_PATH can be set via environment variable"); println!(" Example: ROOT_PATH=/var/www/myapp ./my-app"); println!(" Current ROOT_PATH: {}", config.root_path); println!(); // Example 3: Using get_absolute_path method println!("3. Converting relative paths to absolute:"); let relative_path = "uploads/images"; match config.get_absolute_path(relative_path) { Ok(absolute_path) => { println!(" Relative: {}", relative_path); println!(" Absolute: {}", absolute_path); } Err(e) => { println!(" Error resolving path: {}", e); } } println!(); // Example 4: Demonstrating path resolution behavior println!("4. Path resolution examples:"); let test_cases = vec![ ("relative/path", "Relative path"), ("./config", "Current directory relative"), ("../parent", "Parent directory relative"), ("/absolute/path", "Absolute path (unchanged)"), ]; let config = Config::load()?; for (path, description) in test_cases { match config.get_absolute_path(path) { Ok(resolved) => { println!(" {} ({}): {}", description, path, resolved); } Err(e) => { println!(" {} ({}): Error - {}", description, path, e); } } } println!(); // Example 5: Configuration file paths println!("5. Configuration file discovery:"); println!(" The system looks for config files in this order:"); println!(" 1. Path specified by CONFIG_FILE environment variable"); println!(" 2. Environment-specific files (config.dev.toml, config.prod.toml)"); println!(" 3. Default config.toml"); println!(" 4. Searches from current directory up to root directory"); println!(); // Example 6: Directory structure with ROOT_PATH println!("6. Recommended directory structure:"); println!(" ROOT_PATH/"); println!(" ├── config.toml"); println!(" ├── config.dev.toml"); println!(" ├── config.prod.toml"); println!(" ├── public/ (static assets)"); println!(" ├── content/ (content files)"); println!(" ├── uploads/ (user uploads)"); println!(" ├── logs/ (application logs)"); println!(" ├── cache/ (temporary cache)"); println!(" ├── data/ (application data)"); println!(" └── backups/ (backup files)"); println!(); // Example 7: Environment variable usage println!("7. Useful environment variables:"); println!(" ROOT_PATH=/path/to/app # Set application root"); println!(" CONFIG_FILE=/path/config.toml # Override config file"); println!(" ENVIRONMENT=production # Set environment"); println!(" SERVER_HOST=0.0.0.0 # Override server host"); println!(" SERVER_PORT=8080 # Override server port"); println!(" DATABASE_URL=postgresql://... # Override database URL"); println!(); // Example 8: Docker deployment example println!("8. Docker deployment example:"); println!(" FROM rust:latest"); println!(" WORKDIR /app"); println!(" COPY . ."); println!(" ENV ROOT_PATH=/app"); println!(" ENV ENVIRONMENT=production"); println!(" RUN cargo build --release"); println!(" EXPOSE 3030"); println!(" CMD [\"./target/release/server\"]"); println!(); println!("✅ ROOT_PATH configuration example completed!"); println!("💡 Tips:"); println!(" - Use absolute paths in production for clarity"); println!(" - Set ROOT_PATH in your deployment environment"); println!(" - All relative paths in config files are resolved against ROOT_PATH"); println!(" - Directory creation is automatic if paths don't exist"); Ok(()) } #[cfg(test)] mod tests { use super::*; use std::fs; use tempfile::tempdir; #[test] fn test_root_path_resolution() { // Create a temporary directory structure let temp_dir = tempdir().unwrap(); let temp_path = temp_dir.path().to_string_lossy().to_string(); // Note: In real tests, you would set environment variables before process start // For this test, we'll create a config with a custom root path in the TOML // Create test directories let public_dir = temp_dir.path().join("public"); let logs_dir = temp_dir.path().join("logs"); fs::create_dir_all(&public_dir).unwrap(); fs::create_dir_all(&logs_dir).unwrap(); // Create a test config file with custom root path let config_content = format!( r#" root_path = "{}" [server] protocol = "http" host = "localhost" port = 3030 environment = "development" log_level = "info" [database] url = "postgresql://test:test@localhost:5432/test" max_connections = 10 min_connections = 1 connect_timeout = 30 idle_timeout = 600 max_lifetime = 1800 [session] secret = "test-secret" cookie_name = "session_id" cookie_secure = false cookie_http_only = true cookie_same_site = "lax" max_age = 3600 [cors] allowed_origins = ["http://localhost:3030"] allowed_methods = ["GET", "POST"] allowed_headers = ["Content-Type"] allow_credentials = true max_age = 3600 [static] assets_dir = "public" site_root = "target/site" site_pkg_dir = "pkg" [server_dirs] public_dir = "public" uploads_dir = "uploads" logs_dir = "logs" temp_dir = "tmp" cache_dir = "cache" config_dir = "config" data_dir = "data" backup_dir = "backups" [security] enable_csrf = true csrf_token_name = "csrf_token" rate_limit_requests = 100 rate_limit_window = 60 bcrypt_cost = 12 [oauth] enabled = false [email] enabled = false smtp_host = "localhost" smtp_port = 587 smtp_username = "" smtp_password = "" from_email = "test@example.com" from_name = "Test" [redis] enabled = false url = "redis://localhost:6379" pool_size = 10 connection_timeout = 5 command_timeout = 5 [app] name = "Test App" version = "0.1.0" debug = true enable_metrics = false enable_health_check = true enable_compression = true max_request_size = 10485760 [logging] format = "json" level = "info" file_path = "logs/app.log" max_file_size = 10485760 max_files = 5 enable_console = true enable_file = false [features] auth = true tls = false content_db = true two_factor_auth = false "#, temp_path.replace("\\", "\\\\") ); let config_path = temp_dir.path().join("config.toml"); fs::write(&config_path, config_content).unwrap(); // Test path resolution let config = Config::load_from_file(&config_path).unwrap(); // The public_dir should be resolved to an absolute path assert!(config.static_files.assets_dir.starts_with(&temp_path)); assert!(config.server_dirs.logs_dir.starts_with(&temp_path)); // Test get_absolute_path method let relative_path = "test/path"; let absolute_path = config.get_absolute_path(relative_path).unwrap(); assert!(absolute_path.contains(&temp_path)); assert!(absolute_path.contains("test/path")); } }