Files
ecm_sync_system/sync_state_machine/domain/units/api_handler.py
T
strepsiades f5729d5a18 整理代码
2026-04-03 09:18:44 +08:00

177 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Units (机组) API Handler
职责:
- 更新项目机组数据
- 不支持创建和删除(机组随项目自动生成)
实现的接口:
PUT:
- /units - 更新机组数据
"""
from typing import List, Dict, Any
from ...datasource.api.handler import BaseApiHandler
from ...datasource.task_result import TaskResult
from ...common.sync_node import SyncNode
from ...datasource.api.errors import ERROR_VALIDATION_FAILED
from .sync_node import UnitsSyncNode
from schemas.project_extensions.generator_unit import GeneratorUnitProject, PostGeneratorUnits
class UnitsApiHandler(BaseApiHandler):
"""机组 API Handler"""
def __init__(self):
super().__init__(node_class=UnitsSyncNode, schema=GeneratorUnitProject)
async def load(self) -> List[SyncNode]:
"""加载机组数据(从 project all_info 中提取)"""
from ..project.api_handler import ProjectApiHandler
# 获取已加载的项目
projects = self._collection.filter(node_type="project")
if not projects:
print("⚠️ No projects found, skipping units load")
return []
nodes = []
for project in projects:
project_id = project.data_id
try:
# 从 project context 或缓存获取 all_info
all_info = project.context.get("all_info")
if not all_info:
all_info = await ProjectApiHandler.get_all_info(
self.api_client,
project_id
)
# 提取 generator_units
units_list = all_info.get("generator_units", [])
print(f" Project {project_id}: {len(units_list)} units")
for unit_data in units_list:
# 验证数据
try:
validated = self._schema.model_validate(unit_data)
node = self._create_node(validated.model_dump())
node.context["project_id"] = project_id
nodes.append(node)
except Exception as e:
print(f"⚠️ Skipping invalid unit: {e}")
continue
except Exception as e:
print(f"❌ Failed to load units for project {project_id}: {e}")
continue
return nodes
async def create_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
"""不支持创建"""
return [
TaskResult.failed(node_id=node.node_id, error="Units creation not supported (auto-generated with project)")
for node in nodes
]
async def update_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
"""批量更新机组数据"""
from pydantic import ValidationError
results = []
for node in nodes:
node_data = node.get_data()
if node_data is None:
error_msg = node.error or "Node data is missing or invalid"
results.append(TaskResult.failed(node_id=node.node_id, error=f"Cannot update: {error_msg}"))
continue
origin_data = node.get_origin_data() or {}
force_steps_update = self._steps_changed(node)
update_data = self.build_update_request_data(
node_data,
origin_data,
PostGeneratorUnits,
force_full_schema=force_steps_update,
)
if not update_data:
reason = f"No physical diff found for units {node.data_id} despite strategy update request (Normalization Discrepancy)."
print(f" [WARNING] [units] {reason}")
results.append(TaskResult.skipped(node_id=node.node_id, reason=reason))
continue
# 验证并转换为 Pydantic model
try:
update_model = PostGeneratorUnits.model_validate(update_data)
except ValidationError as e:
results.append(TaskResult.failed(node_id=node.node_id, error=f"{ERROR_VALIDATION_FAILED}: {e}"))
continue
push_id = self._generate_push_id()
biz_id = node.data_id or update_model.id
if not biz_id:
results.append(TaskResult.failed(node_id=node.node_id, error="Missing biz_id for update"))
continue
try:
await api_update_units(
self.api_client,
update_model,
push_id,
biz_id,
steps=self._get_request_steps(node),
)
self._mark_approval_snapshot_synced(node)
results.append(TaskResult.success(node_id=node.node_id))
except Exception as e:
results.append(TaskResult.failed(node_id=node.node_id, error=str(e)))
return results
async def delete_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
"""不支持删除"""
return [
TaskResult.failed(node_id=node.node_id, error="Units deletion not supported")
for node in nodes
]
async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
"""轮询异步任务状态"""
return await super().poll_tasks(task_ids)
def _create_node(self, data: Dict[str, Any]) -> SyncNode:
node = self._create_basic_node(data, depend_ids=[])
if data.get("project_id"):
node.context["project_id"] = data["project_id"]
return node
# ========== 静态 API 函数 ==========
async def api_update_units(
client,
data: PostGeneratorUnits,
push_id: str,
biz_id: str,
*,
steps: List[Dict[str, Any]] | None = None,
) -> None:
"""
PUT /units - 更新机组数据
Args:
client: API 客户端
data: 更新数据(Pydantic model
push_id: 推送ID
biz_id: 业务ID
"""
request_data = {"push_id": push_id, "biz_id": biz_id, "data": data.model_dump(exclude_unset=True), "steps": steps or []}
response = await client.request(method="PUT", endpoint="/units", data=request_data)
if response.get("code") != 200:
raise Exception(f"API error: {response.get('message', 'Unknown error')}")