Skip to content

Commit ca5ec8a

Browse files
committed
feat(config): 优化配置变更事件处理机制
1 parent d1d7b8c commit ca5ec8a

File tree

23 files changed

+205
-335
lines changed

23 files changed

+205
-335
lines changed

‎app/api/endpoints/system.py‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,11 @@ async def set_env_setting(env: dict,
248248
)
249249

250250
if success_updates:
251-
for key in success_updates.keys():
252-
# 发送配置变更事件
253-
await eventmanager.async_send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
254-
key=key,
255-
value=getattr(settings, key, None),
256-
change_type="update"
257-
))
251+
# 发送配置变更事件
252+
await eventmanager.async_send_event(etype=EventType.ConfigChanged, data=ConfigChangeEventData(
253+
key=success_updates.keys(),
254+
change_type="update"
255+
))
258256

259257
return schemas.Response(
260258
success=True,

‎app/core/plugin.py‎

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import inspect
77
import os
88
import sys
9+
import threading
910
import time
1011
import traceback
1112
from concurrent.futures import ThreadPoolExecutor, as_completed
1213
from pathlib import Path
13-
import threading
1414
from typing import Any, Dict, List, Optional, Type, Union, Callable, Tuple
1515

1616
from fastapi import HTTPException
@@ -20,24 +20,24 @@
2020
from app import schemas
2121
from app.core.cache import fresh, async_fresh
2222
from app.core.config import settings
23-
from app.core.event import eventmanager, Event
23+
from app.core.event import eventmanager
2424
from app.db.plugindata_oper import PluginDataOper
2525
from app.db.systemconfig_oper import SystemConfigOper
2626
from app.helper.plugin import PluginHelper
2727
from app.helper.sites import SitesHelper # noqa
2828
from app.log import logger
2929
from app.schemas.types import EventType, SystemConfigKey
3030
from app.utils.crypto import RSAUtils
31+
from app.utils.mixins import ConfigReloadMixin
3132
from app.utils.object import ObjectUtils
3233
from app.utils.singleton import Singleton
3334
from app.utils.string import StringUtils
3435
from app.utils.system import SystemUtils
3536

3637

37-
class PluginManager(metaclass=Singleton):
38-
"""
39-
插件管理器
40-
"""
38+
class PluginManager(ConfigReloadMixin, metaclass=Singleton):
39+
"""插件管理器"""
40+
CONFIG_WATCH = {"DEV", "PLUGIN_AUTO_RELOAD"}
4141

4242
def __init__(self):
4343
# 插件列表
@@ -250,20 +250,12 @@ def plugins(self) -> Dict[str, Any]:
250250
"""
251251
return self._plugins
252252

253-
@eventmanager.register(EventType.ConfigChanged)
254-
def handle_config_changed(self, event: Event):
255-
"""
256-
处理配置变更事件
257-
:param event: 事件对象
258-
"""
259-
if not event:
260-
return
261-
event_data: schemas.ConfigChangeEventData = event.event_data
262-
if event_data.key not in ['DEV', 'PLUGIN_AUTO_RELOAD']:
263-
return
264-
logger.info("配置变更,重新加载插件文件修改监测...")
253+
def on_config_changed(self):
265254
self.reload_monitor()
266255

256+
def get_reload_name(self) -> str:
257+
return "插件文件修改监测"
258+
267259
def reload_monitor(self):
268260
"""
269261
重新加载插件文件修改监测

‎app/helper/doh.py‎

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414
from typing import Dict, Optional
1515

1616
from app.core.config import settings
17-
from app.core.event import Event, eventmanager
1817
from app.log import logger
19-
from app.schemas import ConfigChangeEventData
20-
from app.schemas.types import EventType
18+
from app.utils.mixins import ConfigReloadMixin
2119
from app.utils.singleton import Singleton
2220

2321
# 定义一个全局线程池执行器
@@ -69,25 +67,23 @@ def _patched_getaddrinfo(host, *args, **kwargs):
6967
socket.getaddrinfo = _orig_getaddrinfo
7068

7169

72-
class DohHelper(metaclass=Singleton):
70+
class DohHelper(ConfigReloadMixin, metaclass=Singleton):
7371
"""
7472
DoH帮助类,用于处理DNS over HTTPS解析。
7573
"""
74+
CONFIG_WATCH = {"DOH_ENABLE", "DOH_DOMAINS", "DOH_RESOLVERS"}
75+
7676
def __init__(self):
7777
enable_doh(settings.DOH_ENABLE)
7878

79-
@eventmanager.register(EventType.ConfigChanged)
80-
def handle_config_changed(self, event: Event):
81-
if not event:
82-
return
83-
event_data: ConfigChangeEventData = event.event_data
84-
if event_data.key not in ["DOH_ENABLE", "DOH_DOMAINS", "DOH_RESOLVERS"]:
85-
return
79+
def on_config_changed(self):
8680
with _doh_lock:
8781
# DOH配置有变动的情况下,清空缓存
8882
_doh_cache.clear()
8983
enable_doh(settings.DOH_ENABLE)
9084

85+
def get_reload_name(self):
86+
return 'DoH'
9187

9288
def _doh_query(resolver: str, host: str) -> Optional[str]:
9389
"""

‎app/helper/redis.py‎

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77
from redis.asyncio import Redis
88

99
from app.core.config import settings
10-
from app.core.event import eventmanager, Event
1110
from app.log import logger
12-
from app.schemas import ConfigChangeEventData
13-
from app.schemas.types import EventType
11+
from app.utils.mixins import ConfigReloadMixin
1412
from app.utils.singleton import Singleton
1513

1614
# 类型缓存集合,针对非容器简单类型
@@ -74,16 +72,17 @@ def deserialize(value: bytes) -> Any:
7472
raise ValueError("Unknown serialization format")
7573

7674

77-
class RedisHelper(metaclass=Singleton):
75+
class RedisHelper(ConfigReloadMixin, metaclass=Singleton):
7876
"""
7977
Redis连接和操作助手类,单例模式
80-
78+
8179
特性:
8280
- 管理Redis连接池和客户端
8381
- 提供序列化和反序列化功能
8482
- 支持内存限制和淘��策略设置
8583
- 提供键名生成和区域管理功能
8684
"""
85+
CONFIG_WATCH = {"CACHE_BACKEND_TYPE", "CACHE_BACKEND_URL", "CACHE_REDIS_MAXMEMORY"}
8786

8887
def __init__(self):
8988
"""
@@ -114,25 +113,17 @@ def _connect(self):
114113
self.client = None
115114
raise RuntimeError("Redis connection failed") from e
116115

117-
@eventmanager.register(EventType.ConfigChanged)
118-
def handle_config_changed(self, event: Event):
119-
"""
120-
处理配置变更事件,更新Redis设置
121-
:param event: 事件对象
122-
"""
123-
if not event:
124-
return
125-
event_data: ConfigChangeEventData = event.event_data
126-
if event_data.key not in ['CACHE_BACKEND_TYPE', 'CACHE_BACKEND_URL', 'CACHE_REDIS_MAXMEMORY']:
127-
return
128-
logger.info("配置变更,重连Redis...")
116+
def on_config_changed(self):
129117
self.close()
130118
self._connect()
131119

120+
def get_reload_name(self):
121+
return "Redis"
122+
132123
def set_memory_limit(self, policy: Optional[str] = "allkeys-lru"):
133124
"""
134125
动态设置Redis最大内存和内存淘汰策略
135-
126+
136127
:param policy: 淘汰策略(如'allkeys-lru')
137128
"""
138129
try:
@@ -310,17 +301,18 @@ def close(self) -> None:
310301
logger.debug("Redis connection closed")
311302

312303

313-
class AsyncRedisHelper(metaclass=Singleton):
304+
class AsyncRedisHelper(ConfigReloadMixin, metaclass=Singleton):
314305
"""
315306
异步Redis连接和操作助手类,单例模式
316-
307+
317308
特性:
318309
- 管理异步Redis连接池和客户端
319310
- 提供序列化和反序列化功能
320311
- 支持内存限制和淘汰策略设置
321312
- 提供键名生成和区域管理功能
322313
- 所有操作都是异步的
323314
"""
315+
CONFIG_WATCH = {"CACHE_BACKEND_TYPE", "CACHE_BACKEND_URL", "CACHE_REDIS_MAXMEMORY"}
324316

325317
def __init__(self):
326318
"""
@@ -351,25 +343,17 @@ async def _connect(self):
351343
self.client = None
352344
raise RuntimeError("Redis async connection failed") from e
353345

354-
@eventmanager.register(EventType.ConfigChanged)
355-
async def handle_config_changed(self, event: Event):
356-
"""
357-
处理配置变更事件,更新Redis设置
358-
:param event: 事件对象
359-
"""
360-
if not event:
361-
return
362-
event_data: ConfigChangeEventData = event.event_data
363-
if event_data.key not in ['CACHE_BACKEND_TYPE', 'CACHE_BACKEND_URL', 'CACHE_REDIS_MAXMEMORY']:
364-
return
365-
logger.info("配置变更,重连Redis (async)...")
346+
async def on_config_changed(self):
366347
await self.close()
367348
await self._connect()
368349

350+
def get_reload_name(self):
351+
return "Redis (async)"
352+
369353
async def set_memory_limit(self, policy: Optional[str] = "allkeys-lru"):
370354
"""
371355
动态设置Redis最大内存和内存淘汰策略
372-
356+
373357
:param policy: 淘汰策略(如'allkeys-lru')
374358
"""
375359
try:

‎app/helper/system.py‎

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,32 @@
88
import docker
99

1010
from app.core.config import settings
11-
from app.core.event import eventmanager, Event
1211
from app.log import logger
13-
from app.schemas import ConfigChangeEventData
14-
from app.schemas.types import EventType
12+
from app.utils.mixins import ConfigReloadMixin
1513
from app.utils.system import SystemUtils
1614

1715

18-
class SystemHelper:
16+
class SystemHelper(ConfigReloadMixin):
1917
"""
2018
系统工具类,提供系统相关的操作和判断
2119
"""
20+
CONFIG_WATCH = {
21+
"DEBUG",
22+
"LOG_LEVEL",
23+
"LOG_MAX_FILE_SIZE",
24+
"LOG_BACKUP_COUNT",
25+
"LOG_FILE_FORMAT",
26+
"LOG_CONSOLE_FORMAT",
27+
}
2228

2329
__system_flag_file = "/var/log/nginx/__moviepilot__"
2430

25-
@eventmanager.register(EventType.ConfigChanged)
26-
def handle_config_changed(self, event: Event):
27-
"""
28-
处理配置变更事件,更新日志设置
29-
:param event: 事件对象
30-
"""
31-
if not event:
32-
return
33-
event_data: ConfigChangeEventData = event.event_data
34-
if event_data.key not in ['DEBUG', 'LOG_LEVEL', 'LOG_MAX_FILE_SIZE', 'LOG_BACKUP_COUNT',
35-
'LOG_FILE_FORMAT', 'LOG_CONSOLE_FORMAT']:
36-
return
37-
logger.info("配置变更,更新日志设置...")
31+
def on_config_changed(self):
3832
logger.update_loggers()
3933

34+
def get_reload_name(self):
35+
return "日志设置"
36+
4037
@staticmethod
4138
def can_restart() -> bool:
4239
"""

‎app/modules/__init__.py‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44
from app.helper.service import ServiceConfigHelper
55
from app.schemas import Notification, NotificationConf, MediaServerConf, DownloaderConf
66
from app.schemas.types import ModuleType, DownloaderType, MediaServerType, MessageChannel, StorageSchema, \
7-
OtherModulesType
7+
OtherModulesType, SystemConfigKey
8+
from app.utils.mixins import ConfigReloadMixin
89

910

10-
class _ModuleBase(metaclass=ABCMeta):
11+
class _ModuleBase(ConfigReloadMixin, metaclass=ABCMeta):
1112
"""
1213
模块基类,实现对应方法,在有需要时会被自动调用,返回None代表不启用该模块,将继续执行下一模块
1314
输入参数与输出参数一致的,或没有输出的,可以被多个模块重复实现
1415
"""
1516

17+
def on_config_changed(self):
18+
self.init_module()
19+
20+
def get_reload_name(self):
21+
return self.get_name()
22+
1623
@abstractmethod
1724
def init_module(self) -> None:
1825
"""
@@ -177,6 +184,7 @@ class _MessageBase(ServiceBase[TService, NotificationConf]):
177184
"""
178185
消息基类
179186
"""
187+
CONFIG_WATCH = {SystemConfigKey.Notifications.value}
180188

181189
def __init__(self):
182190
"""
@@ -224,6 +232,7 @@ class _DownloaderBase(ServiceBase[TService, DownloaderConf]):
224232
"""
225233
下载器基类
226234
"""
235+
CONFIG_WATCH = {SystemConfigKey.Downloaders.value}
227236

228237
def __init__(self):
229238
"""
@@ -287,6 +296,7 @@ class _MediaServerBase(ServiceBase[TService, MediaServerConf]):
287296
"""
288297
媒体服务器基类
289298
"""
299+
CONFIG_WATCH = {SystemConfigKey.MediaServers.value}
290300

291301
def get_configs(self) -> Dict[str, MediaServerConf]:
292302
"""

‎app/modules/emby/__init__.py‎

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
from app import schemas
44
from app.core.context import MediaInfo
5-
from app.core.event import eventmanager, Event
5+
from app.core.event import eventmanager
66
from app.log import logger
77
from app.modules import _MediaServerBase, _ModuleBase
88
from app.modules.emby.emby import Emby
9-
from app.schemas.types import MediaType, ModuleType, ChainEventType, MediaServerType, SystemConfigKey, EventType
9+
from app.schemas.types import MediaType, ModuleType, ChainEventType, MediaServerType
1010

1111

1212
class EmbyModule(_ModuleBase, _MediaServerBase[Emby]):
@@ -18,20 +18,6 @@ def init_module(self) -> None:
1818
super().init_service(service_name=Emby.__name__.lower(),
1919
service_type=lambda conf: Emby(**conf.config, sync_libraries=conf.sync_libraries))
2020

21-
@eventmanager.register(EventType.ConfigChanged)
22-
def handle_config_changed(self, event: Event):
23-
"""
24-
处理配置变更事件
25-
:param event: 事件对象
26-
"""
27-
if not event:
28-
return
29-
event_data: schemas.ConfigChangeEventData = event.event_data
30-
if event_data.key not in [SystemConfigKey.MediaServers.value]:
31-
return
32-
logger.info("配置变更,重新初始化Emby模块...")
33-
self.init_module()
34-
3521
@staticmethod
3622
def get_name() -> str:
3723
return "Emby"

0 commit comments

Comments
 (0)