207 lines
8.8 KiB
Python
207 lines
8.8 KiB
Python
# -*- 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,
|
||
) |