Rustelo/server/examples/root_path_example.rs
2025-07-07 23:05:19 +01:00

256 lines
7.7 KiB
Rust

use server::config::Config;
fn main() -> Result<(), Box<dyn std::error::Error>> {
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"));
}
}