fix Config reload

This commit is contained in:
jxxghp
2025-06-04 07:17:47 +08:00
parent 2af8b6f445
commit 0911854e9d
4 changed files with 56 additions and 67 deletions

View File

@@ -32,11 +32,13 @@ from app.helper.subscribe import SubscribeHelper
from app.helper.system import SystemHelper
from app.log import logger
from app.scheduler import Scheduler
from app.schemas.types import SystemConfigKey
from app.schemas import ConfigChangeEventData
from app.schemas.types import SystemConfigKey, EventType
from app.utils.crypto import HashUtils
from app.utils.http import RequestUtils
from app.utils.security import SecurityUtils
from app.utils.url import UrlUtils
from core.event import eventmanager
from version import APP_VERSION
router = APIRouter()
@@ -218,7 +220,7 @@ def set_env_setting(env: dict,
result = settings.update_settings(env=env)
# 统计成功和失败的结果
success_updates = {k: v for k, v in result.items() if v[0]}
failed_updates = {k: v for k, v in result.items() if not v[0]}
failed_updates = {k: v for k, v in result.items() if v[0] is False}
if failed_updates:
return schemas.Response(
@@ -230,6 +232,15 @@ def set_env_setting(env: dict,
}
)
if success_updates:
for key in success_updates.keys():
# 发送配置变更事件
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
value=getattr(settings, key, None),
change_type="update"
))
return schemas.Response(
success=True,
message="所有配置项更新成功",
@@ -283,12 +294,26 @@ def set_setting(key: str, value: Union[list, dict, bool, int, str] = None,
"""
if hasattr(settings, key):
success, message = settings.update_setting(key=key, value=value)
if success:
# 发送配置变更事件
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
value=value,
change_type="update"
))
return schemas.Response(success=success, message=message)
elif key in {item.value for item in SystemConfigKey}:
if isinstance(value, list):
value = list(filter(None, value))
value = value if value else None
SystemConfigOper().set(key, value)
success = SystemConfigOper().set(key, value)
if success:
# 发送配置变更事件
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
value=value,
change_type="update"
))
return schemas.Response(success=True)
else:
return schemas.Response(success=False, message=f"配置项 '{key}' 不存在")

View File

@@ -13,8 +13,6 @@ from pydantic import BaseModel, BaseSettings, validator, Field
from app.log import logger, log_settings, LogConfigModel
from app.utils.system import SystemUtils
from app.utils.url import UrlUtils
from app.schemas.types import EventType
from app.schemas import ConfigChangeEventData
class ConfigModel(BaseModel):
@@ -391,8 +389,6 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
f"配置项 '{field_name}' 的值 '{value}' 无法转换成正确的类型,使用默认值 '{default}',错误信息: {e}")
return default, True
# TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually.
# Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information.
@validator('*', pre=True, always=True)
def generic_type_validator(cls, value: Any, field): # noqa
"""
@@ -435,9 +431,12 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
logger.info(f"配置项 '{field.name}' 已自动修正并写入到 'app.env' 文件")
return True, message
def update_setting(self, key: str, value: Any) -> Tuple[bool, str]:
def update_setting(self, key: str, value: Any) -> Tuple[Optional[bool], str]:
"""
更新单个配置项
:param key: 配置项的名称
:param value: 配置项的新值
:return: (是否成功 True 成功/False 失败/None 无需更新, 错误信息)
"""
if not hasattr(self, key):
return False, f"配置项 '{key}' 不存在"
@@ -448,32 +447,25 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
if field.name == "API_TOKEN":
converted_value, needs_update = self.validate_api_token(value, original_value)
else:
converted_value, needs_update = self.generic_type_converter(value, original_value, field.type_,
field.default, key)
converted_value, needs_update = self.generic_type_converter(value,
original_value,
field.type_,
field.default,
key)
# 如果没有抛出异常,则统一使用 converted_value 进行更新
if needs_update or str(value) != str(converted_value):
success, message = self.update_env_config(field, value, converted_value)
# 仅成功更新配置时,才更新内存
if success:
old_value = getattr(self, key)
setattr(self, key, converted_value)
if hasattr(log_settings, key):
setattr(log_settings, key, converted_value)
# 发送配置变更通知
from app.core.event import eventmanager
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
old_value=old_value,
new_value=converted_value,
change_type="update"
))
return success, message
return True, ""
return None, ""
except Exception as e:
return False, str(e)
def update_settings(self, env: Dict[str, Any]) -> Dict[str, Tuple[bool, str]]:
def update_settings(self, env: Dict[str, Any]) -> Dict[str, Tuple[Optional[bool], str]]:
"""
更新多个配置项
"""

View File

@@ -1,10 +1,9 @@
from typing import Any, Union
from typing import Any, Union, Optional
from app.db import DbOper
from app.db.models.systemconfig import SystemConfig
from app.schemas.types import SystemConfigKey, EventType
from app.schemas.types import SystemConfigKey
from app.utils.singleton import Singleton
from app.schemas import ConfigChangeEventData
class SystemConfigOper(DbOper, metaclass=Singleton):
@@ -19,9 +18,12 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
for item in SystemConfig.list(self._db):
self.__SYSTEMCONF[item.key] = item.value
def set(self, key: Union[str, SystemConfigKey], value: Any):
def set(self, key: Union[str, SystemConfigKey], value: Any) -> Optional[bool]:
"""
设置系统设置
:param key: 配置键
:param value: 配置值
:return: 是否设置成功True 成功/False 失败/None 无需更新)
"""
if isinstance(key, SystemConfigKey):
key = key.value
@@ -31,38 +33,17 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
self.__SYSTEMCONF[key] = value
conf = SystemConfig.get_by_key(self._db, key)
if conf:
if value:
conf.update(self._db, {"value": value})
# 发送配置变更通知
if old_value != value:
from app.core.event import eventmanager
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
old_value=old_value,
new_value=value,
change_type="update"
))
else:
conf.delete(self._db, conf.id)
# 发送配置删除通知
from app.core.event import eventmanager
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
old_value=old_value,
new_value=value,
change_type="delete"
))
if old_value != value:
if value:
conf.update(self._db, {"value": value})
else:
conf.delete(self._db, conf.id)
return True
return None
else:
conf = SystemConfig(key=key, value=value)
conf.create(self._db)
# 发送配置变更通知
from app.core.event import eventmanager
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
old_value=old_value,
new_value=value,
change_type="add"
))
return True
def get(self, key: Union[str, SystemConfigKey] = None) -> Any:
"""
@@ -80,26 +61,18 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
"""
return self.__SYSTEMCONF or {}
def delete(self, key: Union[str, SystemConfigKey]):
def delete(self, key: Union[str, SystemConfigKey]) -> bool:
"""
删除系统设置
"""
if isinstance(key, SystemConfigKey):
key = key.value
# 更新内存
old_value = self.__SYSTEMCONF.pop(key, None)
self.__SYSTEMCONF.pop(key, None)
# 写入数据库
conf = SystemConfig.get_by_key(self._db, key)
if conf:
conf.delete(self._db, conf.id)
# 发送配置变更通知
from app.core.event import eventmanager
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
key=key,
old_value=old_value,
new_value=None,
change_type="delete"
))
return True
def __del__(self):

View File

@@ -27,8 +27,7 @@ class ConfigChangeEventData(BaseEventData):
ConfigChange 事件的数据模型
"""
key: str = Field(..., description="配置项的键")
old_value: Optional[Any] = Field(default=None, description="配置项的")
new_value: Optional[Any] = Field(default=None, description="配置项的新值")
value: Optional[Any] = Field(default=None, description="配置项的")
change_type: str = Field(default="update", description="配置项的变更类型,如 'add', 'update', 'delete'")