base_agent/uas/model/lifecycle.py

187 lines
7.3 KiB
Python
Raw Normal View History

2026-06-18 03:28:14 +00:00
# -*- coding: utf-8 -*-
"""
装备模型生命周期状态机
LifecycleState 枚举CREATED / READY / RUNNING / PAUSED /
STOPPED / ERROR
LifecycleFSM 有限状态机管理合法状态转移非法转移抛出异常
"""
from __future__ import annotations
from enum import Enum
from typing import Dict, Set, Callable, Optional
# ─────────────────────────────────────────────────────────────────
# 生命周期状态枚举
# ─────────────────────────────────────────────────────────────────
class LifecycleState(Enum):
CREATED = "CREATED" # 刚创建,参数未就绪
READY = "READY" # 参数就绪,可启动
RUNNING = "RUNNING" # 仿真运行中
PAUSED = "PAUSED" # 暂停(可恢复)
STOPPED = "STOPPED" # 已停止(不可恢复,需 reset
ERROR = "ERROR" # 发生错误
# ─────────────────────────────────────────────────────────────────
# 合法状态转移表
# ─────────────────────────────────────────────────────────────────
# { 当前状态 → 可转移到的目标状态集合 }
_TRANSITIONS: Dict[LifecycleState, Set[LifecycleState]] = {
LifecycleState.CREATED: {
LifecycleState.READY,
LifecycleState.ERROR,
},
LifecycleState.READY: {
LifecycleState.RUNNING,
LifecycleState.ERROR,
},
LifecycleState.RUNNING: {
LifecycleState.PAUSED,
LifecycleState.STOPPED,
LifecycleState.ERROR,
LifecycleState.READY, # reset 时
},
LifecycleState.PAUSED: {
LifecycleState.RUNNING,
LifecycleState.STOPPED,
LifecycleState.ERROR,
LifecycleState.READY, # reset 时
},
LifecycleState.STOPPED: {
LifecycleState.READY, # reset 后可重新启动
LifecycleState.ERROR,
},
LifecycleState.ERROR: {
LifecycleState.READY, # 错误恢复后 reset
},
}
# ─────────────────────────────────────────────────────────────────
# 生命周期有限状态机
# ─────────────────────────────────────────────────────────────────
class LifecycleFSM:
"""
装备模型生命周期有限状态机
职责
- 维护当前状态
- 校验状态转移合法性
- 触发转移回调on_enter / on_exit
- 记录状态历史
"""
def __init__(
self,
initial: LifecycleState = LifecycleState.CREATED,
on_changed: Optional[Callable[[str, str], None]] = None,
):
self._state: LifecycleState = initial
self._history: list = [(initial, 0.0)]
self._on_changed = on_changed # (old, new) 回调
# ── 属性 ──────────────────────────────────────────────────────
@property
def state(self) -> LifecycleState:
return self._state
@property
def history(self) -> list:
return list(self._history)
# ── 状态查询 ──────────────────────────────────────────────────
@property
def is_running(self) -> bool:
return self._state == LifecycleState.RUNNING
@property
def is_paused(self) -> bool:
return self._state == LifecycleState.PAUSED
@property
def is_stopped(self) -> bool:
return self._state == LifecycleState.STOPPED
@property
def is_ready(self) -> bool:
return self._state == LifecycleState.READY
@property
def is_error(self) -> bool:
return self._state == LifecycleState.ERROR
@property
def can_step(self) -> bool:
"""是否可以执行 step()"""
return self._state == LifecycleState.RUNNING
# ── 状态转移 ──────────────────────────────────────────────────
def transition(
self,
target: LifecycleState,
timestamp: float = 0.0,
force: bool = False,
) -> bool:
"""
执行状态转移
:param target: 目标状态
:param timestamp: 当前仿真时刻用于历史记录
:param force: True=强制转移跳过合法性检查仅内部使用
:return: True=转移成功False=已在目标状态
:raises ValueError: 非法状态转移
"""
if self._state == target:
return False
if not force:
allowed = _TRANSITIONS.get(self._state, set())
if target not in allowed:
raise ValueError(
f"非法状态转移: {self._state.value}{target.value} "
f"(允许: {[s.value for s in allowed]}"
)
old_state = self._state
self._state = target
self._history.append((target, timestamp))
if self._on_changed:
self._on_changed(old_state.value, target.value)
return True
# ── 快捷转移方法 ──────────────────────────────────────────────
def to_ready(self, t: float = 0.0) -> bool:
return self.transition(LifecycleState.READY, t)
def to_running(self, t: float = 0.0) -> bool:
return self.transition(LifecycleState.RUNNING, t)
def to_paused(self, t: float = 0.0) -> bool:
return self.transition(LifecycleState.PAUSED, t)
def to_stopped(self, t: float = 0.0) -> bool:
return self.transition(LifecycleState.STOPPED, t)
def to_error(self, t: float = 0.0) -> bool:
return self.transition(LifecycleState.ERROR, t, force=True)
# ── 工具 ──────────────────────────────────────────────────────
def reset(self, t: float = 0.0) -> bool:
"""强制重置到 READY任意状态均可"""
return self.transition(LifecycleState.READY, t, force=True)
def __repr__(self) -> str:
return f"LifecycleFSM(state={self._state.value})"