mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-30 12:36:55 +08:00
fix: preserve legacy event and db dto contracts
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
"""
|
||||
import time
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Tuple, List, Optional
|
||||
|
||||
from sqlalchemy import delete as sqlalchemy_delete, select
|
||||
@@ -28,13 +27,31 @@ AfterCommitEffect = Callable[[int], None]
|
||||
AsyncAfterCommitEffect = Callable[[int], Awaitable[None]]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class SubscribeStageResult:
|
||||
"""Oper 暂存结果,按 Application 端口需要暴露最小只读状态。"""
|
||||
|
||||
subscribe_id: int
|
||||
message: str
|
||||
created: bool
|
||||
__slots__ = ("_subscribe_id", "_message", "_created")
|
||||
|
||||
def __init__(self, subscribe_id: int, message: str, created: bool) -> None:
|
||||
"""保存写入后的订阅 ID、消息和是否创建标志。"""
|
||||
self._subscribe_id = subscribe_id
|
||||
self._message = message
|
||||
self._created = created
|
||||
|
||||
@property
|
||||
def subscribe_id(self) -> int:
|
||||
"""返回已暂存或已存在的订阅 ID。"""
|
||||
return self._subscribe_id
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
"""返回暂存结果的人类可读消息。"""
|
||||
return self._message
|
||||
|
||||
@property
|
||||
def created(self) -> bool:
|
||||
"""返回本次暂存是否创建了新记录。"""
|
||||
return self._created
|
||||
|
||||
|
||||
def _normalize_integer_flags(payload: dict, fields: Tuple[str, ...] = INTEGER_FLAG_FIELDS) -> dict:
|
||||
|
||||
@@ -130,17 +130,40 @@ EVENT_CONTRACTS = {
|
||||
}
|
||||
|
||||
|
||||
def get_event_contract(event_type: EventType | ChainEventType) -> EventContract:
|
||||
"""返回 enum 事件的完整登记契约。"""
|
||||
return EVENT_CONTRACTS[event_type]
|
||||
def normalize_event_type(
|
||||
event_type: EventType | ChainEventType | str,
|
||||
) -> EventType | ChainEventType | str:
|
||||
"""把旧 SDK 传入的已知字符串恢复为 enum,未知扩展值保持原样。"""
|
||||
if not isinstance(event_type, str):
|
||||
return event_type
|
||||
for enum_type in (EventType, ChainEventType):
|
||||
try:
|
||||
return enum_type(event_type)
|
||||
except ValueError:
|
||||
continue
|
||||
return event_type
|
||||
|
||||
|
||||
def get_event_contract(
|
||||
event_type: EventType | ChainEventType | str,
|
||||
) -> EventContract:
|
||||
"""返回已登记事件的完整契约,兼容传入 enum value 字符串。"""
|
||||
normalized = normalize_event_type(event_type)
|
||||
if isinstance(normalized, str):
|
||||
raise KeyError(normalized)
|
||||
return EVENT_CONTRACTS[normalized]
|
||||
|
||||
|
||||
def validate_event_payload(
|
||||
event_type: EventType | ChainEventType,
|
||||
event_type: EventType | ChainEventType | str,
|
||||
payload: Any,
|
||||
) -> tuple[str, ...]:
|
||||
"""在发送边界诊断首批 typed payload,保持原对象和插件 dict 形状不变。"""
|
||||
model = get_event_contract(event_type).payload_model
|
||||
try:
|
||||
model = get_event_contract(event_type).payload_model
|
||||
except KeyError:
|
||||
# 动态插件在旧 ABI 下可能使用宿主枚举之外的字符串事件。
|
||||
return ()
|
||||
if model is None or payload is None:
|
||||
return ()
|
||||
if isinstance(payload, model):
|
||||
|
||||
@@ -20,7 +20,7 @@ from app.runtime.event.binding import (
|
||||
from app.runtime.event.dispatch import EventDispatcher
|
||||
from app.runtime.event.errors import EventErrorNotifier, EventErrorPolicy
|
||||
from app.runtime.event.registry import EventRegistry
|
||||
from app.runtime.event.contracts import validate_event_payload
|
||||
from app.runtime.event.contracts import normalize_event_type, validate_event_payload
|
||||
from app.runtime.correlation import get_correlation_id
|
||||
from app.runtime.observability import record_metric
|
||||
|
||||
@@ -35,7 +35,7 @@ class Event:
|
||||
事件类,封装事件的基本信息
|
||||
"""
|
||||
|
||||
def __init__(self, event_type: Union[EventType, ChainEventType],
|
||||
def __init__(self, event_type: Union[EventType, ChainEventType, str],
|
||||
event_data: Optional[Union[Dict, ChainEventData]] = None,
|
||||
priority: Optional[int] = DEFAULT_EVENT_PRIORITY,
|
||||
correlation_id: Optional[str] = None):
|
||||
@@ -45,11 +45,12 @@ class Event:
|
||||
:param priority: 可选,事件的优先级,默认为 10
|
||||
:param correlation_id: 生产事件时固化的请求关联 ID
|
||||
"""
|
||||
event_type = normalize_event_type(event_type)
|
||||
payload_problems = validate_event_payload(event_type, event_data)
|
||||
if payload_problems:
|
||||
logger.warning(
|
||||
"事件 %s payload 与登记契约不一致:%s;当前保留旧 payload 继续投递",
|
||||
event_type.value,
|
||||
getattr(event_type, "value", event_type),
|
||||
"; ".join(payload_problems),
|
||||
)
|
||||
self.event_id = str(uuid.uuid4()) # 事件ID
|
||||
@@ -63,7 +64,8 @@ class Event:
|
||||
重写 __repr__ 方法,用于返回事件的详细信息,包括事件类型、事件ID和优先级
|
||||
"""
|
||||
event_kind = Event.get_event_kind(self.event_type)
|
||||
return f"<{event_kind}: {self.event_type.value}, ID: {self.event_id}, Priority: {self.priority}>"
|
||||
event_name = getattr(self.event_type, "value", self.event_type)
|
||||
return f"<{event_kind}: {event_name}, ID: {self.event_id}, Priority: {self.priority}>"
|
||||
|
||||
def __lt__(self, other):
|
||||
"""
|
||||
@@ -73,7 +75,7 @@ class Event:
|
||||
return self.priority < other.priority
|
||||
|
||||
@staticmethod
|
||||
def get_event_kind(event_type: Union[EventType, ChainEventType]) -> str:
|
||||
def get_event_kind(event_type: Union[EventType, ChainEventType, str]) -> str:
|
||||
"""
|
||||
根据事件类型判断事件是广播事件还是链式事件
|
||||
:param event_type: 事件类型,支持 EventType 或 ChainEventType
|
||||
|
||||
Reference in New Issue
Block a user