159 lines
6.1 KiB
Python
159 lines
6.1 KiB
Python
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
Action 工厂注册表
|
|||
|
|
─────────────────────────────────────────────────────────────────
|
|||
|
|
将 ActionType → handler 函数的映射集中管理
|
|||
|
|
支持:
|
|||
|
|
- 内置 handler 自动注册
|
|||
|
|
- 运行时动态注册/覆盖 handler
|
|||
|
|
- 通过 create() 工厂方法快速创建 Action 实例
|
|||
|
|
─────────────────────────────────────────────────────────────────
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
import threading
|
|||
|
|
from typing import Callable, Dict, List, Optional, Union
|
|||
|
|
|
|||
|
|
from uas.action.action_model import Action, make_action
|
|||
|
|
from uas.action.action_type import ActionType
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ActionFactory:
|
|||
|
|
"""
|
|||
|
|
Action 工厂(单例)
|
|||
|
|
─────────────────────────────────────────────────────────────
|
|||
|
|
使用方式:
|
|||
|
|
factory = ActionFactory.instance()
|
|||
|
|
|
|||
|
|
# 注册自定义 handler
|
|||
|
|
factory.register(ActionType.CAPTURE_PHOTO, my_photo_handler)
|
|||
|
|
|
|||
|
|
# 创建 Action 实例(自动绑定 handler)
|
|||
|
|
action = factory.create(
|
|||
|
|
ActionType.CAPTURE_PHOTO,
|
|||
|
|
source = "camera-01",
|
|||
|
|
resolution = "4K",
|
|||
|
|
format = "jpg",
|
|||
|
|
)
|
|||
|
|
─────────────────────────────────────────────────────────────
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
_instance = None
|
|||
|
|
_lock = threading.Lock()
|
|||
|
|
|
|||
|
|
@classmethod
|
|||
|
|
def instance(cls) -> "ActionFactory":
|
|||
|
|
if cls._instance is None:
|
|||
|
|
cls._instance = cls()
|
|||
|
|
return cls._instance
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
# { type_key: handler_fn }
|
|||
|
|
self._handlers: Dict[str, Callable] = {}
|
|||
|
|
self._init_builtin()
|
|||
|
|
|
|||
|
|
def _init_builtin(self):
|
|||
|
|
"""自动注册所有内置 handler"""
|
|||
|
|
from uas.action.actions.builtin_actions import BUILTIN_HANDLERS
|
|||
|
|
for action_type, handler in BUILTIN_HANDLERS.items():
|
|||
|
|
self.register(action_type, handler)
|
|||
|
|
logger.info(f"✅ ActionFactory 初始化,内置 handler={len(self._handlers)}")
|
|||
|
|
|
|||
|
|
# ── 注册 ──────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def register(
|
|||
|
|
self,
|
|||
|
|
action_type: Union[ActionType, str],
|
|||
|
|
handler: Callable,
|
|||
|
|
override: bool = True,
|
|||
|
|
) -> None:
|
|||
|
|
"""
|
|||
|
|
注册 Action 处理函数
|
|||
|
|
:param action_type: ActionType 枚举 或 自定义字符串
|
|||
|
|
:param handler: fn(action: Action, ctx: ActionContext) -> Any
|
|||
|
|
:param override: True=允许覆盖已有 handler
|
|||
|
|
"""
|
|||
|
|
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
|
|||
|
|
with self._lock:
|
|||
|
|
if key in self._handlers and not override:
|
|||
|
|
logger.warning(f"handler 已存在且 override=False,跳过: {key}")
|
|||
|
|
return
|
|||
|
|
self._handlers[key] = handler
|
|||
|
|
logger.info(f"注册 handler: {key} -> {handler.__name__}")
|
|||
|
|
|
|||
|
|
def unregister(self, action_type: Union[ActionType, str]) -> bool:
|
|||
|
|
"""注销 handler"""
|
|||
|
|
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
|
|||
|
|
with self._lock:
|
|||
|
|
if key in self._handlers:
|
|||
|
|
del self._handlers[key]
|
|||
|
|
logger.info(f"注销 handler: {key}")
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def get_handler(self, action_type: Union[ActionType, str]) -> Optional[Callable]:
|
|||
|
|
"""获取指定类型的 handler"""
|
|||
|
|
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
|
|||
|
|
return self._handlers.get(key)
|
|||
|
|
|
|||
|
|
def has_handler(self, action_type: Union[ActionType, str]) -> bool:
|
|||
|
|
key = action_type.value if isinstance(action_type, ActionType) else str(action_type)
|
|||
|
|
return key in self._handlers
|
|||
|
|
|
|||
|
|
def registered_types(self) -> List[str]:
|
|||
|
|
return list(self._handlers.keys())
|
|||
|
|
|
|||
|
|
# ── 工厂创建 ──────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def create(
|
|||
|
|
self,
|
|||
|
|
action_type: Union[ActionType, str],
|
|||
|
|
source: str = "system",
|
|||
|
|
priority: int = 0,
|
|||
|
|
handler: Optional[Callable] = None,
|
|||
|
|
**params
|
|||
|
|
) -> Action:
|
|||
|
|
"""
|
|||
|
|
工厂方法:创建并自动绑定 handler 的 Action 实例
|
|||
|
|
:param action_type: 行为类型
|
|||
|
|
:param source: 触发来源
|
|||
|
|
:param priority: 执行优先级
|
|||
|
|
:param handler: 若指定则覆盖注册表中的 handler
|
|||
|
|
:param params: 传递给 Action 的业务参数
|
|||
|
|
:return: Action 实例
|
|||
|
|
"""
|
|||
|
|
resolved_handler = handler or self.get_handler(action_type)
|
|||
|
|
if resolved_handler is None:
|
|||
|
|
logger.warning(f"未找到 handler: {action_type},将使用空处理器")
|
|||
|
|
resolved_handler = _noop_handler
|
|||
|
|
|
|||
|
|
action = make_action(
|
|||
|
|
action_type = action_type,
|
|||
|
|
handler = resolved_handler,
|
|||
|
|
source = source,
|
|||
|
|
priority = priority,
|
|||
|
|
**params,
|
|||
|
|
)
|
|||
|
|
logger.debug(f"创建 Action: {action}")
|
|||
|
|
return action
|
|||
|
|
|
|||
|
|
def create_batch(self, specs: List[dict]) -> List[Action]:
|
|||
|
|
"""
|
|||
|
|
批量创建 Action
|
|||
|
|
:param specs: [{"action_type": ..., "source": ..., **params}, ...]
|
|||
|
|
"""
|
|||
|
|
return [self.create(**spec) for spec in specs]
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _noop_handler(action, ctx):
|
|||
|
|
"""空处理器(未注册 handler 时的占位)"""
|
|||
|
|
logger.warning(f"[noop] Action [{action.type_key}] 无处理器,跳过执行")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 全局工厂实例
|
|||
|
|
action_factory = ActionFactory.instance()
|