🔀手动Merge轻雪主仓库a77f97f

This commit is contained in:
2024-10-06 02:39:10 +08:00
parent 4cc2ae61db
commit f8b57bfe9a
108 changed files with 3131 additions and 3574 deletions

View File

@ -1,49 +1,132 @@
"""
该模块用于常用配置文件的加载
多配置文件编写原则:
1. 尽量不要冲突: 一个键不要多次出现
2. 分工明确: 每个配置文件给一个或一类服务提供配置
3. 扁平化编写: 配置文件尽量扁平化,不要出现过多的嵌套
4. 注意冲突时的优先级: 项目目录下的配置文件优先级高于config目录下的配置文件
5. 请不要将需要动态加载的内容写入配置文件,你应该使用其他储存方式
"""
import os
from typing import List
import nonebot
import json
import copy
import toml
import yaml
from pydantic import BaseModel
from typing import Any
from liteyuki.log import logger
_SUPPORTED_CONFIG_FORMATS = (".yaml", ".yml", ".json", ".toml")
config = {} # 主进程全局配置,确保加载后读取
def flat_config(config: dict[str, Any]) -> dict[str, Any]:
"""
扁平化配置文件
{a:{b:{c:1}}} -> {"a.b.c": 1}
Args:
config: 配置项目
Returns:
扁平化后的配置文件,但也包含原有的键值对
"""
new_config = copy.deepcopy(config)
for key, value in config.items():
if isinstance(value, dict):
for k, v in flat_config(value).items():
new_config[f"{key}.{k}"] = v
return new_config
class SatoriNodeConfig(BaseModel):
host: str = ""
port: str = "5500"
path: str = ""
token: str = ""
def load_from_yaml(file_: str) -> dict[str, Any]:
"""
Load config from yaml file
"""
logger.debug("正在从 {} 中加载 YAML 配置".format(file_))
config = yaml.safe_load(open(file_, "r", encoding="utf-8"))
return flat_config(config if config is not None else {})
class SatoriConfig(BaseModel):
comment: str = "此皆正处于开发之中,切勿在生产环境中启用。"
enable: bool = False
hosts: List[SatoriNodeConfig] = [SatoriNodeConfig()]
def load_from_json(file_: str) -> dict[str, Any]:
"""
Load config from json file
"""
logger.debug("正在从 {} 中加载 JSON 配置".format(file_))
config = json.load(open(file_, "r", encoding="utf-8"))
return flat_config(config if config is not None else {})
class BasicConfig(BaseModel):
host: str = "127.0.0.1"
port: int = 20247
superusers: list[str] = []
command_start: list[str] = ["/", ""]
nickname: list[str] = [f"灵温"]
satori: SatoriConfig = SatoriConfig()
data_path: str = "data/liteyuki"
def load_from_toml(file_: str) -> dict[str, Any]:
"""
Load config from toml file
"""
logger.debug("正在从 {} 中加载 TOML 配置".format(file_))
config = toml.load(open(file_, "r", encoding="utf-8"))
return flat_config(config if config is not None else {})
def load_from_yaml(file: str) -> dict:
global config
nonebot.logger.debug("Loading config from %s" % file)
if not os.path.exists(file):
nonebot.logger.warning(f"未找到配置文件 {file} ,已创建默认配置,请修改后重启。")
with open(file, "w", encoding="utf-8") as f:
yaml.dump(BasicConfig().dict(), f, default_flow_style=False)
def load_from_files(*files: str, no_warning: bool = False) -> dict[str, Any]:
"""
从指定文件加载配置项,会自动识别文件格式
默认执行扁平化选项
"""
config = {}
for file in files:
if os.path.exists(file):
if file.endswith((".yaml", "yml")):
config.update(load_from_yaml(file))
elif file.endswith(".json"):
config.update(load_from_json(file))
elif file.endswith(".toml"):
config.update(load_from_toml(file))
else:
if not no_warning:
logger.warning(f"不支持配置文件 {file} 的类型")
else:
if not no_warning:
logger.warning(f"配置文件 {file} 未寻得")
return config
with open(file, "r", encoding="utf-8") as f:
conf = yaml.load(f, Loader=yaml.FullLoader)
config = conf
if conf is None:
nonebot.logger.warning(f"配置文件 {file} 为空,已创建默认配置,请修改后重启。")
conf = BasicConfig().dict()
return conf
def load_configs_from_dirs(
*directories: str, no_waring: bool = False
) -> dict[str, Any]:
"""
从目录下加载配置文件,不递归
按照读取文件的优先级反向覆盖
默认执行扁平化选项
"""
config = {}
for directory in directories:
if not os.path.exists(directory):
if not no_waring:
logger.warning(f"目录 {directory} 未寻得")
continue
for file in os.listdir(directory):
if file.endswith(_SUPPORTED_CONFIG_FORMATS):
config.update(
load_from_files(os.path.join(directory, file), no_warning=no_waring)
)
return config
def load_config_in_default(no_waring: bool = False) -> dict[str, Any]:
"""
从一个标准的轻雪项目加载配置文件
项目目录下的config.*和config目录下的所有配置文件
项目目录下的配置文件优先
"""
config = load_configs_from_dirs("config", no_waring=no_waring)
config.update(
load_from_files(
"config.yaml",
"config.toml",
"config.json",
"config.yml",
no_warning=no_waring,
)
)
return config