重构适配器系统并增强插件架构
- 在mofox_bus中,将BaseAdapter重命名为AdapterBase以提高清晰度。 - 引入了AdapterInfo类来封装适配器组件信息。 - 增强的PluginManager,支持核心消息接收器配置和适配器注册。 - 实现了EnvelopeConverter,用于将MessageEnvelope转换为内部消息格式。 - 创建了BaseAdapter类来管理插件的生命周期、配置和健康检查。 - 开发了AdapterManager,用于管理适配器实例和子流程。 - 添加了一个示例适配器插件,以展示与新适配器系统的集成。 - 删除了过时的Phi插件文档。
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
"""
|
||||
|
||||
from .base_action import BaseAction
|
||||
from .base_adapter import BaseAdapter
|
||||
from .base_command import BaseCommand
|
||||
from .base_events_handler import BaseEventHandler
|
||||
from .base_http_component import BaseRouterComponent
|
||||
@@ -15,6 +16,7 @@ from .command_args import CommandArgs
|
||||
from .component_types import (
|
||||
ActionActivationType,
|
||||
ActionInfo,
|
||||
AdapterInfo,
|
||||
ChatMode,
|
||||
ChatType,
|
||||
CommandInfo,
|
||||
@@ -36,7 +38,9 @@ from .plus_command import PlusCommand, create_plus_command_adapter
|
||||
__all__ = [
|
||||
"ActionActivationType",
|
||||
"ActionInfo",
|
||||
"AdapterInfo",
|
||||
"BaseAction",
|
||||
"BaseAdapter",
|
||||
"BaseCommand",
|
||||
"BaseEventHandler",
|
||||
"BasePlugin",
|
||||
@@ -56,7 +60,7 @@ __all__ = [
|
||||
"PluginMetadata",
|
||||
# 增强命令系统
|
||||
"PlusCommand",
|
||||
"BaseRouterComponent"
|
||||
"BaseRouterComponent",
|
||||
"PlusCommandInfo",
|
||||
"PythonDependency",
|
||||
"ToolInfo",
|
||||
|
||||
252
src/plugin_system/base/base_adapter.py
Normal file
252
src/plugin_system/base/base_adapter.py
Normal file
@@ -0,0 +1,252 @@
|
||||
"""
|
||||
插件系统 Adapter 基类
|
||||
|
||||
提供插件化的适配器支持,包装 mofox_bus.AdapterBase,
|
||||
添加插件生命周期、配置管理、自动启动等特性。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Dict, Optional
|
||||
|
||||
from mofox_bus import AdapterBase as MoFoxAdapterBase, CoreMessageSink, MessageEnvelope
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.plugin_system.base.base_plugin import BasePlugin
|
||||
|
||||
from src.common.logger import get_logger
|
||||
|
||||
logger = get_logger("plugin.adapter")
|
||||
|
||||
|
||||
class BaseAdapter(MoFoxAdapterBase, ABC):
|
||||
"""
|
||||
插件系统的 Adapter 基类
|
||||
|
||||
相比 mofox_bus.AdapterBase,增加了以下特性:
|
||||
1. 插件生命周期管理 (on_adapter_loaded, on_adapter_unloaded)
|
||||
2. 配置管理集成
|
||||
3. 自动重连与健康检查
|
||||
4. 子进程启动支持
|
||||
"""
|
||||
|
||||
# 适配器元数据
|
||||
adapter_name: str = "unknown_adapter"
|
||||
adapter_version: str = "0.0.1"
|
||||
adapter_author: str = "Unknown"
|
||||
adapter_description: str = "No description"
|
||||
|
||||
# 是否在子进程中运行
|
||||
run_in_subprocess: bool = True
|
||||
|
||||
# 子进程启动脚本路径(相对于插件目录)
|
||||
subprocess_entry: Optional[str] = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
core_sink: CoreMessageSink,
|
||||
plugin: Optional[BasePlugin] = None,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
core_sink: 核心消息接收器
|
||||
plugin: 所属插件实例(可选)
|
||||
**kwargs: 传递给 AdapterBase 的其他参数
|
||||
"""
|
||||
super().__init__(core_sink, **kwargs)
|
||||
self.plugin = plugin
|
||||
self._config: Dict[str, Any] = {}
|
||||
self._health_check_task: Optional[asyncio.Task] = None
|
||||
self._running = False
|
||||
|
||||
@property
|
||||
def config(self) -> Dict[str, Any]:
|
||||
"""获取适配器配置"""
|
||||
if self.plugin and hasattr(self.plugin, "config"):
|
||||
return self.plugin.config
|
||||
return self._config
|
||||
|
||||
@config.setter
|
||||
def config(self, value: Dict[str, Any]) -> None:
|
||||
"""设置适配器配置"""
|
||||
self._config = value
|
||||
|
||||
async def start(self) -> None:
|
||||
"""启动适配器"""
|
||||
logger.info(f"启动适配器: {self.adapter_name} v{self.adapter_version}")
|
||||
|
||||
# 调用生命周期钩子
|
||||
await self.on_adapter_loaded()
|
||||
|
||||
# 调用父类启动
|
||||
await super().start()
|
||||
|
||||
# 启动健康检查
|
||||
if self.config.get("enable_health_check", False):
|
||||
self._health_check_task = asyncio.create_task(self._health_check_loop())
|
||||
|
||||
self._running = True
|
||||
logger.info(f"适配器 {self.adapter_name} 启动成功")
|
||||
|
||||
async def stop(self) -> None:
|
||||
"""停止适配器"""
|
||||
logger.info(f"停止适配器: {self.adapter_name}")
|
||||
|
||||
self._running = False
|
||||
|
||||
# 停止健康检查
|
||||
if self._health_check_task and not self._health_check_task.done():
|
||||
self._health_check_task.cancel()
|
||||
try:
|
||||
await self._health_check_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
# 调用父类停止
|
||||
await super().stop()
|
||||
|
||||
# 调用生命周期钩子
|
||||
await self.on_adapter_unloaded()
|
||||
|
||||
logger.info(f"适配器 {self.adapter_name} 已停止")
|
||||
|
||||
async def on_adapter_loaded(self) -> None:
|
||||
"""
|
||||
适配器加载时的钩子
|
||||
子类可重写以执行初始化逻辑
|
||||
"""
|
||||
pass
|
||||
|
||||
async def on_adapter_unloaded(self) -> None:
|
||||
"""
|
||||
适配器卸载时的钩子
|
||||
子类可重写以执行清理逻辑
|
||||
"""
|
||||
pass
|
||||
|
||||
async def _health_check_loop(self) -> None:
|
||||
"""健康检查循环"""
|
||||
interval = self.config.get("health_check_interval", 30)
|
||||
|
||||
while self._running:
|
||||
try:
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
# 执行健康检查
|
||||
is_healthy = await self.health_check()
|
||||
|
||||
if not is_healthy:
|
||||
logger.warning(f"适配器 {self.adapter_name} 健康检查失败,尝试重连...")
|
||||
await self.reconnect()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"适配器 {self.adapter_name} 健康检查异常: {e}", exc_info=True)
|
||||
|
||||
async def health_check(self) -> bool:
|
||||
"""
|
||||
健康检查
|
||||
子类可重写以实现自定义检查逻辑
|
||||
|
||||
Returns:
|
||||
bool: 是否健康
|
||||
"""
|
||||
# 默认检查 WebSocket 连接状态
|
||||
if self._ws and not self._ws.closed:
|
||||
return True
|
||||
return False
|
||||
|
||||
async def reconnect(self) -> None:
|
||||
"""
|
||||
重新连接
|
||||
子类可重写以实现自定义重连逻辑
|
||||
"""
|
||||
try:
|
||||
await self.stop()
|
||||
await asyncio.sleep(2) # 等待一段时间再重连
|
||||
await self.start()
|
||||
except Exception as e:
|
||||
logger.error(f"适配器 {self.adapter_name} 重连失败: {e}", exc_info=True)
|
||||
|
||||
def get_subprocess_entry_path(self) -> Optional[Path]:
|
||||
"""
|
||||
获取子进程启动脚本的完整路径
|
||||
|
||||
Returns:
|
||||
Path | None: 脚本路径,如果不存在则返回 None
|
||||
"""
|
||||
if not self.subprocess_entry:
|
||||
return None
|
||||
|
||||
if not self.plugin:
|
||||
return None
|
||||
|
||||
# 获取插件目录
|
||||
plugin_dir = Path(self.plugin.__file__).parent
|
||||
entry_path = plugin_dir / self.subprocess_entry
|
||||
|
||||
if entry_path.exists():
|
||||
return entry_path
|
||||
|
||||
logger.warning(f"子进程入口脚本不存在: {entry_path}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_adapter_info(cls) -> "AdapterInfo":
|
||||
"""获取适配器的信息
|
||||
|
||||
Returns:
|
||||
AdapterInfo: 适配器组件信息
|
||||
"""
|
||||
from src.plugin_system.base.component_types import AdapterInfo
|
||||
|
||||
return AdapterInfo(
|
||||
name=getattr(cls, "adapter_name", cls.__name__.lower().replace("adapter", "")),
|
||||
version=getattr(cls, "adapter_version", "1.0.0"),
|
||||
platform=getattr(cls, "platform", "unknown"),
|
||||
description=getattr(cls, "adapter_description", ""),
|
||||
enabled=True,
|
||||
run_in_subprocess=getattr(cls, "run_in_subprocess", False),
|
||||
subprocess_entry=getattr(cls, "subprocess_entry", None),
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def from_platform_message(self, raw: Any) -> MessageEnvelope:
|
||||
"""
|
||||
将平台原始消息转换为 MessageEnvelope
|
||||
|
||||
子类必须实现此方法
|
||||
|
||||
Args:
|
||||
raw: 平台原始消息
|
||||
|
||||
Returns:
|
||||
MessageEnvelope: 统一的消息信封
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
async def _send_platform_message(self, envelope: MessageEnvelope) -> None:
|
||||
"""
|
||||
发送消息到平台
|
||||
|
||||
如果使用了 WebSocketAdapterOptions 或 HttpAdapterOptions,
|
||||
此方法会自动处理。否则子类需要重写此方法。
|
||||
|
||||
Args:
|
||||
envelope: 要发送的消息信封
|
||||
"""
|
||||
# 如果配置了自动传输,调用父类方法
|
||||
if self._transport_config:
|
||||
await super()._send_platform_message(envelope)
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
f"适配器 {self.adapter_name} 未配置自动传输,必须重写 _send_platform_message 方法"
|
||||
)
|
||||
|
||||
|
||||
__all__ = ["BaseAdapter"]
|
||||
@@ -54,6 +54,7 @@ class ComponentType(Enum):
|
||||
INTEREST_CALCULATOR = "interest_calculator" # 兴趣度计算组件
|
||||
PROMPT = "prompt" # Prompt组件
|
||||
ROUTER = "router" # 路由组件
|
||||
ADAPTER = "adapter" # 适配器组件
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
@@ -148,6 +149,20 @@ class PermissionNodeField:
|
||||
description: str # 权限描述
|
||||
|
||||
|
||||
@dataclass
|
||||
class AdapterInfo:
|
||||
"""适配器组件信息"""
|
||||
|
||||
name: str # 适配器名称
|
||||
component_type: ComponentType = field(default=ComponentType.ADAPTER, init=False)
|
||||
version: str = "1.0.0" # 适配器版本
|
||||
platform: str = "unknown" # 平台名称
|
||||
description: str = "" # 适配器描述
|
||||
enabled: bool = True # 是否启用
|
||||
run_in_subprocess: bool = False # 是否在子进程中运行
|
||||
subprocess_entry: str | None = None # 子进程入口脚本
|
||||
|
||||
|
||||
@dataclass
|
||||
class ComponentInfo:
|
||||
"""组件信息"""
|
||||
|
||||
316
src/plugin_system/core/adapter_manager.py
Normal file
316
src/plugin_system/core/adapter_manager.py
Normal file
@@ -0,0 +1,316 @@
|
||||
"""
|
||||
Adapter 管理器
|
||||
|
||||
负责管理所有注册的适配器,支持子进程自动启动和生命周期管理。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Dict, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.plugin_system.base.base_adapter import BaseAdapter
|
||||
|
||||
from src.common.logger import get_logger
|
||||
|
||||
logger = get_logger("adapter_manager")
|
||||
|
||||
|
||||
class AdapterProcess:
|
||||
"""适配器子进程包装器"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
adapter_name: str,
|
||||
entry_path: Path,
|
||||
python_executable: Optional[str] = None,
|
||||
):
|
||||
self.adapter_name = adapter_name
|
||||
self.entry_path = entry_path
|
||||
self.python_executable = python_executable or sys.executable
|
||||
self.process: Optional[subprocess.Popen] = None
|
||||
self._monitor_task: Optional[asyncio.Task] = None
|
||||
|
||||
async def start(self) -> bool:
|
||||
"""启动适配器子进程"""
|
||||
try:
|
||||
logger.info(f"启动适配器子进程: {self.adapter_name}")
|
||||
logger.debug(f"Python: {self.python_executable}")
|
||||
logger.debug(f"Entry: {self.entry_path}")
|
||||
|
||||
# 启动子进程
|
||||
self.process = subprocess.Popen(
|
||||
[self.python_executable, str(self.entry_path)],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
)
|
||||
|
||||
# 启动监控任务
|
||||
self._monitor_task = asyncio.create_task(self._monitor_process())
|
||||
|
||||
logger.info(f"适配器 {self.adapter_name} 子进程已启动 (PID: {self.process.pid})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"启动适配器 {self.adapter_name} 子进程失败: {e}", exc_info=True)
|
||||
return False
|
||||
|
||||
async def stop(self) -> None:
|
||||
"""停止适配器子进程"""
|
||||
if not self.process:
|
||||
return
|
||||
|
||||
logger.info(f"停止适配器子进程: {self.adapter_name} (PID: {self.process.pid})")
|
||||
|
||||
try:
|
||||
# 取消监控任务
|
||||
if self._monitor_task and not self._monitor_task.done():
|
||||
self._monitor_task.cancel()
|
||||
try:
|
||||
await self._monitor_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
# 终止进程
|
||||
self.process.terminate()
|
||||
|
||||
# 等待进程退出(最多等待5秒)
|
||||
try:
|
||||
await asyncio.wait_for(
|
||||
asyncio.to_thread(self.process.wait),
|
||||
timeout=5.0
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning(f"适配器 {self.adapter_name} 未能在5秒内退出,强制终止")
|
||||
self.process.kill()
|
||||
await asyncio.to_thread(self.process.wait)
|
||||
|
||||
logger.info(f"适配器 {self.adapter_name} 子进程已停止")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"停止适配器 {self.adapter_name} 子进程时出错: {e}", exc_info=True)
|
||||
finally:
|
||||
self.process = None
|
||||
|
||||
async def _monitor_process(self) -> None:
|
||||
"""监控子进程状态"""
|
||||
if not self.process:
|
||||
return
|
||||
|
||||
try:
|
||||
# 在后台线程中等待进程退出
|
||||
return_code = await asyncio.to_thread(self.process.wait)
|
||||
|
||||
if return_code != 0:
|
||||
logger.error(
|
||||
f"适配器 {self.adapter_name} 子进程异常退出 (返回码: {return_code})"
|
||||
)
|
||||
|
||||
# 读取 stderr 输出
|
||||
if self.process.stderr:
|
||||
stderr = self.process.stderr.read()
|
||||
if stderr:
|
||||
logger.error(f"错误输出:\n{stderr}")
|
||||
else:
|
||||
logger.info(f"适配器 {self.adapter_name} 子进程正常退出")
|
||||
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(f"监控适配器 {self.adapter_name} 子进程时出错: {e}", exc_info=True)
|
||||
|
||||
def is_running(self) -> bool:
|
||||
"""检查进程是否正在运行"""
|
||||
if not self.process:
|
||||
return False
|
||||
return self.process.poll() is None
|
||||
|
||||
|
||||
class AdapterManager:
|
||||
"""适配器管理器"""
|
||||
|
||||
def __init__(self):
|
||||
self._adapters: Dict[str, BaseAdapter] = {}
|
||||
self._adapter_processes: Dict[str, AdapterProcess] = {}
|
||||
self._in_process_adapters: Dict[str, BaseAdapter] = {}
|
||||
|
||||
def register_adapter(self, adapter: BaseAdapter) -> None:
|
||||
"""
|
||||
注册适配器
|
||||
|
||||
Args:
|
||||
adapter: 要注册的适配器实例
|
||||
"""
|
||||
adapter_name = adapter.adapter_name
|
||||
|
||||
if adapter_name in self._adapters:
|
||||
logger.warning(f"适配器 {adapter_name} 已经注册,将被覆盖")
|
||||
|
||||
self._adapters[adapter_name] = adapter
|
||||
logger.info(f"已注册适配器: {adapter_name} v{adapter.adapter_version}")
|
||||
|
||||
async def start_adapter(self, adapter_name: str) -> bool:
|
||||
"""
|
||||
启动指定的适配器
|
||||
|
||||
Args:
|
||||
adapter_name: 适配器名称
|
||||
|
||||
Returns:
|
||||
bool: 是否成功启动
|
||||
"""
|
||||
adapter = self._adapters.get(adapter_name)
|
||||
if not adapter:
|
||||
logger.error(f"适配器 {adapter_name} 未注册")
|
||||
return False
|
||||
|
||||
# 检查是否需要在子进程中运行
|
||||
if adapter.run_in_subprocess:
|
||||
return await self._start_adapter_subprocess(adapter)
|
||||
else:
|
||||
return await self._start_adapter_in_process(adapter)
|
||||
|
||||
async def _start_adapter_subprocess(self, adapter: BaseAdapter) -> bool:
|
||||
"""在子进程中启动适配器"""
|
||||
adapter_name = adapter.adapter_name
|
||||
|
||||
# 获取子进程入口脚本
|
||||
entry_path = adapter.get_subprocess_entry_path()
|
||||
if not entry_path:
|
||||
logger.error(
|
||||
f"适配器 {adapter_name} 配置为子进程运行,但未提供有效的入口脚本"
|
||||
)
|
||||
return False
|
||||
|
||||
# 创建并启动子进程
|
||||
adapter_process = AdapterProcess(adapter_name, entry_path)
|
||||
success = await adapter_process.start()
|
||||
|
||||
if success:
|
||||
self._adapter_processes[adapter_name] = adapter_process
|
||||
|
||||
return success
|
||||
|
||||
async def _start_adapter_in_process(self, adapter: BaseAdapter) -> bool:
|
||||
"""在主进程中启动适配器"""
|
||||
adapter_name = adapter.adapter_name
|
||||
|
||||
try:
|
||||
await adapter.start()
|
||||
self._in_process_adapters[adapter_name] = adapter
|
||||
logger.info(f"适配器 {adapter_name} 已在主进程中启动")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"在主进程中启动适配器 {adapter_name} 失败: {e}", exc_info=True)
|
||||
return False
|
||||
|
||||
async def stop_adapter(self, adapter_name: str) -> None:
|
||||
"""
|
||||
停止指定的适配器
|
||||
|
||||
Args:
|
||||
adapter_name: 适配器名称
|
||||
"""
|
||||
# 检查是否在子进程中运行
|
||||
if adapter_name in self._adapter_processes:
|
||||
adapter_process = self._adapter_processes.pop(adapter_name)
|
||||
await adapter_process.stop()
|
||||
|
||||
# 检查是否在主进程中运行
|
||||
if adapter_name in self._in_process_adapters:
|
||||
adapter = self._in_process_adapters.pop(adapter_name)
|
||||
try:
|
||||
await adapter.stop()
|
||||
logger.info(f"适配器 {adapter_name} 已从主进程中停止")
|
||||
except Exception as e:
|
||||
logger.error(f"停止适配器 {adapter_name} 时出错: {e}", exc_info=True)
|
||||
|
||||
async def start_all_adapters(self) -> None:
|
||||
"""启动所有注册的适配器"""
|
||||
logger.info(f"开始启动 {len(self._adapters)} 个适配器...")
|
||||
|
||||
for adapter_name in list(self._adapters.keys()):
|
||||
await self.start_adapter(adapter_name)
|
||||
|
||||
async def stop_all_adapters(self) -> None:
|
||||
"""停止所有适配器"""
|
||||
logger.info("停止所有适配器...")
|
||||
|
||||
# 停止所有子进程适配器
|
||||
for adapter_name in list(self._adapter_processes.keys()):
|
||||
await self.stop_adapter(adapter_name)
|
||||
|
||||
# 停止所有主进程适配器
|
||||
for adapter_name in list(self._in_process_adapters.keys()):
|
||||
await self.stop_adapter(adapter_name)
|
||||
|
||||
logger.info("所有适配器已停止")
|
||||
|
||||
def get_adapter(self, adapter_name: str) -> Optional[BaseAdapter]:
|
||||
"""
|
||||
获取适配器实例
|
||||
|
||||
Args:
|
||||
adapter_name: 适配器名称
|
||||
|
||||
Returns:
|
||||
BaseAdapter | None: 适配器实例,如果不存在则返回 None
|
||||
"""
|
||||
# 只返回在主进程中运行的适配器
|
||||
return self._in_process_adapters.get(adapter_name)
|
||||
|
||||
def list_adapters(self) -> Dict[str, Dict[str, any]]:
|
||||
"""
|
||||
列出所有适配器的状态
|
||||
|
||||
Returns:
|
||||
Dict: 适配器状态信息
|
||||
"""
|
||||
result = {}
|
||||
|
||||
for adapter_name, adapter in self._adapters.items():
|
||||
status = {
|
||||
"name": adapter_name,
|
||||
"version": adapter.adapter_version,
|
||||
"platform": adapter.platform,
|
||||
"run_in_subprocess": adapter.run_in_subprocess,
|
||||
"running": False,
|
||||
"location": "unknown",
|
||||
}
|
||||
|
||||
# 检查运行状态
|
||||
if adapter_name in self._adapter_processes:
|
||||
process = self._adapter_processes[adapter_name]
|
||||
status["running"] = process.is_running()
|
||||
status["location"] = "subprocess"
|
||||
if process.process:
|
||||
status["pid"] = process.process.pid
|
||||
|
||||
elif adapter_name in self._in_process_adapters:
|
||||
status["running"] = True
|
||||
status["location"] = "in-process"
|
||||
|
||||
result[adapter_name] = status
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# 全局单例
|
||||
_adapter_manager: Optional[AdapterManager] = None
|
||||
|
||||
|
||||
def get_adapter_manager() -> AdapterManager:
|
||||
"""获取适配器管理器单例"""
|
||||
global _adapter_manager
|
||||
if _adapter_manager is None:
|
||||
_adapter_manager = AdapterManager()
|
||||
return _adapter_manager
|
||||
|
||||
|
||||
__all__ = ["AdapterManager", "AdapterProcess", "get_adapter_manager"]
|
||||
@@ -33,6 +33,9 @@ class PluginManager:
|
||||
|
||||
self.loaded_plugins: dict[str, PluginBase] = {} # 已加载的插件类实例注册表,插件名 -> 插件类实例
|
||||
self.failed_plugins: dict[str, str] = {} # 记录加载失败的插件文件及其错误信息,插件名 -> 错误信息
|
||||
|
||||
# 核心消息接收器(由主程序设置)
|
||||
self._core_sink: Optional[Any] = None
|
||||
|
||||
# 确保插件目录存在
|
||||
self._ensure_plugin_directories()
|
||||
@@ -40,6 +43,15 @@ class PluginManager:
|
||||
|
||||
# === 插件目录管理 ===
|
||||
|
||||
def set_core_sink(self, core_sink: Any) -> None:
|
||||
"""设置核心消息接收器
|
||||
|
||||
Args:
|
||||
core_sink: 核心消息接收器实例(InProcessCoreSink)
|
||||
"""
|
||||
self._core_sink = core_sink
|
||||
logger.info("已设置核心消息接收器")
|
||||
|
||||
def add_plugin_directory(self, directory: str) -> bool:
|
||||
"""添加插件目录"""
|
||||
if os.path.exists(directory):
|
||||
@@ -151,6 +163,11 @@ class PluginManager:
|
||||
except Exception as e:
|
||||
logger.error(f"调用插件 '{plugin_name}' 的 on_plugin_loaded 钩子时出错: {e}")
|
||||
|
||||
# 检查并注册适配器组件
|
||||
task = asyncio.create_task(self._register_adapter_components(plugin_name, plugin_instance))
|
||||
_background_tasks.add(task)
|
||||
task.add_done_callback(_background_tasks.discard)
|
||||
|
||||
return True, 1
|
||||
else:
|
||||
self.failed_plugins[plugin_name] = "插件注册失败"
|
||||
@@ -165,6 +182,74 @@ class PluginManager:
|
||||
logger.debug("详细错误信息: ", exc_info=True)
|
||||
return False, 1
|
||||
|
||||
async def _register_adapter_components(self, plugin_name: str, plugin_instance: PluginBase) -> None:
|
||||
"""注册适配器组件
|
||||
|
||||
Args:
|
||||
plugin_name: 插件名称
|
||||
plugin_instance: 插件实例
|
||||
"""
|
||||
try:
|
||||
from src.plugin_system.base.component_types import AdapterInfo, ComponentType
|
||||
from src.plugin_system.core.adapter_manager import get_adapter_manager
|
||||
from src.plugin_system.core.component_registry import component_registry
|
||||
|
||||
# 获取所有 ADAPTER 类型的组件
|
||||
plugin_info = plugin_instance.plugin_info
|
||||
adapter_components = [
|
||||
comp for comp in plugin_info.components
|
||||
if comp.component_type == ComponentType.ADAPTER
|
||||
]
|
||||
|
||||
if not adapter_components:
|
||||
return
|
||||
|
||||
adapter_manager = get_adapter_manager()
|
||||
|
||||
for comp_info in adapter_components:
|
||||
# 类型检查:确保是 AdapterInfo
|
||||
if not isinstance(comp_info, AdapterInfo):
|
||||
logger.warning(f"组件 {comp_info.name} 不是 AdapterInfo 类型")
|
||||
continue
|
||||
|
||||
try:
|
||||
# 从组件注册表获取适配器类
|
||||
adapter_class = component_registry.get_component_class(
|
||||
comp_info.name,
|
||||
ComponentType.ADAPTER
|
||||
)
|
||||
|
||||
if not adapter_class:
|
||||
logger.warning(f"无法找到适配器组件类: {comp_info.name}")
|
||||
continue
|
||||
|
||||
# 创建适配器实例,传入 core_sink 和 plugin
|
||||
if self._core_sink is not None:
|
||||
adapter_instance = adapter_class(self._core_sink, plugin=plugin_instance) # type: ignore
|
||||
else:
|
||||
logger.warning(
|
||||
f"适配器 '{comp_info.name}' 未获得 core_sink,"
|
||||
"请在主程序中调用 plugin_manager.set_core_sink()"
|
||||
)
|
||||
# 尝试无参数创建(某些适配器可能不需要 core_sink)
|
||||
adapter_instance = adapter_class(plugin=plugin_instance) # type: ignore
|
||||
|
||||
# 注册到适配器管理器
|
||||
adapter_manager.register_adapter(adapter_instance) # type: ignore
|
||||
logger.info(
|
||||
f"插件 '{plugin_name}' 注册了适配器组件: {comp_info.name} "
|
||||
f"(平台: {comp_info.platform})"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"注册插件 '{plugin_name}' 的适配器组件 '{comp_info.name}' 时出错: {e}",
|
||||
exc_info=True
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理插件 '{plugin_name}' 的适配器组件时出错: {e}", exc_info=True)
|
||||
|
||||
async def remove_registered_plugin(self, plugin_name: str) -> bool:
|
||||
"""
|
||||
禁用插件模块
|
||||
|
||||
Reference in New Issue
Block a user