mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-14 01:39:45 +08:00
117 lines
3.2 KiB
Python
117 lines
3.2 KiB
Python
"""事件 payload 的只读契约快照访问。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from typing import Any
|
||
|
||
from pydantic import BaseModel, ValidationError
|
||
|
||
from app.runtime.event.contracts import get_event_contract, normalize_event_type
|
||
from app.schemas.types import ChainEventType, EventType
|
||
|
||
|
||
@dataclass(frozen=True, slots=True)
|
||
class EventPayloadSnapshot:
|
||
"""保存原始 payload 及按登记契约解析出的独立快照。"""
|
||
|
||
event_type: EventType | ChainEventType | str
|
||
raw: Any
|
||
payload: BaseModel | None
|
||
input: BaseModel | None
|
||
output: BaseModel | None
|
||
known: bool
|
||
schema_version: int | None
|
||
payload_mode: str | None
|
||
validation_mode: str | None
|
||
errors: tuple[str, ...] = ()
|
||
|
||
@property
|
||
def valid(self) -> bool:
|
||
"""返回已知事件的全部登记模型是否都通过校验。"""
|
||
return self.known and not self.errors
|
||
|
||
|
||
def _model_snapshot(
|
||
model: type[BaseModel] | None,
|
||
payload: Any,
|
||
label: str,
|
||
cache: dict[type[BaseModel], BaseModel | None],
|
||
errors: list[str],
|
||
) -> BaseModel | None:
|
||
"""按单个模型构造快照,同一模型在一次访问中只解析一次。"""
|
||
if model is None:
|
||
return None
|
||
if model in cache:
|
||
return cache[model]
|
||
if isinstance(payload, model):
|
||
cache[model] = payload.model_copy(deep=True)
|
||
return cache[model]
|
||
try:
|
||
cache[model] = model.model_validate(payload)
|
||
except (ValidationError, TypeError, ValueError) as error:
|
||
cache[model] = None
|
||
errors.append(f"{label}:{model.__name__}: {error}")
|
||
return cache[model]
|
||
|
||
|
||
def snapshot_event_data(
|
||
event_type: EventType | ChainEventType | str,
|
||
event_data: Any,
|
||
) -> EventPayloadSnapshot:
|
||
"""按事件注册契约解析 payload,未知自定义事件保持原始数据并返回未登记状态。"""
|
||
normalized = normalize_event_type(event_type)
|
||
try:
|
||
contract = get_event_contract(normalized)
|
||
except KeyError:
|
||
return EventPayloadSnapshot(
|
||
event_type=normalized,
|
||
raw=event_data,
|
||
payload=None,
|
||
input=None,
|
||
output=None,
|
||
known=False,
|
||
schema_version=None,
|
||
payload_mode=None,
|
||
validation_mode=None,
|
||
)
|
||
|
||
errors: list[str] = []
|
||
cache: dict[type[BaseModel], BaseModel | None] = {}
|
||
payload_snapshot = _model_snapshot(
|
||
contract.payload_model,
|
||
event_data,
|
||
"payload",
|
||
cache,
|
||
errors,
|
||
)
|
||
input_snapshot = _model_snapshot(
|
||
contract.input_model,
|
||
event_data,
|
||
"input",
|
||
cache,
|
||
errors,
|
||
)
|
||
output_snapshot = _model_snapshot(
|
||
contract.output_model,
|
||
event_data,
|
||
"output",
|
||
cache,
|
||
errors,
|
||
)
|
||
return EventPayloadSnapshot(
|
||
event_type=normalized,
|
||
raw=event_data,
|
||
payload=payload_snapshot,
|
||
input=input_snapshot,
|
||
output=output_snapshot,
|
||
known=True,
|
||
schema_version=contract.schema_version,
|
||
payload_mode=contract.payload_mode.value,
|
||
validation_mode=contract.validation_mode.value,
|
||
errors=tuple(errors),
|
||
)
|
||
|
||
|
||
__all__ = ["EventPayloadSnapshot", "snapshot_event_data"]
|