import json import logging from pathlib import Path from typing import Any, TypeVar import aiofiles from .config import Config logger = logging.getLogger(__name__) CONFIG_PATH = Path.cwd() / ".nyahome" / "config.json" T = TypeVar("T", str, int, bool, list) class ConfigManager: """ ConfigManager 携带一个初始化的 Config 实例。在 Config 初始化时,所有的默认设置键的值就都已经加载。 因此,如果不 load_config,ConfigManager 也将持有一套默认设置。 """ def __init__(self) -> None: CONFIG_PATH.parent.mkdir(exist_ok=True) self._config = Config() def _parse(self, config: dict) -> None: """ 解析给定的字典作为配置。 Args: config: 配置字典 """ for key, value in config.items(): setattr(self._config, key, value) def _dumps(self) -> str: """ 将配置项序列化为 json 字符串,包含格式化缩进。 Returns: json 字符串。 """ config = {} for attr in dir(self._config): if not attr.startswith("_"): value = getattr(self._config, attr) config[attr] = value return json.dumps(config, ensure_ascii=False, indent=2) async def async_load_config(self) -> None: async with aiofiles.open(CONFIG_PATH, "r", encoding="utf-8") as f: self._parse(json.loads(await f.read())) logger.info("异步从 config.json 读取设置完成。") def sync_load_config(self) -> None: with open(CONFIG_PATH, "r", encoding="utf-8") as f: self._parse(json.load(f)) logger.info("同步从 config.json 读取设置完成。") async def async_save_config(self) -> None: async with aiofiles.open(CONFIG_PATH, "w", encoding="utf-8") as f: await f.write(self._dumps()) logger.info("异步保存设置到 config.json 完成。") def sync_save_config(self) -> None: with open(CONFIG_PATH, "w", encoding="utf-8") as f: f.write(self._dumps()) logger.info("同步保存设置到 config.json 完成。") def get(self, key: str, default: T | None = None) -> T: """ 获取配置项 Args: key: 配置键 default: 默认值,如果不提供则会在获取配置项失败时报错 Returns: 返回配置值,返回类型根据提供的默认值进行推断。 """ return getattr(self._config, key, default) # type: ignore[return-value] def set(self, key: str, value: T) -> None: """ 设置配置项。 Args: key: 配置键名 value: 配置键的新值,可以是(且仅支持)字符串、整型以及列表。 Raises: AttributeError: 配置键名错误 TypeError: 配置键值类型错误 """ try: old_value = self.get(key) except AttributeError as e: raise e match old_value: case str(): new_value = str(value) case int(): new_value = int(value) case bool(): new_value = bool(value) case list(): new_value = list(value) case _: raise TypeError(f"不支持 {type(old_value).__name__} 类型的设置项。({key})") setattr(self._config, key, new_value) def reset(self, key: str) -> None: """ 将配置项恢复至默认值。 Args: key: 配置键名 Raises: AttributeError: 配置键名错误 """ ci = Config() try: default_value = getattr(ci, key) except AttributeError as e: raise e setattr(self._config, key, default_value) def get_config(self) -> dict[str, Any]: config = {} for attr in dir(self._config): if not attr.startswith("_"): value = getattr(self._config, attr) config[attr] = value return config def set_config(self, config: dict[str, Any]) -> dict[str, Any]: for attr in dir(self._config): if not attr.startswith("_"): setattr(self._config, attr, config[attr]) return self.get_config() config_manager = ConfigManager()