""" Development environment configuration for Aniworld application. This module provides development-specific settings including debugging, hot-reloading, and relaxed security for local development. Environment Variables: JWT_SECRET_KEY: Secret key for JWT token signing (default: dev-secret) PASSWORD_SALT: Salt for password hashing (default: dev-salt) DATABASE_URL: Development database connection string (default: SQLite) LOG_LEVEL: Logging level (default: INFO) CORS_ORIGINS: Comma-separated list of allowed CORS origins API_RATE_LIMIT: API rate limit per minute (default: 1000) """ from typing import List from pydantic import Field, validator from pydantic_settings import BaseSettings class DevelopmentSettings(BaseSettings): """Development environment configuration settings.""" # ============================================================================ # Security Settings (Relaxed for Development) # ============================================================================ jwt_secret_key: str = Field( default="dev-secret-key-change-in-production", env="JWT_SECRET_KEY" ) """JWT secret key (non-production value for development).""" password_salt: str = Field( default="dev-salt-change-in-production", env="PASSWORD_SALT" ) """Password salt (non-production value for development).""" master_password_hash: str = Field( default="$2b$12$wP0KBVbJKVAb8CdSSXw0NeGTKCk" "bw4fSAFXIqR2/wDqPSEBn9w7lS", env="MASTER_PASSWORD_HASH" ) """Hash of the master password (dev: 'password').""" master_password: str = Field(default="password", env="MASTER_PASSWORD") """Master password for development (NEVER use in production).""" allowed_hosts: List[str] = Field( default=["localhost", "127.0.0.1", "*"], env="ALLOWED_HOSTS" ) """Allowed hosts (permissive for development).""" cors_origins: str = Field(default="*", env="CORS_ORIGINS") """CORS origins (allow all for development).""" # ============================================================================ # Database Settings # ============================================================================ database_url: str = Field( default="sqlite:///./data/aniworld_dev.db", env="DATABASE_URL" ) """Development database URL (SQLite by default).""" database_pool_size: int = Field(default=5, env="DATABASE_POOL_SIZE") """Database connection pool size.""" database_max_overflow: int = Field(default=10, env="DATABASE_MAX_OVERFLOW") """Maximum overflow connections for database pool.""" database_pool_recycle: int = Field( default=3600, env="DATABASE_POOL_RECYCLE" ) """Recycle database connections every N seconds.""" # ============================================================================ # API Settings # ============================================================================ api_rate_limit: int = Field(default=1000, env="API_RATE_LIMIT") """API rate limit per minute (relaxed for development).""" api_timeout: int = Field(default=60, env="API_TIMEOUT") """API request timeout in seconds (longer for debugging).""" # ============================================================================ # Logging Settings # ============================================================================ log_level: str = Field(default="INFO", env="LOG_LEVEL") """Logging level (INFO for standard output).""" log_file: str = Field(default="logs/development.log", env="LOG_FILE") """Path to development log file.""" log_rotation_size: int = Field(default=5_242_880, env="LOG_ROTATION_SIZE") """Log file rotation size in bytes (default: 5MB).""" log_retention_days: int = Field(default=7, env="LOG_RETENTION_DAYS") """Number of days to retain log files.""" # ============================================================================ # Performance Settings # ============================================================================ workers: int = Field(default=1, env="WORKERS") """Number of Uvicorn worker processes (single for development).""" worker_timeout: int = Field(default=120, env="WORKER_TIMEOUT") """Worker timeout in seconds.""" max_request_size: int = Field(default=104_857_600, env="MAX_REQUEST_SIZE") """Maximum request body size in bytes (default: 100MB).""" session_timeout_hours: int = Field( default=168, env="SESSION_TIMEOUT_HOURS" ) """Session timeout in hours (longer for development).""" # ============================================================================ # Provider Settings # ============================================================================ default_provider: str = Field( default="aniworld.to", env="DEFAULT_PROVIDER" ) """Default content provider.""" provider_timeout: int = Field(default=60, env="PROVIDER_TIMEOUT") """Provider request timeout in seconds (longer for debugging).""" provider_retries: int = Field(default=1, env="PROVIDER_RETRIES") """Number of retry attempts for provider requests.""" # ============================================================================ # Download Settings # ============================================================================ max_concurrent_downloads: int = Field( default=1, env="MAX_CONCURRENT_DOWNLOADS" ) """Maximum concurrent downloads (limited for development).""" download_timeout: int = Field(default=7200, env="DOWNLOAD_TIMEOUT") """Download timeout in seconds (default: 2 hours).""" # ============================================================================ # Application Paths # ============================================================================ anime_directory: str = Field( default="/tmp/aniworld_dev", env="ANIME_DIRECTORY" ) """Directory where anime is stored (development default).""" temp_directory: str = Field( default="/tmp/aniworld_dev/temp", env="TEMP_DIRECTORY" ) """Temporary directory for downloads and cache.""" # ============================================================================ # Validators # ============================================================================ @validator("log_level") @classmethod def validate_log_level(cls, v: str) -> str: """Validate log level is valid.""" valid_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} if v.upper() not in valid_levels: raise ValueError( f"Invalid log level '{v}'. Must be one of: {valid_levels}" ) return v.upper() @validator("cors_origins") @classmethod def parse_cors_origins(cls, v: str) -> str: """Parse comma-separated CORS origins.""" if not v: return "http://localhost,http://127.0.0.1" return v # ============================================================================ # Configuration # ============================================================================ class Config: """Pydantic config.""" env_file = ".env.development" extra = "ignore" case_sensitive = False # ============================================================================ # Properties # ============================================================================ @property def parsed_cors_origins(self) -> List[str]: """Get parsed CORS origins as list.""" if not self.cors_origins or self.cors_origins == "*": return ["*"] return [origin.strip() for origin in self.cors_origins.split(",")] @property def is_production(self) -> bool: """Check if running in production mode.""" return False @property def debug_enabled(self) -> bool: """Check if debug mode is enabled.""" return True @property def reload_enabled(self) -> bool: """Check if auto-reload is enabled.""" return True def get_development_settings() -> DevelopmentSettings: """ Get development settings instance. This is a factory function that should be called when settings are needed. Returns: DevelopmentSettings instance configured from environment variables """ return DevelopmentSettings() # Export factory for backward compatibility development_settings = DevelopmentSettings()