from __future__ import annotations from dataclasses import dataclass from pathlib import Path import os @dataclass(frozen=True) class AppConfig: env_path: Path | None feishu_app_id: str feishu_app_secret: str feishu_base_url: str feishu_app_token: str | None analytics_db_host: str analytics_db_port: str analytics_db_user: str analytics_db_password: str analytics_db_name: str def load_env_file(env_path: Path) -> dict[str, str]: values: dict[str, str] = {} if not env_path.exists(): return values for raw_line in env_path.read_text(encoding="utf-8").splitlines(): line = raw_line.strip() if not line or line.startswith("#") or "=" not in line: continue key, value = line.split("=", 1) values[key.strip()] = value.strip().strip("'").strip('"') return values def load_env_candidates() -> tuple[dict[str, str], Path | None]: script_path = Path(__file__).resolve() candidates = [ script_path.parent.parent / ".env", script_path.parent.parent / "project (1)" / ".env", script_path.parent.parent.parent / ".env", Path.cwd() / ".env", ] seen: set[Path] = set() for candidate in candidates: candidate = candidate.resolve() if candidate in seen: continue seen.add(candidate) values = load_env_file(candidate) if values: return values, candidate return {}, None def get_config(config: dict[str, str], *keys: str) -> str | None: for key in keys: value = config.get(key) or os.getenv(key) if value: return value return None def require_config(config: dict[str, str], *keys: str) -> str: value = get_config(config, *keys) if value: return value raise KeyError(f"缺少必填配置: {' / '.join(keys)}") def build_app_config() -> AppConfig: config, env_path = load_env_candidates() return AppConfig( env_path=env_path, feishu_app_id=require_config(config, "FEISHU_APP_ID", "APP_ID"), feishu_app_secret=require_config(config, "FEISHU_APP_SECRET", "FEISHU_APP_SECRE", "APP_SECRET"), feishu_base_url=require_config(config, "FEISHU_BASE_URL", "BASE_URL").rstrip("/"), feishu_app_token=get_config(config, "FEISHU_APP_TOKEN"), analytics_db_host=require_config(config, "ANALYTICS_DB_HOST"), analytics_db_port=require_config(config, "ANALYTICS_DB_PORT"), analytics_db_user=require_config(config, "ANALYTICS_DB_USER"), analytics_db_password=require_config(config, "ANALYTICS_DB_PASSWORD"), analytics_db_name=require_config(config, "ANALYTICS_DB_NAME"), )