mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 08:26:53 +08:00
fix Config reload
This commit is contained in:
@@ -32,11 +32,13 @@ from app.helper.subscribe import SubscribeHelper
|
|||||||
from app.helper.system import SystemHelper
|
from app.helper.system import SystemHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.scheduler import Scheduler
|
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.crypto import HashUtils
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
from app.utils.security import SecurityUtils
|
from app.utils.security import SecurityUtils
|
||||||
from app.utils.url import UrlUtils
|
from app.utils.url import UrlUtils
|
||||||
|
from core.event import eventmanager
|
||||||
from version import APP_VERSION
|
from version import APP_VERSION
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
@@ -218,7 +220,7 @@ def set_env_setting(env: dict,
|
|||||||
result = settings.update_settings(env=env)
|
result = settings.update_settings(env=env)
|
||||||
# 统计成功和失败的结果
|
# 统计成功和失败的结果
|
||||||
success_updates = {k: v for k, v in result.items() if v[0]}
|
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:
|
if failed_updates:
|
||||||
return schemas.Response(
|
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(
|
return schemas.Response(
|
||||||
success=True,
|
success=True,
|
||||||
message="所有配置项更新成功",
|
message="所有配置项更新成功",
|
||||||
@@ -283,12 +294,26 @@ def set_setting(key: str, value: Union[list, dict, bool, int, str] = None,
|
|||||||
"""
|
"""
|
||||||
if hasattr(settings, key):
|
if hasattr(settings, key):
|
||||||
success, message = settings.update_setting(key=key, value=value)
|
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)
|
return schemas.Response(success=success, message=message)
|
||||||
elif key in {item.value for item in SystemConfigKey}:
|
elif key in {item.value for item in SystemConfigKey}:
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
value = list(filter(None, value))
|
value = list(filter(None, value))
|
||||||
value = value if value else None
|
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)
|
return schemas.Response(success=True)
|
||||||
else:
|
else:
|
||||||
return schemas.Response(success=False, message=f"配置项 '{key}' 不存在")
|
return schemas.Response(success=False, message=f"配置项 '{key}' 不存在")
|
||||||
|
|||||||
+11
-19
@@ -13,8 +13,6 @@ from pydantic import BaseModel, BaseSettings, validator, Field
|
|||||||
from app.log import logger, log_settings, LogConfigModel
|
from app.log import logger, log_settings, LogConfigModel
|
||||||
from app.utils.system import SystemUtils
|
from app.utils.system import SystemUtils
|
||||||
from app.utils.url import UrlUtils
|
from app.utils.url import UrlUtils
|
||||||
from app.schemas.types import EventType
|
|
||||||
from app.schemas import ConfigChangeEventData
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigModel(BaseModel):
|
class ConfigModel(BaseModel):
|
||||||
@@ -391,8 +389,6 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
|||||||
f"配置项 '{field_name}' 的值 '{value}' 无法转换成正确的类型,使用默认值 '{default}',错误信息: {e}")
|
f"配置项 '{field_name}' 的值 '{value}' 无法转换成正确的类型,使用默认值 '{default}',错误信息: {e}")
|
||||||
return default, True
|
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)
|
@validator('*', pre=True, always=True)
|
||||||
def generic_type_validator(cls, value: Any, field): # noqa
|
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' 文件")
|
logger.info(f"配置项 '{field.name}' 已自动修正并写入到 'app.env' 文件")
|
||||||
return True, message
|
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):
|
if not hasattr(self, key):
|
||||||
return False, f"配置项 '{key}' 不存在"
|
return False, f"配置项 '{key}' 不存在"
|
||||||
@@ -448,32 +447,25 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
|||||||
if field.name == "API_TOKEN":
|
if field.name == "API_TOKEN":
|
||||||
converted_value, needs_update = self.validate_api_token(value, original_value)
|
converted_value, needs_update = self.validate_api_token(value, original_value)
|
||||||
else:
|
else:
|
||||||
converted_value, needs_update = self.generic_type_converter(value, original_value, field.type_,
|
converted_value, needs_update = self.generic_type_converter(value,
|
||||||
field.default, key)
|
original_value,
|
||||||
|
field.type_,
|
||||||
|
field.default,
|
||||||
|
key)
|
||||||
# 如果没有抛出异常,则统一使用 converted_value 进行更新
|
# 如果没有抛出异常,则统一使用 converted_value 进行更新
|
||||||
if needs_update or str(value) != str(converted_value):
|
if needs_update or str(value) != str(converted_value):
|
||||||
success, message = self.update_env_config(field, value, converted_value)
|
success, message = self.update_env_config(field, value, converted_value)
|
||||||
# 仅成功更新配置时,才更新内存
|
# 仅成功更新配置时,才更新内存
|
||||||
if success:
|
if success:
|
||||||
old_value = getattr(self, key)
|
|
||||||
setattr(self, key, converted_value)
|
setattr(self, key, converted_value)
|
||||||
if hasattr(log_settings, key):
|
if hasattr(log_settings, key):
|
||||||
setattr(log_settings, key, converted_value)
|
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 success, message
|
||||||
return True, ""
|
return None, ""
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False, str(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]]:
|
||||||
"""
|
"""
|
||||||
更新多个配置项
|
更新多个配置项
|
||||||
"""
|
"""
|
||||||
|
|||||||
+16
-43
@@ -1,10 +1,9 @@
|
|||||||
from typing import Any, Union
|
from typing import Any, Union, Optional
|
||||||
|
|
||||||
from app.db import DbOper
|
from app.db import DbOper
|
||||||
from app.db.models.systemconfig import SystemConfig
|
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.utils.singleton import Singleton
|
||||||
from app.schemas import ConfigChangeEventData
|
|
||||||
|
|
||||||
|
|
||||||
class SystemConfigOper(DbOper, metaclass=Singleton):
|
class SystemConfigOper(DbOper, metaclass=Singleton):
|
||||||
@@ -19,9 +18,12 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
|
|||||||
for item in SystemConfig.list(self._db):
|
for item in SystemConfig.list(self._db):
|
||||||
self.__SYSTEMCONF[item.key] = item.value
|
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):
|
if isinstance(key, SystemConfigKey):
|
||||||
key = key.value
|
key = key.value
|
||||||
@@ -31,38 +33,17 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
|
|||||||
self.__SYSTEMCONF[key] = value
|
self.__SYSTEMCONF[key] = value
|
||||||
conf = SystemConfig.get_by_key(self._db, key)
|
conf = SystemConfig.get_by_key(self._db, key)
|
||||||
if conf:
|
if conf:
|
||||||
if value:
|
if old_value != value:
|
||||||
conf.update(self._db, {"value": value})
|
if value:
|
||||||
# 发送配置变更通知
|
conf.update(self._db, {"value": value})
|
||||||
if old_value != value:
|
else:
|
||||||
from app.core.event import eventmanager
|
conf.delete(self._db, conf.id)
|
||||||
eventmanager.send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
|
return True
|
||||||
key=key,
|
return None
|
||||||
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"
|
|
||||||
))
|
|
||||||
else:
|
else:
|
||||||
conf = SystemConfig(key=key, value=value)
|
conf = SystemConfig(key=key, value=value)
|
||||||
conf.create(self._db)
|
conf.create(self._db)
|
||||||
# 发送配置变更通知
|
return True
|
||||||
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"
|
|
||||||
))
|
|
||||||
|
|
||||||
def get(self, key: Union[str, SystemConfigKey] = None) -> Any:
|
def get(self, key: Union[str, SystemConfigKey] = None) -> Any:
|
||||||
"""
|
"""
|
||||||
@@ -80,26 +61,18 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
return self.__SYSTEMCONF or {}
|
return self.__SYSTEMCONF or {}
|
||||||
|
|
||||||
def delete(self, key: Union[str, SystemConfigKey]):
|
def delete(self, key: Union[str, SystemConfigKey]) -> bool:
|
||||||
"""
|
"""
|
||||||
删除系统设置
|
删除系统设置
|
||||||
"""
|
"""
|
||||||
if isinstance(key, SystemConfigKey):
|
if isinstance(key, SystemConfigKey):
|
||||||
key = key.value
|
key = key.value
|
||||||
# 更新内存
|
# 更新内存
|
||||||
old_value = self.__SYSTEMCONF.pop(key, None)
|
self.__SYSTEMCONF.pop(key, None)
|
||||||
# 写入数据库
|
# 写入数据库
|
||||||
conf = SystemConfig.get_by_key(self._db, key)
|
conf = SystemConfig.get_by_key(self._db, key)
|
||||||
if conf:
|
if conf:
|
||||||
conf.delete(self._db, conf.id)
|
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
|
return True
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ class ConfigChangeEventData(BaseEventData):
|
|||||||
ConfigChange 事件的数据模型
|
ConfigChange 事件的数据模型
|
||||||
"""
|
"""
|
||||||
key: str = Field(..., description="配置项的键")
|
key: str = Field(..., description="配置项的键")
|
||||||
old_value: Optional[Any] = Field(default=None, description="配置项的旧值")
|
value: Optional[Any] = Field(default=None, description="配置项的新值")
|
||||||
new_value: Optional[Any] = Field(default=None, description="配置项的新值")
|
|
||||||
change_type: str = Field(default="update", description="配置项的变更类型,如 'add', 'update', 'delete'")
|
change_type: str = Field(default="update", description="配置项的变更类型,如 'add', 'update', 'delete'")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user