conf.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from functools import lru_cache
  4. from typing import Literal
  5. from dotenv import load_dotenv
  6. from pydantic import model_validator
  7. from pydantic_settings import BaseSettings, SettingsConfigDict
  8. from core.path_conf import BasePath
  9. class Settings(BaseSettings):
  10. """Global Settings"""
  11. model_config = SettingsConfigDict(env_file=f'{BasePath}/.env', env_file_encoding='utf-8', extra='ignore')
  12. # Env Config
  13. ENVIRONMENT: Literal['dev', 'pro']
  14. BATCH_CONCURRENT: int
  15. # Env MySQL
  16. MYSQL_HOST: str
  17. MYSQL_PORT: int
  18. MYSQL_USER: str
  19. MYSQL_PASSWORD: str
  20. # Env Redis
  21. REDIS_HOST: str
  22. REDIS_PORT: int
  23. REDIS_PASSWORD: str
  24. REDIS_DATABASE: int
  25. # Env Token
  26. TOKEN_SECRET_KEY: str # 密钥 secrets.token_urlsafe(32)
  27. # Env Opera Log
  28. OPERA_LOG_ENCRYPT_SECRET_KEY: str # 密钥 os.urandom(32), 需使用 bytes.hex() 方法转换为 str
  29. # FastAPI
  30. API_V1_STR: str = '/api/v1'
  31. TITLE: str = '3ex AI 接口'
  32. VERSION: str = '0.0.1'
  33. DESCRIPTION: str = '3ex AI API'
  34. DOCS_URL: str | None = f'{API_V1_STR}/docs'
  35. REDOCS_URL: str | None = f'{API_V1_STR}/redocs'
  36. OPENAPI_URL: str | None = f'{API_V1_STR}/openapi'
  37. @model_validator(mode='before')
  38. @classmethod
  39. def validate_openapi_url(cls, values):
  40. if values['ENVIRONMENT'] == 'pro':
  41. values['OPENAPI_URL'] = None
  42. return values
  43. # Demo mode
  44. # Only GET, OPTIONS requests are allowed
  45. DEMO_MODE: bool = False
  46. DEMO_MODE_EXCLUDE: set[tuple[str, str]] = {
  47. ('POST', f'{API_V1_STR}/auth/login'),
  48. ('POST', f'{API_V1_STR}/auth/logout'),
  49. ('GET', f'{API_V1_STR}/auth/captcha'),
  50. }
  51. # Static Server
  52. STATIC_FILES: bool = False
  53. # Location Parse
  54. LOCATION_PARSE: Literal['online', 'offline', 'false'] = 'offline'
  55. # Limiter
  56. LIMITER_REDIS_PREFIX: str = 'fba:limiter'
  57. # DateTime
  58. DATETIME_TIMEZONE: str = 'Asia/Shanghai'
  59. DATETIME_FORMAT: str = '%Y-%m-%d %H:%M:%S'
  60. # MySQL
  61. MYSQL_ECHO: bool = False
  62. MYSQL_DATABASE: str = 'fba'
  63. MYSQL_CHARSET: str = 'utf8mb4'
  64. # Redis
  65. REDIS_TIMEOUT: int = 5
  66. # Token
  67. TOKEN_ALGORITHM: str = 'HS256' # 算法
  68. TOKEN_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
  69. TOKEN_REFRESH_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7 # 刷新过期时间,单位:秒
  70. TOKEN_REDIS_PREFIX: str = 'fba:token'
  71. TOKEN_CALL_REDIS_PREFIX: str = 'fba:call_token'
  72. TOKEN_REFRESH_REDIS_PREFIX: str = 'fba:token:refresh'
  73. TOKEN_EXCLUDE: list[str] = [ # JWT / RBAC 白名单
  74. f'{API_V1_STR}/auth/login',
  75. ]
  76. JWT_USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
  77. # Sys User
  78. USER_REDIS_PREFIX: str = 'fba:user'
  79. USER_REDIS_EXPIRE_SECONDS: int = 60 * 60 * 24 * 7
  80. # Log
  81. LOG_LEVEL: str = 'INFO'
  82. LOG_FORMAT: str = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</> | <lvl>{level: <8}</> | <lvl>{message}</>'
  83. LOG_STDOUT_FILENAME: str = 'fba_access.log'
  84. LOG_STDERR_FILENAME: str = 'fba_error.log'
  85. # Middleware
  86. MIDDLEWARE_CORS: bool = True
  87. MIDDLEWARE_ACCESS: bool = True
  88. # RBAC Permission
  89. PERMISSION_MODE: Literal['casbin', 'role-menu'] = 'casbin'
  90. PERMISSION_REDIS_PREFIX: str = 'fba:permission'
  91. # Casbin Auth
  92. CASBIN_EXCLUDE: set[tuple[str, str]] = {
  93. ('POST', f'{API_V1_STR}/auth/logout'),
  94. ('POST', f'{API_V1_STR}/auth/token/new'),
  95. }
  96. # Role Menu Auth
  97. ROLE_MENU_EXCLUDE: list[str] = [
  98. 'sys:monitor:redis',
  99. 'sys:monitor:server',
  100. ]
  101. # Opera log
  102. OPERA_LOG_EXCLUDE: list[str] = [
  103. '/favicon.ico',
  104. DOCS_URL,
  105. REDOCS_URL,
  106. OPENAPI_URL,
  107. f'{API_V1_STR}/auth/login/swagger',
  108. f'{API_V1_STR}/auth/github/callback',
  109. ]
  110. OPERA_LOG_ENCRYPT: int = 1 # 0: AES (性能损耗); 1: md5; 2: ItsDangerous; 3: 不加密, others: 替换为 ******
  111. OPERA_LOG_ENCRYPT_INCLUDE: list[str] = [
  112. 'password',
  113. 'old_password',
  114. 'new_password',
  115. 'confirm_password',
  116. ]
  117. # Ip location
  118. IP_LOCATION_REDIS_PREFIX: str = 'fba:ip:location'
  119. IP_LOCATION_EXPIRE_SECONDS: int = 60 * 60 * 24 * 1 # 过期时间,单位:秒
  120. @lru_cache
  121. def get_settings() -> Settings:
  122. """获取全局配置"""
  123. load_dotenv()
  124. return Settings()
  125. # 创建配置实例
  126. settings = get_settings()