- Update fastapi_app.py to use INFO level instead of DEBUG - Update development.py config to default to INFO instead of DEBUG - Update uvicorn log_level from debug to info - Prevents debug messages from appearing in logs
240 lines
8.4 KiB
Python
240 lines
8.4 KiB
Python
"""
|
|
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()
|