base_agent/uas/action/action_context.py

155 lines
5.7 KiB
Python
Raw Normal View History

2026-06-18 03:28:14 +00:00
# -*- coding: utf-8 -*-
"""
Action 执行上下文
ActionContext 在处理函数执行期间提供
- 共享数据存储 Action 传递状态
- Event 收集器处理函数产生的 Event 暂存于此
- 进度上报接口
- 取消/暂停检查接口
"""
from __future__ import annotations
import logging
import threading
from typing import Any, Callable, Dict, List, Optional
logger = logging.getLogger(__name__)
class ActionContext:
"""
Action 执行上下文每次执行独立实例
处理函数签名
def my_handler(action: Action, ctx: ActionContext) -> Any:
# 产生事件
ctx.emit_event(make_event(EventType.DEVICE_DATA_RECEIVED, ...))
ctx.emit_event(make_event(EventType.DEVICE_STATUS_CHANGED, ...))
# 上报进度
ctx.report_progress(50, "处理中...")
# 检查取消
if ctx.is_cancelled:
return None
return {"result": "ok"}
"""
def __init__(
self,
action, # Action 对象
shared_store: Optional[Dict] = None, # 全局共享数据
progress_cb: Optional[Callable] = None,
):
self._action = action
self._events: List[Any] = [] # 收集产生的 Event 对象
self._store: Dict[str, Any] = shared_store if shared_store is not None else {}
self._lock = threading.Lock()
self._progress_cb = progress_cb
self._progress: int = 0
self._status_msg: str = ""
self.logger = logging.getLogger(
f"ActionContext[{action.type_key}:{action.action_id[:8]}]"
)
# ── Event 收集 ────────────────────────────────────────────────
def emit_event(self, event: Any) -> None:
"""
在处理函数中产生一个 Event 对象
Event 将被收集后统一由 ActionExecutor 提交到 EventBus
"""
with self._lock:
self._events.append(event)
self.logger.debug(f"产生事件: {event}")
def emit_events(self, events: List[Any]) -> None:
"""批量产生多个 Event 对象"""
for event in events:
self.emit_event(event)
@property
def collected_events(self) -> List[Any]:
"""获取所有已收集的 Event 对象(只读副本)"""
with self._lock:
return list(self._events)
# ── 进度上报 ──────────────────────────────────────────────────
def report_progress(self, percent: int, message: str = "") -> None:
"""
上报执行进度0~100
:param percent: 进度百分比
:param message: 进度描述
"""
self._progress = max(0, min(100, percent))
self._status_msg = message
if self._progress_cb:
self._progress_cb(self._action.action_id, self._progress, message)
self.logger.debug(f"进度 {self._progress}% - {message}")
@property
def progress(self) -> int:
return self._progress
@property
def status_message(self) -> str:
return self._status_msg
# ── 取消/暂停检查 ─────────────────────────────────────────────
@property
def is_cancelled(self) -> bool:
"""处理函数内部轮询此属性以响应取消请求"""
return self._action.cancel_requested
@property
def is_paused(self) -> bool:
return self._action.pause_requested
def check_cancel(self) -> bool:
"""
检查取消标志若已取消则抛出 ActionCancelledError
在处理函数关键节点调用ctx.check_cancel()
"""
if self.is_cancelled:
raise ActionCancelledError(
f"Action {self._action.type_key} 已被取消"
)
return False
# ── 共享数据存储 ──────────────────────────────────────────────
def set(self, key: str, value: Any) -> None:
"""写入共享数据"""
with self._lock:
self._store[key] = value
def get(self, key: str, default: Any = None) -> Any:
"""读取共享数据"""
with self._lock:
return self._store.get(key, default)
def update(self, data: dict) -> None:
with self._lock:
self._store.update(data)
@property
def store(self) -> dict:
with self._lock:
return dict(self._store)
# ─────────────────────────────────────────────────────────────────
# 自定义异常
# ─────────────────────────────────────────────────────────────────
class ActionCancelledError(Exception):
"""Action 被取消时抛出"""
pass
class ActionTimeoutError(Exception):
"""Action 执行超时时抛出"""
pass