diff --git a/app/application/configuration.py b/app/application/configuration.py index b83c807a9..41371afb2 100644 --- a/app/application/configuration.py +++ b/app/application/configuration.py @@ -140,6 +140,8 @@ class ChainRuntimeConfig: """Chain 在一次宿主生命周期内使用的基础配置快照。""" media_extensions: tuple[str, ...] + api_port: int = 3000 + api_token: str | None = None video_extensions: tuple[str, ...] = () subtitle_extensions: tuple[str, ...] = () audio_extensions: tuple[str, ...] = () @@ -198,6 +200,7 @@ class ChainRuntimeConfig: refresh_batch_size: int = 50 torrent_cache_size: int = 1000 site_url: Optional[str] = None + workflow_url: Optional[str] = None season_zero_names: tuple[str, ...] = () movie_rename_format: str = "" television_rename_format: str = "" diff --git a/app/startup/configuration.py b/app/startup/configuration.py index a65c3b03c..d7e408262 100644 --- a/app/startup/configuration.py +++ b/app/startup/configuration.py @@ -87,6 +87,8 @@ def build_chain_runtime_config(settings: Settings) -> ChainRuntimeConfig: + settings.RMT_SUBEXT + settings.RMT_AUDIOEXT ), + api_port=settings.PORT, + api_token=settings.API_TOKEN, video_extensions=tuple(settings.RMT_MEDIAEXT), subtitle_extensions=tuple(settings.RMT_SUBEXT), audio_extensions=tuple(settings.RMT_AUDIOEXT), @@ -147,6 +149,7 @@ def build_chain_runtime_config(settings: Settings) -> ChainRuntimeConfig: refresh_batch_size=settings.CONF.refresh, torrent_cache_size=settings.CONF.torrents, site_url=settings.MP_DOMAIN("#/site"), + workflow_url=settings.MP_DOMAIN("#/workflow"), season_zero_names=tuple(settings.RENAME_FORMAT_S0_NAMES), movie_rename_format=settings.RENAME_FORMAT(MediaType.MOVIE), television_rename_format=settings.RENAME_FORMAT(MediaType.TV), diff --git a/app/workflow/actions/fetch_medias.py b/app/workflow/actions/fetch_medias.py index acfc75b16..f5faa0225 100644 --- a/app/workflow/actions/fetch_medias.py +++ b/app/workflow/actions/fetch_medias.py @@ -4,9 +4,10 @@ from pydantic import Field from app.workflow.actions import BaseAction from app.chain.recommend import RecommendChain +from app.application.configuration import get_chain_runtime_config_snapshot from app.schemas.workflow import ActionParams from app.schemas.workflow import ActionContext -from app.runtime.config import settings, global_vars +from app.runtime.config import global_vars from app.runtime.events import eventmanager from app.runtime.log import logger from app.schemas.event import RecommendSourceEventData @@ -152,7 +153,11 @@ class FetchMediasAction(BaseAction): results = source['func']() else: # 调用内部API获取数据 - api_url = f"http://127.0.0.1:{settings.PORT}/api/v1/{source['api_path']}?token={settings.API_TOKEN}" + runtime_config = get_chain_runtime_config_snapshot() + api_url = ( + f"http://127.0.0.1:{runtime_config.api_port}" + f"/api/v1/{source['api_path']}?token={runtime_config.api_token}" + ) res = RequestUtils(timeout=15).post_res(api_url) if res: results = res.json() @@ -163,7 +168,11 @@ class FetchMediasAction(BaseAction): logger.error(f"{name} 获取数据失败") else: # 调用内部API获取数据 - api_url = f"http://127.0.0.1:{settings.PORT}{params.api_path}?token={settings.API_TOKEN}" + runtime_config = get_chain_runtime_config_snapshot() + api_url = ( + f"http://127.0.0.1:{runtime_config.api_port}{params.api_path}" + f"?token={runtime_config.api_token}" + ) res = RequestUtils(timeout=15).post_res(api_url) if res: results = res.json() diff --git a/app/workflow/actions/send_message.py b/app/workflow/actions/send_message.py index 8d8d94884..70bb06473 100644 --- a/app/workflow/actions/send_message.py +++ b/app/workflow/actions/send_message.py @@ -3,10 +3,10 @@ from typing import List, Optional, Union from pydantic import Field from app.workflow.actions import BaseAction, ActionChain +from app.application.configuration import get_chain_runtime_config_snapshot from app.schemas.workflow import ActionParams from app.schemas.workflow import ActionContext from app.schemas.message import Message -from app.runtime.config import settings class SendMessageParams(ActionParams): @@ -58,7 +58,7 @@ class SendMessageAction(BaseAction): userid=params.userid, title="【工作流执行结果】", text=msg_text, - link=settings.MP_DOMAIN("#/workflow") + link=get_chain_runtime_config_snapshot().workflow_url ) ) diff --git a/docs/refactor/backend-architecture-next-stage.md b/docs/refactor/backend-architecture-next-stage.md index f592b20a9..3a0759be5 100644 --- a/docs/refactor/backend-architecture-next-stage.md +++ b/docs/refactor/backend-architecture-next-stage.md @@ -1005,6 +1005,7 @@ MFA/Passkey 专项测试与架构门禁通过,密钥类配置仍保留在安 共 280 项测试通过,架构、复杂度与异步阻塞门禁通过。 2026-08-23 将工作流动作 `FetchRssAction`、`ScanFileAction` 和 `AddSubscribeAction` 接入 `ChainRuntimeConfig` 快照,分别移除代理、媒体后缀和超级用户的全局 `settings` 读取;保留动作公开入口与工作流上下文行为,新增快照注入测试覆盖。配置债务由 130 个文件降至 127 个文件,宿主依赖与配置基线已更新。 +2026-08-23 将工作流动作 `FetchMediasAction` 和 `SendMessageAction` 接入 `ChainRuntimeConfig` 快照,分别移除内部 API 端口/令牌及工作流链接的全局 `settings` 读取;保留动作公开入口与消息载荷行为,新增快照注入测试覆盖。配置债务由 127 个文件降至 125 个文件,宿主依赖与配置基线已更新。 **收口记录(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,先提取媒体身份规范化阶段,保留显式 diff --git a/tests/fixtures/architecture/configuration-debt-baseline.json b/tests/fixtures/architecture/configuration-debt-baseline.json index 8d04171f5..69f9d4f05 100644 --- a/tests/fixtures/architecture/configuration-debt-baseline.json +++ b/tests/fixtures/architecture/configuration-debt-baseline.json @@ -9,7 +9,7 @@ "root": "app" }, "settings_imports": { - "count": 127, + "count": 125, "files": [ "app/adapters/cache/backends.py", "app/adapters/cache/redis.py", @@ -135,9 +135,7 @@ "app/startup/lifecycle/__init__.py", "app/startup/modules_initializer.py", "app/startup/plugins_initializer.py", - "app/startup/routers_initializer.py", - "app/workflow/actions/fetch_medias.py", - "app/workflow/actions/send_message.py" + "app/startup/routers_initializer.py" ] }, "system_config_oper_constructions": {