"""项目配置:静态配置从环境变量读取,命令监听配置支持数据库动态修改。""" import os import uuid from pathlib import Path from dotenv import load_dotenv # 加载 .env 文件(优先从插件目录查找) load_dotenv(Path(__file__).parent / ".env") # ── 鉴权 ──────────────────────────────────────────────────── WEBHOOK_API_KEY: str = os.environ.get("WEBHOOK_API_KEY", "") or uuid.uuid4().hex # ── 网络 ───────────────────────────────────────────────────── HOST: str = os.environ.get("WEBHOOK_HOST", "0.0.0.0") try: PORT: int = int(os.environ.get("WEBHOOK_PORT", "8081")) except ValueError: PORT = 8081 # ── 上传 ───────────────────────────────────────────────────── UPLOAD_DIR: Path = Path(os.environ.get("UPLOAD_DIR", str(Path(__file__).parent / "uploads"))) # 单个文件最大 20 MB MAX_UPLOAD_SIZE: int = int(os.environ.get("MAX_UPLOAD_SIZE", str(20 * 1024 * 1024))) # 允许的文件扩展名(小写,不含点),为空则不限制 ALLOWED_EXTENSIONS: set[str] = set( filter(None, os.environ.get("ALLOWED_EXTENSIONS", "").lower().split(",")) ) # ── QQ API ─────────────────────────────────────────────────── QQ_API_TIMEOUT: float = float(os.environ.get("QQ_API_TIMEOUT", "10")) QQ_API_MAX_RETRIES: int = int(os.environ.get("QQ_API_MAX_RETRIES", "2")) # ── 命令监听(可动态修改,从数据库加载) ────────────────────── COMMAND_PREFIX: str = os.environ.get("COMMAND_PREFIX", "#") COMMAND_LENGTH_MIN: int = int(os.environ.get("COMMAND_LENGTH_MIN", "2")) COMMAND_LENGTH_MAX: int = int(os.environ.get("COMMAND_LENGTH_MAX", "4")) COMMAND_CALLBACK_URL: str = os.environ.get("COMMAND_CALLBACK_URL", "") COMMAND_CALLBACK_TIMEOUT: int = int(os.environ.get("COMMAND_CALLBACK_TIMEOUT", "180")) COMMAND_SCOPE: str = os.environ.get("COMMAND_SCOPE", "all") # all / group / private COMMAND_LIST_MODE: str = os.environ.get("COMMAND_LIST_MODE", "allow") # allow / deny COMMAND_ALLOWED_GROUPS: frozenset[str] = frozenset( filter(None, os.environ.get("COMMAND_ALLOWED_GROUPS", "").split(",")) ) COMMAND_DENIED_GROUPS: frozenset[str] = frozenset( filter(None, os.environ.get("COMMAND_DENIED_GROUPS", "").split(",")) ) COMMAND_ALLOWED_USERS: frozenset[str] = frozenset( filter(None, os.environ.get("COMMAND_ALLOWED_USERS", "").split(",")) ) COMMAND_DENIED_USERS: frozenset[str] = frozenset( filter(None, os.environ.get("COMMAND_DENIED_USERS", "").split(",")) ) COMMAND_AT_SENDER: bool = os.environ.get("COMMAND_AT_SENDER", "true").lower() in ("true", "1", "yes") # ── 动态配置刷新 ───────────────────────────────────────────── def _parse_frozenset(value: str) -> frozenset[str]: """将逗号分隔字符串解析为 frozenset。""" return frozenset(filter(None, (v.strip() for v in value.split(",")))) def reload_settings(settings: dict[str, str]) -> None: """从数据库读取的配置覆盖模块级变量,使配置动态生效。""" global COMMAND_PREFIX, COMMAND_LENGTH_MIN, COMMAND_LENGTH_MAX global COMMAND_CALLBACK_URL, COMMAND_CALLBACK_TIMEOUT, COMMAND_SCOPE global COMMAND_LIST_MODE, COMMAND_ALLOWED_GROUPS, COMMAND_DENIED_GROUPS global COMMAND_ALLOWED_USERS, COMMAND_DENIED_USERS, COMMAND_AT_SENDER if "command_prefix" in settings: COMMAND_PREFIX = settings["command_prefix"] if "command_length_min" in settings: try: COMMAND_LENGTH_MIN = int(settings["command_length_min"]) except ValueError: pass if "command_length_max" in settings: try: COMMAND_LENGTH_MAX = int(settings["command_length_max"]) except ValueError: pass if "command_callback_url" in settings: COMMAND_CALLBACK_URL = settings["command_callback_url"] if "command_callback_timeout" in settings: try: COMMAND_CALLBACK_TIMEOUT = int(settings["command_callback_timeout"]) except ValueError: pass if "command_scope" in settings: COMMAND_SCOPE = settings["command_scope"] if "command_list_mode" in settings: COMMAND_LIST_MODE = settings["command_list_mode"] if "command_allowed_groups" in settings: COMMAND_ALLOWED_GROUPS = _parse_frozenset(settings["command_allowed_groups"]) if "command_denied_groups" in settings: COMMAND_DENIED_GROUPS = _parse_frozenset(settings["command_denied_groups"]) if "command_allowed_users" in settings: COMMAND_ALLOWED_USERS = _parse_frozenset(settings["command_allowed_users"]) if "command_denied_users" in settings: COMMAND_DENIED_USERS = _parse_frozenset(settings["command_denied_users"]) if "command_at_sender" in settings: COMMAND_AT_SENDER = settings["command_at_sender"].lower() in ("true", "1", "yes") # 刷新正则编译缓存 from .handlers.command import rebuild_pattern rebuild_pattern()