base_agent/uas/event/event_model.py

207 lines
8.8 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.

# -*- coding: utf-8 -*-
"""
事件数据模型
─────────────────────────────────────────────────────────────────
Event —— 核心事件对象,贯穿整个生命周期
EventResult —— 处理器返回结果
EventState —— 事件处理状态机
─────────────────────────────────────────────────────────────────
"""
from __future__ import annotations
import time
import uuid
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Union
from uas.event.event_type import EventType, EventPriority, event_registry
# ─────────────────────────────────────────────────────────────────
# 事件状态
# ─────────────────────────────────────────────────────────────────
class EventState(Enum):
CREATED = "created" # 已创建,未提交
PENDING = "pending" # 已提交,等待处理
PROCESSING = "processing" # 处理中
HANDLED = "handled" # 已处理完成
CANCELLED = "cancelled" # 已取消
FAILED = "failed" # 处理失败
IGNORED = "ignored" # 无处理器,已忽略
# ─────────────────────────────────────────────────────────────────
# 事件处理结果
# ─────────────────────────────────────────────────────────────────
@dataclass
class EventResult:
"""单个处理器的执行结果"""
handler_name: str
success: bool
data: Any = None
error: str = ""
elapsed_ms: float = 0.0
def __repr__(self):
status = "" if self.success else ""
return f"EventResult({status} {self.handler_name} {self.elapsed_ms:.1f}ms)"
# ─────────────────────────────────────────────────────────────────
# 核心事件对象
# ─────────────────────────────────────────────────────────────────
@dataclass
class Event:
"""
核心事件对象
─────────────────────────────────────────────────────────────
字段说明:
event_type —— 事件类型EventType 枚举 或 自定义字符串)
source —— 事件来源设备ID、模块名等
params —— 事件携带参数(任意字典)
priority —— 优先级(默认从注册表读取)
timestamp —— 发生时间Unix 时间戳,自动填充)
event_id —— 唯一标识UUID自动生成
─────────────────────────────────────────────────────────────
"""
event_type: Union[EventType, str]
source: str = "unknown"
params: Dict[str, Any] = field(default_factory=dict)
priority: Optional[EventPriority] = None
message: str = ""
# 自动填充字段
event_id: str = field(default_factory=lambda: str(uuid.uuid4()))
timestamp: float = field(default_factory=time.time)
state: EventState = field(default=EventState.CREATED)
# 运行时字段(不参与构造)
results: List[EventResult] = field(default_factory=list)
_cancelled: bool = field(default=False, repr=False)
_submit_time: Optional[float] = field(default=None, repr=False)
_done_time: Optional[float] = field(default=None, repr=False)
def __post_init__(self):
# 若未指定优先级,从注册表读取
if self.priority is None:
self.priority = event_registry.get_priority(self.type_key)
# ── 属性 ──────────────────────────────────────────────────────
@property
def type_key(self) -> str:
"""统一返回字符串 key"""
return (self.event_type.value
if isinstance(self.event_type, EventType)
else str(self.event_type))
@property
def datetime(self) -> datetime:
return datetime.fromtimestamp(self.timestamp)
@property
def datetime_str(self) -> str:
return self.datetime.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
@property
def is_cancelled(self) -> bool:
return self._cancelled
@property
def elapsed_ms(self) -> float:
"""从提交到完成的总耗时ms"""
if self._submit_time and self._done_time:
return (self._done_time - self._submit_time) * 1000
return 0.0
@property
def success_count(self) -> int:
return sum(1 for r in self.results if r.success)
@property
def failed_count(self) -> int:
return sum(1 for r in self.results if not r.success)
# ── 状态操作 ──────────────────────────────────────────────────
def cancel(self) -> bool:
"""取消事件(仅 cancellable 类型可取消)"""
if event_registry.is_cancellable(self.type_key):
self._cancelled = True
self.state = EventState.CANCELLED
return True
return False
def mark_pending(self):
self.state = EventState.PENDING
self._submit_time = time.time()
def mark_processing(self):
self.state = EventState.PROCESSING
def mark_done(self):
self._done_time = time.time()
if self._cancelled:
self.state = EventState.CANCELLED
elif any(not r.success for r in self.results):
self.state = EventState.FAILED
elif not self.results:
self.state = EventState.IGNORED
else:
self.state = EventState.HANDLED
def add_result(self, result: EventResult):
self.results.append(result)
# ── 序列化 ────────────────────────────────────────────────────
def to_dict(self) -> dict:
return {
"event_id": self.event_id,
"event_type": self.type_key,
"source": self.source,
"message": self.message,
"params": self.params,
"priority": self.priority.name if self.priority else "NORMAL",
"timestamp": self.timestamp,
"datetime": self.datetime_str,
"state": self.state.value,
"elapsed_ms": self.elapsed_ms,
"results": [str(r) for r in self.results],
}
def __repr__(self):
return (f"Event(id={self.event_id[:8]}, type={self.type_key!r}, "
f"src={self.source!r}, state={self.state.value}, "
f"priority={self.priority.name if self.priority else 'N/A'})")
# ─────────────────────────────────────────────────────────────────
# 便捷工厂函数
# ─────────────────────────────────────────────────────────────────
def make_event(
event_type: Union[EventType, str],
source: str = "system",
message: str = "",
**params
) -> Event:
"""
快速创建事件
示例:
e = make_event(EventType.DEVICE_ERROR, source="sensor-01",
message="温度传感器异常", code="E001", temp=98.5)
"""
return Event(
event_type = event_type,
source = source,
message = message,
params = params,
)