refactor: route monitor and resource settings through runtime

This commit is contained in:
jxxghp
2026-08-23 01:59:37 +08:00
parent 2c6e8181c2
commit b4e003f098
11 changed files with 68 additions and 47 deletions
+2 -2
View File
@@ -20,8 +20,8 @@ from app.adapters.system.plugin.manifest import (
PluginDependencyManifestError,
load_dependency_manifest,
)
from app.runtime.config import settings
from app.runtime.log import logger
from app.runtime.settings import get_runtime_setting
@dataclass
@@ -52,7 +52,7 @@ class PluginDependencyInstaller:
self._helper = helper
self._installed_plugins_provider = installed_plugins_provider or (lambda: [])
self._plugin_dir = plugin_dir or (
Path(settings.ROOT_PATH) / "app" / "plugins"
Path(get_runtime_setting("ROOT_PATH")) / "app" / "plugins"
)
@staticmethod
+5 -3
View File
@@ -11,8 +11,8 @@ from pathlib import Path
from typing import Optional
from app.adapters.external.market import PluginHelper as _PluginHelper
from app.runtime.config import settings
from app.runtime.log import logger
from app.runtime.settings import get_runtime_setting
@dataclass(frozen=True, slots=True)
@@ -37,7 +37,9 @@ class PluginPackageManager:
@staticmethod
def _plugin_dir(plugin_id: str) -> Path:
"""解析插件运行目录并拒绝越出宿主插件根目录的标识。"""
plugins_root = (Path(settings.ROOT_PATH) / "app" / "plugins").resolve()
plugins_root = (
Path(get_runtime_setting("ROOT_PATH")) / "app" / "plugins"
).resolve()
plugin_dir = (plugins_root / plugin_id.lower()).resolve()
if plugin_dir == plugins_root or not plugin_dir.is_relative_to(plugins_root):
raise ValueError(f"非法插件ID{plugin_id}")
@@ -47,7 +49,7 @@ class PluginPackageManager:
"""在包变更前创建独立快照,供后续提交或补偿恢复。"""
plugin_dir = self._plugin_dir(plugin_id)
transaction_dir = (
Path(settings.TEMP_PATH)
Path(get_runtime_setting("TEMP_PATH"))
/ "plugin_transactions"
/ f"{plugin_id.lower()}-{uuid.uuid4().hex}"
)
+20 -11
View File
@@ -4,11 +4,16 @@ import sys
from pathlib import Path
from typing import Callable
from app.runtime.config import settings
from app.runtime import config as _runtime_config
from app.runtime.log import logger
from app.adapters.network.http import RequestUtils
from app.foundation.version import compare_version
from app.adapters.system.host import SystemUtils
from app.runtime.settings import get_runtime_setting
# 保留模块级旧 Settings 入口,旧插件和测试可能仍会对其做运行时覆盖;实现读取统一走 runtime 端口。
settings = _runtime_config.settings
ResourceVersionProvider = Callable[[], tuple[str, str]]
@@ -33,11 +38,11 @@ class ResourceHelper:
检测和更新资源包
"""
_base_dir: Path = settings.ROOT_PATH
_base_dir: Path = get_runtime_setting("ROOT_PATH")
_resource_target = Path("app/application/site")
_version_flag = settings.RESOURCE_VERSION_FLAG
_version_flag = get_runtime_setting("RESOURCE_VERSION_FLAG")
_repo = (
f"{settings.GITHUB_PROXY}https://raw.githubusercontent.com/"
f"{get_runtime_setting('GITHUB_PROXY')}https://raw.githubusercontent.com/"
f"jxxghp/MoviePilot-Resources/main/package.{_version_flag}.json"
)
_files_api = (
@@ -48,7 +53,11 @@ class ResourceHelper:
@property
def proxies(self):
"""返回访问 GitHub 资源时应使用的代理配置。"""
return None if settings.GITHUB_PROXY else settings.PROXY
return (
None
if get_runtime_setting("GITHUB_PROXY")
else get_runtime_setting("PROXY")
)
@staticmethod
def _get_python_version_tag() -> str:
@@ -86,7 +95,7 @@ class ResourceHelper:
"""读取 V3 资源清单。"""
response = RequestUtils(
proxies=self.proxies,
headers=settings.GITHUB_HEADERS,
headers=get_runtime_setting("GITHUB_HEADERS"),
timeout=10,
).get_res(self._repo)
return response if response and response.status_code == 200 else None
@@ -104,7 +113,7 @@ class ResourceHelper:
:param indexer_version: 当前已加载的站点索引资源版本;省略时使用组合根注入值
:return: 是否成功安装了需要由上层处理重启的新资源
"""
if not settings.AUTO_UPDATE_RESOURCE:
if not get_runtime_setting("AUTO_UPDATE_RESOURCE"):
return False
if SystemUtils.is_frozen():
return False
@@ -159,8 +168,8 @@ class ResourceHelper:
if need_updates:
# 下载文件信息列表
r = RequestUtils(
proxies=settings.PROXY,
headers=settings.GITHUB_HEADERS,
proxies=get_runtime_setting("PROXY"),
headers=get_runtime_setting("GITHUB_HEADERS"),
timeout=30,
).get_res(self._files_api)
if r and not r.ok:
@@ -186,11 +195,11 @@ class ResourceHelper:
if item.get("download_url"):
logger.info(f"开始更新资源文件:{file_name} ...")
download_url = (
f"{settings.GITHUB_PROXY}{item.get('download_url')}"
f"{get_runtime_setting('GITHUB_PROXY')}{item.get('download_url')}"
)
res = RequestUtils(
proxies=self.proxies,
headers=settings.GITHUB_HEADERS,
headers=get_runtime_setting("GITHUB_HEADERS"),
timeout=180,
).get_res(download_url)
if not res:
+6 -3
View File
@@ -6,7 +6,6 @@ from typing import Any, Dict, List, Optional, Tuple
from app.chain.transfer import TransferChain
from app.runtime.cache import TTLCache
from app.runtime.config import settings
from app.application.directory import DirectoryHelper
from app.application.history import (
HistoryGateAction,
@@ -21,6 +20,7 @@ from app.runtime.log import logger
from app.adapters.system.fsproxy import fsproxy
from app.schemas.workflow import FileItem
from app.schemas.types import MediaType
from app.runtime.settings import get_runtime_setting
class TransferDispatcher:
@@ -39,7 +39,10 @@ class TransferDispatcher:
:param cache: 去重缓存,默认使用 10 秒 TTL 缓存
"""
self.all_exts = all_exts if all_exts is not None else (
settings.RMT_MEDIAEXT + settings.RMT_SUBEXT + settings.RMT_AUDIOEXT)
get_runtime_setting("RMT_MEDIAEXT")
+ get_runtime_setting("RMT_SUBEXT")
+ get_runtime_setting("RMT_AUDIOEXT")
)
self._cache = cache if cache is not None else TTLCache(region="monitor", maxsize=1024, ttl=10)
self._lock = Lock()
# 历史查询失败待重试的文件
@@ -76,7 +79,7 @@ class TransferDispatcher:
"""
判断监控事件路径是否需要进入整理链。
"""
if self._has_suffix_in(file_path, settings.DOWNLOAD_TMPEXT):
if self._has_suffix_in(file_path, get_runtime_setting("DOWNLOAD_TMPEXT")):
return False
return self._has_suffix_in(file_path, self.all_exts)
+3 -3
View File
@@ -7,7 +7,6 @@ from typing import Any, Callable, Dict, List, Optional, Tuple
from apscheduler.schedulers.background import BackgroundScheduler
from app.runtime.config import settings
from app.application.directory import DirectoryHelper
from app.application.messaging.message import MessageHelper
from app.runtime.log import logger
@@ -21,6 +20,7 @@ from app.schemas.types import SystemConfigKey
from app.runtime.reload import ConfigReloadMixin
from app.foundation.singleton import SingletonClass
from app.adapters.system.host import SystemUtils
from app.runtime.settings import get_runtime_setting
class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
@@ -172,7 +172,7 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
logger.info(f"找到 {len(monitor_dirs)} 个目录监控配置")
# 启动定时服务进程
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
self._scheduler = BackgroundScheduler(timezone=get_runtime_setting("TZ"))
mon_storages: Dict[str, List[Path]] = {}
# 本地监控启动结果计数,用于输出真实的启动总结
@@ -285,7 +285,7 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
# 网络/FUSE 挂载轮询降频,减少监控自身对挂载后端的持续 stat 压力
poll_delay_ms = None
if use_polling and SystemUtils.is_network_filesystem(mon_path):
poll_delay_ms = (settings.MONITOR_POLL_DELAY_NETWORK
poll_delay_ms = (get_runtime_setting("MONITOR_POLL_DELAY_NETWORK")
or LocalDirectoryWatcher.POLL_DELAY_NETWORK_MS)
logger.info(f"检测到网络文件系统,轮询扫描间隔调整为 {poll_delay_ms}ms: {mon_path}")
+4 -2
View File
@@ -3,8 +3,8 @@ import time
from typing import Dict, List, Optional, Tuple
from app.runtime.cache import FileCache
from app.runtime.config import settings
from app.runtime.log import logger
from app.runtime.settings import get_runtime_setting
class SnapshotStore:
@@ -18,7 +18,9 @@ class SnapshotStore:
初始化快照存储。
:param cache: 快照文件缓存,默认使用 CACHE_PATH/snapshots
"""
self._cache = cache if cache is not None else FileCache(base=settings.CACHE_PATH / "snapshots")
self._cache = cache if cache is not None else FileCache(
base=get_runtime_setting("CACHE_PATH") / "snapshots"
)
def save(self, storage: str, snapshot: Dict, file_count: int = 0,
last_snapshot_time: Optional[float] = None,
+2 -2
View File
@@ -2,9 +2,9 @@ import platform
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from app.runtime.config import settings
from app.runtime.log import logger
from app.adapters.system.host import SystemUtils
from app.runtime.settings import get_runtime_setting
def count_directory_entries(directory: Path, max_check: int = 10000) -> Tuple[int, int]:
@@ -123,7 +123,7 @@ def decide_monitor_mode(directory: Path,
# 检查网络文件系统
if SystemUtils.is_network_filesystem(directory):
if not settings.MONITOR_NETWORK_FAST_MODE:
if not get_runtime_setting("MONITOR_NETWORK_FAST_MODE"):
return True, "检测到网络文件系统,建议使用兼容模式", None, None
# 用户已确认该挂载支持 inotify,继续走快速模式的系统限制检查
logger.info(f"检测到网络文件系统,但已配置允许快速模式: {directory}")
+4 -2
View File
@@ -7,8 +7,8 @@ from typing import Any, Optional
from watchfiles import Change, DefaultFilter, watch
from app.runtime.config import settings
from app.runtime.log import logger
from app.runtime.settings import get_runtime_setting
@dataclass(frozen=True)
@@ -285,7 +285,9 @@ class LocalDirectoryWatcher:
配置,配置热更新后无需重建监控线程即可生效;解析失败或未配置时回退默认值。
:return: 重扫轮次延迟秒数元组
"""
return self._parse_rescan_delays(getattr(settings, "MONITOR_RESCAN_DELAYS", None))
return self._parse_rescan_delays(
get_runtime_setting("MONITOR_RESCAN_DELAYS")
)
@classmethod
def _parse_rescan_delays(cls, raw: Optional[str]) -> tuple[int, ...]:
@@ -70,7 +70,7 @@ MoviePilot V3 当前不是“目录混乱、必须推倒重来”的状态。第
| legacy 默认模块契约 | 0 个宿主观察方法;未知动态方法保留 fallback | 所有静态宿主方法已有显式 V2 spec;真实 fallback 命中由 `module.contract.legacy_hit` 观测 |
| 事件枚举 | 53 | 66 个静态 producer、15 个静态 consumer |
| 专用 EventData model | 53 | Event Contract Registry 已为全部事件登记 typed payload/fallback 原因 |
| 直接读取 `settings` 的文件 | 117 | 仍按模块族迁移,动态协议和安全端口暂保留 |
| 直接读取 `settings` 的文件 | 109 | 仍按模块族迁移,动态协议和安全端口暂保留 |
| `SystemConfigOper()` | 1 个 | 仅组合根创建 `SystemConfigService` 时保留 |
| Model 上的 DB 查询装饰器 | 119 | `db_update`/`async_db_update` 为 0;查询 ABI 继续按 canonical 用例迁移 |
| 路由端点 | 335 | 11 个已装饰端点超过 80 行,最大 400 行 |
@@ -1023,6 +1023,16 @@ MFA/Passkey 专项测试与架构门禁通过,密钥类配置仍保留在安
2026-08-23 将 `CookieCloudHelper` 的五项运行配置改为通过 `RuntimeSettingsService` 读取;同步期间仍获取最新值,未装配时保留旧 Settings ABI。配置债务由 120 个文件降至 119 个文件,并通过 CookieCloud 路由与站点回归测试。
2026-08-23 将 DoH 开关、域名和解析器配置改为通过 `RuntimeSettingsService` 动态读取;socket 补丁、热更新、缓存和线程池关闭语义保持不变,未装配时保留旧 Settings ABI。配置债务由 119 个文件降至 118 个文件,并通过 DoH 与生命周期回归测试。
2026-08-23 将 Rust 加速开关改为通过 `RuntimeSettingsService` 动态读取;扩展可用性、异常回退和公开适配器 API 保持不变,未装配时保留旧 Settings ABI。配置债务由 118 个文件降至 117 个文件,并通过 Rust 解析与开关回归测试。
2026-08-23 将目录监控的快照、整理分发、系统限制、监控门面和本地 watcher 配置读取统一改为
`app.runtime.settings.get_runtime_setting()`;保留未装配时的旧 Settings 回退和热更新读取语义,监控专项
87 项测试、Pylint 与架构基线通过。配置债务由 117 个文件降至 112 个文件。
随后将插件依赖扫描、插件包事务和 V3 资源安装适配器的部署配置读取迁移到同一 runtime 端口;资源适配器
保留模块级 `settings` 兼容入口供旧插件覆盖,实际逻辑动态读取 runtime 配置。插件/资源专项 141 项测试、
Pylint 与架构基线通过,配置债务由 112 个文件降至 109 个文件。
同日修正适配器配置下沉边界:OCR、CookieCloud、DoH、Rust 和资源签名等低层实现不再直接依赖
`app.application`,由 `app.runtime.settings` 端口承接组合根注入;未启动装配时仍回退旧 Settings ABI
架构依赖专项和官方插件语义观察均通过。
**收口记录(2026-08-22**`reidentify_cache``nettest``scrape`、OpenAI `chat_completions/responses``get_logging` 和 Web Agent SSE 均改为稳定公开入口委托私有编排实现;四个消息交互 Handler 的公开方法也保留 ABI 并委托私有状态机。复杂度基线已清零,API/Application/Chain 入口预算、异步阻塞 ratchet 均通过;复杂度及兼容专项合计 252 项测试通过。
随后将 `TransferChain.do_transfer` 的公开入口收口为稳定兼容 Facade,先提取媒体身份规范化阶段,保留显式
@@ -9,7 +9,7 @@
"root": "app"
},
"settings_imports": {
"count": 117,
"count": 109,
"files": [
"app/adapters/cache/backends.py",
"app/adapters/cache/redis.py",
@@ -17,9 +17,6 @@
"app/adapters/external/server.py",
"app/adapters/network/browser.py",
"app/adapters/system/fsproxy.py",
"app/adapters/system/plugin/dependency.py",
"app/adapters/system/plugin/package.py",
"app/adapters/system/resource.py",
"app/adapters/web/security/access.py",
"app/agent/capabilities/adapter.py",
"app/agent/llm/capability.py",
@@ -110,11 +107,6 @@
"app/modules/webpush/__init__.py",
"app/modules/wechat/wechatbot.py",
"app/modules/wechatclawbot/wechatclawbot.py",
"app/monitor/dispatcher.py",
"app/monitor/monitor.py",
"app/monitor/snapshot.py",
"app/monitor/syslimits.py",
"app/monitor/watcher.py",
"app/runtime/extensions/host_module_adapter.py",
"app/runtime/extensions/module_manager.py",
"app/runtime/extensions/plugin/catalog.py",
+10 -9
View File
@@ -13,8 +13,8 @@
"runtime_to_db": [],
"workflow_to_db": []
},
"edge_count": 6418,
"edge_sha256": "8ec406999c67a103722fdb3e2cb641dff8addc83b4c60df7b0ea18027afdfb08",
"edge_count": 6419,
"edge_sha256": "dffb0fbffbe79a933346a0d5be5332b61ca2323f732ca1b9c919af8e01abe73e",
"edges": [
"app -> app.runtime",
"app -> app.runtime.compat",
@@ -134,16 +134,16 @@
"app.adapters.system.plugin.dependency -> app.adapters.system.plugin",
"app.adapters.system.plugin.dependency -> app.adapters.system.plugin.manifest",
"app.adapters.system.plugin.dependency -> app.runtime",
"app.adapters.system.plugin.dependency -> app.runtime.config",
"app.adapters.system.plugin.dependency -> app.runtime.log",
"app.adapters.system.plugin.dependency -> app.runtime.settings",
"app.adapters.system.plugin.manifest -> app.runtime",
"app.adapters.system.plugin.manifest -> app.runtime.log",
"app.adapters.system.plugin.package -> app.adapters",
"app.adapters.system.plugin.package -> app.adapters.external",
"app.adapters.system.plugin.package -> app.adapters.external.market",
"app.adapters.system.plugin.package -> app.runtime",
"app.adapters.system.plugin.package -> app.runtime.config",
"app.adapters.system.plugin.package -> app.runtime.log",
"app.adapters.system.plugin.package -> app.runtime.settings",
"app.adapters.system.resource -> app.adapters",
"app.adapters.system.resource -> app.adapters.network",
"app.adapters.system.resource -> app.adapters.network.http",
@@ -154,6 +154,7 @@
"app.adapters.system.resource -> app.runtime",
"app.adapters.system.resource -> app.runtime.config",
"app.adapters.system.resource -> app.runtime.log",
"app.adapters.system.resource -> app.runtime.settings",
"app.adapters.system.rust -> app.runtime",
"app.adapters.system.rust -> app.runtime.log",
"app.adapters.system.rust -> app.runtime.settings",
@@ -5379,8 +5380,8 @@
"app.monitor.dispatcher -> app.chain.transfer",
"app.monitor.dispatcher -> app.runtime",
"app.monitor.dispatcher -> app.runtime.cache",
"app.monitor.dispatcher -> app.runtime.config",
"app.monitor.dispatcher -> app.runtime.log",
"app.monitor.dispatcher -> app.runtime.settings",
"app.monitor.dispatcher -> app.schemas",
"app.monitor.dispatcher -> app.schemas.types",
"app.monitor.dispatcher -> app.schemas.workflow",
@@ -5401,9 +5402,9 @@
"app.monitor.monitor -> app.monitor.syslimits",
"app.monitor.monitor -> app.monitor.watcher",
"app.monitor.monitor -> app.runtime",
"app.monitor.monitor -> app.runtime.config",
"app.monitor.monitor -> app.runtime.log",
"app.monitor.monitor -> app.runtime.reload",
"app.monitor.monitor -> app.runtime.settings",
"app.monitor.monitor -> app.schemas",
"app.monitor.monitor -> app.schemas.types",
"app.monitor.poller -> app.chain",
@@ -5417,21 +5418,21 @@
"app.monitor.recovery -> app.runtime.log",
"app.monitor.snapshot -> app.runtime",
"app.monitor.snapshot -> app.runtime.cache",
"app.monitor.snapshot -> app.runtime.config",
"app.monitor.snapshot -> app.runtime.log",
"app.monitor.snapshot -> app.runtime.settings",
"app.monitor.syslimits -> app.adapters",
"app.monitor.syslimits -> app.adapters.system",
"app.monitor.syslimits -> app.adapters.system.fsproxy",
"app.monitor.syslimits -> app.adapters.system.host",
"app.monitor.syslimits -> app.runtime",
"app.monitor.syslimits -> app.runtime.config",
"app.monitor.syslimits -> app.runtime.log",
"app.monitor.syslimits -> app.runtime.settings",
"app.monitor.watcher -> app.adapters",
"app.monitor.watcher -> app.adapters.system",
"app.monitor.watcher -> app.adapters.system.fsproxy",
"app.monitor.watcher -> app.runtime",
"app.monitor.watcher -> app.runtime.config",
"app.monitor.watcher -> app.runtime.log",
"app.monitor.watcher -> app.runtime.settings",
"app.runtime.capabilities.registry -> app.runtime",
"app.runtime.capabilities.registry -> app.runtime.capabilities",
"app.runtime.capabilities.registry -> app.runtime.capabilities.errors",