ForcePilot/backend/package/yuxi/channel/infrastructure/plugin/manifest_parser.py
Kris 9e503becd3
Some checks failed
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
feat(plugin): 实现完整的插件注册管理系统
新增了插件相关的完整领域模型、应用服务、基础设施实现,包括:
1. 插件状态、注册模式、来源等基础枚举和数据结构
2. 插件清单解析、发现、加载工具类
3. 插件注册表领域服务和内存存储实现
4. 插件相关的命令、查询、事件定义
5. 插件REST API接口和DTO映射
6. 集成了原有通道适配器到插件系统
7. 新增内置插件注册和自动发现能力
2026-05-31 16:44:13 +08:00

71 lines
2.5 KiB
Python

from __future__ import annotations
import logging
from dataclasses import dataclass
from yuxi.channel.domain.exception.plugin_exception import InvalidManifestException
from yuxi.channel.domain.model.plugin_registry.plugin_manifest import PluginManifest
from yuxi.channel.domain.model.shared.channel_capabilities import ChannelCapabilities
logger = logging.getLogger(__name__)
@dataclass
class ManifestParseResult:
manifest: PluginManifest
raw: dict
class ManifestParser:
def parse(self, data: dict) -> ManifestParseResult:
try:
plugin_id = data.get("id", "")
name = data.get("name", "")
version = data.get("version", "0.0.0")
channel_type = data.get("channel_type", "")
entry = data.get("entry", "")
dependencies = data.get("dependencies", [])
config_schema = data.get("config_schema", None)
caps_data = data.get("capabilities", {})
capabilities = ChannelCapabilities(
media=caps_data.get("media", False),
group=caps_data.get("group", False),
dm=caps_data.get("dm", True),
streaming=caps_data.get("streaming", False),
typing=caps_data.get("typing", False),
reaction=caps_data.get("reaction", False),
thread=caps_data.get("thread", False),
max_text_length=caps_data.get("max_text_length", 4096),
)
manifest = PluginManifest(
id=plugin_id,
name=name,
version=version,
channel_type=channel_type,
capabilities=capabilities,
config_schema=config_schema,
entry=entry,
dependencies=dependencies,
)
return ManifestParseResult(manifest=manifest, raw=data)
except InvalidManifestException:
raise
except Exception as exc:
raise InvalidManifestException(str(exc)) from exc
async def parse_file(self, path: str) -> ManifestParseResult:
try:
import yaml
with open(path) as f:
data = yaml.safe_load(f) or {}
except FileNotFoundError as exc:
raise InvalidManifestException(f"manifest file not found: {path}") from exc
except Exception as exc:
raise InvalidManifestException(f"failed to parse manifest: {exc}") from exc
return self.parse(data)