mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
refactor(workflow): enforce typed query boundary
This commit is contained in:
@@ -5,7 +5,6 @@ from __future__ import annotations
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
|
||||
AgentDataFactory = Callable[[], Any]
|
||||
|
||||
|
||||
@@ -76,12 +75,6 @@ class DownloadHistoryPort(_PortProxy):
|
||||
port_name = "download_history"
|
||||
|
||||
|
||||
class WorkflowPort(_PortProxy):
|
||||
"""工作流数据端口代理。"""
|
||||
|
||||
port_name = "workflow"
|
||||
|
||||
|
||||
class PluginDataPort(_PortProxy):
|
||||
"""插件数据端口代理。"""
|
||||
|
||||
@@ -110,7 +103,6 @@ def configure_agent_data_ports(**factories: AgentDataFactory) -> None:
|
||||
"subscribe_history",
|
||||
"transfer_history",
|
||||
"download_history",
|
||||
"workflow",
|
||||
"plugin_data",
|
||||
}
|
||||
missing = sorted(required - factories.keys())
|
||||
@@ -167,11 +159,6 @@ def get_agent_download_history_port() -> Any:
|
||||
return get_agent_data_ports().download_history()
|
||||
|
||||
|
||||
def get_agent_workflow_port() -> Any:
|
||||
"""创建 Agent 工作流数据端口实例。"""
|
||||
return get_agent_data_ports().workflow()
|
||||
|
||||
|
||||
def get_agent_plugin_data_port() -> Any:
|
||||
"""创建 Agent 插件数据端口实例。"""
|
||||
return get_agent_data_ports().plugin_data()
|
||||
|
||||
@@ -4,8 +4,10 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import asdict
|
||||
from typing import Any, Optional
|
||||
|
||||
from app.application.workflow import WorkflowSnapshot
|
||||
from app.schemas.media import resolve_media_identity
|
||||
|
||||
|
||||
@@ -26,8 +28,10 @@ class ServerSharingService:
|
||||
*,
|
||||
subscribe_provider: Callable[[int], Any],
|
||||
async_subscribe_provider: Callable[[int], Awaitable[Any]],
|
||||
workflow_provider: Callable[[int], Any],
|
||||
async_workflow_provider: Callable[[int], Awaitable[Any]],
|
||||
workflow_provider: Callable[[int], Optional[WorkflowSnapshot]],
|
||||
async_workflow_provider: Callable[
|
||||
[int], Awaitable[Optional[WorkflowSnapshot]]
|
||||
],
|
||||
user_uuid_provider: Callable[[], str],
|
||||
subscribe_sender: Callable[[dict], Any],
|
||||
async_subscribe_sender: Callable[[dict], Awaitable[Any]],
|
||||
@@ -68,9 +72,9 @@ class ServerSharingService:
|
||||
return payload
|
||||
|
||||
@staticmethod
|
||||
def prepare_workflow(workflow: Any) -> dict:
|
||||
def prepare_workflow(workflow: WorkflowSnapshot) -> dict:
|
||||
"""移除本地字段并把动作和流程编码为中心服务兼容格式。"""
|
||||
workflow_dict = workflow.to_dict()
|
||||
workflow_dict = asdict(workflow)
|
||||
workflow_dict.pop("id", None)
|
||||
workflow_dict.pop("context", None)
|
||||
workflow_dict["actions"] = json.dumps(workflow_dict["actions"] or [])
|
||||
@@ -78,7 +82,9 @@ class ServerSharingService:
|
||||
return workflow_dict
|
||||
|
||||
@staticmethod
|
||||
def validate_workflow(workflow: Any) -> tuple[bool, str]:
|
||||
def validate_workflow(
|
||||
workflow: Optional[WorkflowSnapshot],
|
||||
) -> tuple[bool, str]:
|
||||
"""验证工作流存在且同时包含动作与流程。"""
|
||||
if not workflow:
|
||||
return False, "工作流不存在"
|
||||
@@ -160,6 +166,8 @@ class ServerSharingService:
|
||||
valid, message = self.validate_workflow(workflow)
|
||||
if not valid:
|
||||
return False, message
|
||||
if workflow is None:
|
||||
return False, "工作流不存在"
|
||||
payload = {
|
||||
"share_title": share_title,
|
||||
"share_comment": share_comment,
|
||||
@@ -188,6 +196,8 @@ class ServerSharingService:
|
||||
valid, message = self.validate_workflow(workflow)
|
||||
if not valid:
|
||||
return False, message
|
||||
if workflow is None:
|
||||
return False, "工作流不存在"
|
||||
payload = {
|
||||
"share_title": share_title,
|
||||
"share_comment": share_comment,
|
||||
|
||||
+72
-15
@@ -1,11 +1,12 @@
|
||||
"""工作流状态与定义写操作应用用例。"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
from collections.abc import Awaitable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable, Mapping, Optional, Protocol, TypeVar
|
||||
from typing import Any, Callable, List, Mapping, Optional, Protocol, TypeVar
|
||||
|
||||
from app.schemas.common import JsonData
|
||||
|
||||
WORKFLOW_TRIGGER_TIMER = "timer"
|
||||
WORKFLOW_TRIGGER_EVENT = "event"
|
||||
@@ -17,6 +18,30 @@ SUPPORTED_WORKFLOW_TRIGGERS = {
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class WorkflowSnapshot:
|
||||
"""工作流查询返回的脱离数据库会话的冻结快照。"""
|
||||
|
||||
id: int
|
||||
name: str
|
||||
description: Optional[str]
|
||||
timer: Optional[str]
|
||||
trigger_type: Optional[str]
|
||||
event_type: Optional[str]
|
||||
event_conditions: Mapping[str, JsonData]
|
||||
state: str
|
||||
current_action: Optional[str]
|
||||
result: Optional[str]
|
||||
run_count: Optional[int]
|
||||
actions: tuple[Mapping[str, JsonData], ...]
|
||||
flows: tuple[Mapping[str, JsonData], ...]
|
||||
context: Mapping[str, JsonData]
|
||||
execution_config: Mapping[str, JsonData]
|
||||
execution_state: Mapping[str, JsonData]
|
||||
add_time: Optional[str]
|
||||
last_time: Optional[str]
|
||||
|
||||
|
||||
class WorkflowRuntime(Protocol):
|
||||
"""声明宿主入口与 Chain 消费的工作流运行时能力。"""
|
||||
|
||||
@@ -40,7 +65,7 @@ class WorkflowRuntime(Protocol):
|
||||
"""移除全部或指定工作流的事件触发器。"""
|
||||
...
|
||||
|
||||
def update_workflow_event(self, workflow: Any) -> None:
|
||||
def update_workflow_event(self, workflow: WorkflowSnapshot) -> None:
|
||||
"""按最新定义刷新工作流事件触发器。"""
|
||||
...
|
||||
|
||||
@@ -87,15 +112,31 @@ def get_workflow_manager() -> WorkflowRuntime:
|
||||
return _workflow_runtime_provider()
|
||||
|
||||
|
||||
class AsyncWorkflowQueryRepository(Protocol):
|
||||
"""工作流查询用例需要的异步读取端口。"""
|
||||
class WorkflowQueryRepository(Protocol):
|
||||
"""工作流查询用例需要的同步与异步快照端口。"""
|
||||
|
||||
async def async_list(self) -> list[Any]:
|
||||
"""读取全部工作流。"""
|
||||
def get(self, workflow_id: int) -> Optional[WorkflowSnapshot]:
|
||||
"""按 ID 读取工作流快照。"""
|
||||
...
|
||||
|
||||
async def async_get(self, workflow_id: int) -> Optional[Any]:
|
||||
"""按 ID 读取工作流。"""
|
||||
def list_enabled(self) -> List[WorkflowSnapshot]:
|
||||
"""读取全部启用的工作流快照。"""
|
||||
...
|
||||
|
||||
def list_timer_enabled(self) -> List[WorkflowSnapshot]:
|
||||
"""读取启用的定时工作流快照。"""
|
||||
...
|
||||
|
||||
def list_event_enabled(self) -> List[WorkflowSnapshot]:
|
||||
"""读取启用的事件工作流快照。"""
|
||||
...
|
||||
|
||||
async def async_list(self) -> List[WorkflowSnapshot]:
|
||||
"""异步读取全部工作流快照。"""
|
||||
...
|
||||
|
||||
async def async_get(self, workflow_id: int) -> Optional[WorkflowSnapshot]:
|
||||
"""异步按 ID 读取工作流快照。"""
|
||||
...
|
||||
|
||||
|
||||
@@ -114,18 +155,34 @@ class WorkflowCachePort(Protocol):
|
||||
class WorkflowQueryService:
|
||||
"""提供工作流列表和详情查询,隔离 API 与数据库会话。"""
|
||||
|
||||
def __init__(self, repository: AsyncWorkflowQueryRepository) -> None:
|
||||
"""保存请求级异步查询端口。"""
|
||||
def __init__(self, repository: WorkflowQueryRepository) -> None:
|
||||
"""保存可返回脱离会话快照的查询端口。"""
|
||||
self._repository = repository
|
||||
|
||||
async def list(self) -> list[Any]:
|
||||
"""返回全部工作流。"""
|
||||
async def list(self) -> List[WorkflowSnapshot]:
|
||||
"""返回全部工作流快照。"""
|
||||
return await self._repository.async_list()
|
||||
|
||||
async def get(self, workflow_id: int) -> Optional[Any]:
|
||||
"""返回指定工作流。"""
|
||||
async def get(self, workflow_id: int) -> Optional[WorkflowSnapshot]:
|
||||
"""返回指定工作流快照。"""
|
||||
return await self._repository.async_get(workflow_id)
|
||||
|
||||
def get_sync(self, workflow_id: int) -> Optional[WorkflowSnapshot]:
|
||||
"""同步返回指定工作流快照。"""
|
||||
return self._repository.get(workflow_id)
|
||||
|
||||
def list_enabled(self) -> List[WorkflowSnapshot]:
|
||||
"""同步返回全部启用的工作流快照。"""
|
||||
return self._repository.list_enabled()
|
||||
|
||||
def list_timer_enabled(self) -> List[WorkflowSnapshot]:
|
||||
"""同步返回启用的定时工作流快照。"""
|
||||
return self._repository.list_timer_enabled()
|
||||
|
||||
def list_event_enabled(self) -> List[WorkflowSnapshot]:
|
||||
"""同步返回启用的事件工作流快照。"""
|
||||
return self._repository.list_event_enabled()
|
||||
|
||||
|
||||
_configured_workflow_query: WorkflowQueryService | None = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user