126 lines
3.7 KiB
Python
126 lines
3.7 KiB
Python
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
from typing import Optional
|
|
import os
|
|
|
|
|
|
class AppSettings(BaseSettings):
|
|
"""应用配置"""
|
|
|
|
# 基础配置
|
|
app_name: str = "xiaoxia-saas"
|
|
app_env: str = "development" # development / staging / production
|
|
app_version: str = "0.1.0"
|
|
debug: bool = True
|
|
|
|
# API 配置
|
|
api_host: str = "0.0.0.0"
|
|
api_port: int = 8000
|
|
api_prefix: str = "/api/v1"
|
|
|
|
# 数据库配置
|
|
database_url: str = "postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas"
|
|
database_pool_size: int = 20
|
|
database_max_overflow: int = 40
|
|
database_pool_timeout: int = 30
|
|
database_pool_recycle: int = 3600
|
|
|
|
# Redis 配置
|
|
redis_url: str = "redis://localhost:6379/0"
|
|
redis_max_connections: int = 50
|
|
|
|
# Celery 配置
|
|
celery_broker_url: str = "redis://localhost:6379/0"
|
|
celery_result_backend: str = "redis://localhost:6379/1"
|
|
celery_worker_concurrency: int = 4
|
|
celery_worker_max_tasks_per_child: int = 1000
|
|
|
|
# MinIO 配置
|
|
minio_endpoint: str = "localhost:9000"
|
|
minio_access_key: str = "admin"
|
|
minio_secret_key: str = "xiaoxia2026"
|
|
minio_bucket: str = "xiaoxia-assets"
|
|
minio_secure: bool = False
|
|
minio_public_url: str = "http://localhost:9000"
|
|
|
|
# 日志配置
|
|
log_level: str = "INFO"
|
|
log_format: str = "json" # json / text
|
|
log_file: Optional[str] = None
|
|
|
|
# CORS 配置
|
|
cors_origins: str = "http://localhost:3000,http://localhost:8000"
|
|
cors_allow_credentials: bool = True
|
|
|
|
# 文件上传限制
|
|
max_upload_size_mb: int = 1000
|
|
allowed_file_types: str = "video/mp4,video/quicktime,video/x-msvideo,audio/mpeg,audio/wav,image/jpeg,image/png,image/gif"
|
|
|
|
# 安全配置
|
|
secret_key: str = "change-me-in-production"
|
|
access_token_expire_minutes: int = 60
|
|
refresh_token_expire_days: int = 7
|
|
|
|
# 监控配置(可选)
|
|
sentry_dsn: Optional[str] = None
|
|
prometheus_port: Optional[int] = None
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
case_sensitive=False,
|
|
extra="ignore",
|
|
)
|
|
|
|
@property
|
|
def cors_origins_list(self) -> list[str]:
|
|
"""解析 CORS origins 为列表"""
|
|
return [origin.strip() for origin in self.cors_origins.split(",")]
|
|
|
|
@property
|
|
def allowed_file_types_list(self) -> list[str]:
|
|
"""解析允许的文件类型为列表"""
|
|
return [ft.strip() for ft in self.allowed_file_types.split(",")]
|
|
|
|
@property
|
|
def is_production(self) -> bool:
|
|
"""是否为生产环境"""
|
|
return self.app_env == "production"
|
|
|
|
@property
|
|
def is_staging(self) -> bool:
|
|
"""是否为 staging 环境"""
|
|
return self.app_env == "staging"
|
|
|
|
@property
|
|
def is_development(self) -> bool:
|
|
"""是否为开发环境"""
|
|
return self.app_env == "development"
|
|
|
|
|
|
# 全局配置实例
|
|
_settings: Optional[AppSettings] = None
|
|
|
|
|
|
def get_settings() -> AppSettings:
|
|
"""获取配置实例(单例模式)"""
|
|
global _settings
|
|
if _settings is None:
|
|
# 根据环境加载不同的 .env 文件
|
|
env = os.getenv("APP_ENV", "development")
|
|
env_file = f".env.{env}" if env != "development" else ".env"
|
|
|
|
# 如果环境特定的配置文件存在,则使用它
|
|
if os.path.exists(env_file):
|
|
_settings = AppSettings(_env_file=env_file)
|
|
else:
|
|
_settings = AppSettings()
|
|
|
|
return _settings
|
|
|
|
|
|
def reload_settings():
|
|
"""重新加载配置(用于测试)"""
|
|
global _settings
|
|
_settings = None
|
|
return get_settings()
|