插件和组件管理API
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
- `config_api.py`中的`get_global_config`和`get_plugin_config`方法现在支持嵌套访问的配置键名。
|
- `config_api.py`中的`get_global_config`和`get_plugin_config`方法现在支持嵌套访问的配置键名。
|
||||||
- `database_api.py`中的`db_query`方法调整了参数顺序以增强参数限制的同时,保证了typing正确;`db_get`方法增加了`single_result`参数,与`db_query`保持一致。
|
- `database_api.py`中的`db_query`方法调整了参数顺序以增强参数限制的同时,保证了typing正确;`db_get`方法增加了`single_result`参数,与`db_query`保持一致。
|
||||||
5. 增加了`logging_api`,可以用`get_logger`来获取日志记录器。
|
5. 增加了`logging_api`,可以用`get_logger`来获取日志记录器。
|
||||||
|
6. 增加了插件和组件管理的API。
|
||||||
|
|
||||||
# 插件系统修改
|
# 插件系统修改
|
||||||
1. 现在所有的匹配模式不再是关键字了,而是枚举类。**(可能有遗漏)**
|
1. 现在所有的匹配模式不再是关键字了,而是枚举类。**(可能有遗漏)**
|
||||||
@@ -53,11 +54,13 @@
|
|||||||
- 通过`disable_specific_chat_action`,`enable_specific_chat_action`,`disable_specific_chat_command`,`enable_specific_chat_command`,`disable_specific_chat_event_handler`,`enable_specific_chat_event_handler`来操作
|
- 通过`disable_specific_chat_action`,`enable_specific_chat_action`,`disable_specific_chat_command`,`enable_specific_chat_command`,`disable_specific_chat_event_handler`,`enable_specific_chat_event_handler`来操作
|
||||||
- 同样不保存到配置文件~
|
- 同样不保存到配置文件~
|
||||||
|
|
||||||
|
# 官方插件修改
|
||||||
|
1. `HelloWorld`插件现在有一个样例的`EventHandler`。
|
||||||
|
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
把这个看起来就很别扭的config获取方式改一下
|
把这个看起来就很别扭的config获取方式改一下
|
||||||
|
|
||||||
来个API管理这些启用禁用!
|
|
||||||
|
|
||||||
|
|
||||||
# 吐槽
|
# 吐槽
|
||||||
```python
|
```python
|
||||||
|
|||||||
@@ -23,13 +23,6 @@ from .base import (
|
|||||||
EventType,
|
EventType,
|
||||||
MaiMessages,
|
MaiMessages,
|
||||||
)
|
)
|
||||||
from .core import (
|
|
||||||
plugin_manager,
|
|
||||||
component_registry,
|
|
||||||
dependency_manager,
|
|
||||||
events_manager,
|
|
||||||
global_announcement_manager,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 导入工具模块
|
# 导入工具模块
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@@ -39,12 +32,42 @@ from .utils import (
|
|||||||
# generate_plugin_manifest,
|
# generate_plugin_manifest,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .apis import register_plugin, get_logger
|
from .apis import (
|
||||||
|
chat_api,
|
||||||
|
component_manage_api,
|
||||||
|
config_api,
|
||||||
|
database_api,
|
||||||
|
emoji_api,
|
||||||
|
generator_api,
|
||||||
|
llm_api,
|
||||||
|
message_api,
|
||||||
|
person_api,
|
||||||
|
plugin_manage_api,
|
||||||
|
send_api,
|
||||||
|
utils_api,
|
||||||
|
register_plugin,
|
||||||
|
get_logger,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
__version__ = "1.0.0"
|
__version__ = "1.0.0"
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
# API 模块
|
||||||
|
"chat_api",
|
||||||
|
"component_manage_api",
|
||||||
|
"config_api",
|
||||||
|
"database_api",
|
||||||
|
"emoji_api",
|
||||||
|
"generator_api",
|
||||||
|
"llm_api",
|
||||||
|
"message_api",
|
||||||
|
"person_api",
|
||||||
|
"plugin_manage_api",
|
||||||
|
"send_api",
|
||||||
|
"utils_api",
|
||||||
|
"register_plugin",
|
||||||
|
"get_logger",
|
||||||
# 基础类
|
# 基础类
|
||||||
"BasePlugin",
|
"BasePlugin",
|
||||||
"BaseAction",
|
"BaseAction",
|
||||||
@@ -63,12 +86,6 @@ __all__ = [
|
|||||||
"EventType",
|
"EventType",
|
||||||
# 消息
|
# 消息
|
||||||
"MaiMessages",
|
"MaiMessages",
|
||||||
# 管理器
|
|
||||||
"plugin_manager",
|
|
||||||
"component_registry",
|
|
||||||
"dependency_manager",
|
|
||||||
"events_manager",
|
|
||||||
"global_announcement_manager",
|
|
||||||
# 装饰器
|
# 装饰器
|
||||||
"register_plugin",
|
"register_plugin",
|
||||||
"ConfigField",
|
"ConfigField",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
# 导入所有API模块
|
# 导入所有API模块
|
||||||
from src.plugin_system.apis import (
|
from src.plugin_system.apis import (
|
||||||
chat_api,
|
chat_api,
|
||||||
|
component_manage_api,
|
||||||
config_api,
|
config_api,
|
||||||
database_api,
|
database_api,
|
||||||
emoji_api,
|
emoji_api,
|
||||||
@@ -14,15 +15,17 @@ from src.plugin_system.apis import (
|
|||||||
llm_api,
|
llm_api,
|
||||||
message_api,
|
message_api,
|
||||||
person_api,
|
person_api,
|
||||||
|
plugin_manage_api,
|
||||||
send_api,
|
send_api,
|
||||||
utils_api,
|
utils_api,
|
||||||
plugin_register_api,
|
|
||||||
)
|
)
|
||||||
from .logging_api import get_logger
|
from .logging_api import get_logger
|
||||||
from .plugin_register_api import register_plugin
|
from .plugin_register_api import register_plugin
|
||||||
|
|
||||||
# 导出所有API模块,使它们可以通过 apis.xxx 方式访问
|
# 导出所有API模块,使它们可以通过 apis.xxx 方式访问
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"chat_api",
|
"chat_api",
|
||||||
|
"component_manage_api",
|
||||||
"config_api",
|
"config_api",
|
||||||
"database_api",
|
"database_api",
|
||||||
"emoji_api",
|
"emoji_api",
|
||||||
@@ -30,9 +33,9 @@ __all__ = [
|
|||||||
"llm_api",
|
"llm_api",
|
||||||
"message_api",
|
"message_api",
|
||||||
"person_api",
|
"person_api",
|
||||||
|
"plugin_manage_api",
|
||||||
"send_api",
|
"send_api",
|
||||||
"utils_api",
|
"utils_api",
|
||||||
"plugin_register_api",
|
|
||||||
"get_logger",
|
"get_logger",
|
||||||
"register_plugin",
|
"register_plugin",
|
||||||
]
|
]
|
||||||
|
|||||||
222
src/plugin_system/apis/component_manage_api.py
Normal file
222
src/plugin_system/apis/component_manage_api.py
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
from typing import Optional, Union, Dict
|
||||||
|
from src.plugin_system.base.component_types import (
|
||||||
|
CommandInfo,
|
||||||
|
ActionInfo,
|
||||||
|
EventHandlerInfo,
|
||||||
|
PluginInfo,
|
||||||
|
ComponentType,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# === 插件信息查询 ===
|
||||||
|
def get_all_plugin_info() -> Dict[str, PluginInfo]:
|
||||||
|
"""
|
||||||
|
获取所有插件的信息。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 包含所有插件信息的字典,键为插件名称,值为 PluginInfo 对象。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_all_plugins()
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_info(plugin_name: str) -> Optional[PluginInfo]:
|
||||||
|
"""
|
||||||
|
获取指定插件的信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_name (str): 插件名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PluginInfo: 插件信息对象,如果插件不存在则返回 None。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_plugin_info(plugin_name)
|
||||||
|
|
||||||
|
|
||||||
|
# === 组件查询方法 ===
|
||||||
|
def get_component_info(
|
||||||
|
component_name: str, component_type: ComponentType
|
||||||
|
) -> Optional[Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||||
|
"""
|
||||||
|
获取指定组件的信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_name (str): 组件名称。
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
Returns:
|
||||||
|
Union[CommandInfo, ActionInfo, EventHandlerInfo]: 组件信息对象,如果组件不存在则返回 None。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_component_info(component_name, component_type) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def get_components_info_by_type(
|
||||||
|
component_type: ComponentType,
|
||||||
|
) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||||
|
"""
|
||||||
|
获取指定类型的所有组件信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 包含指定类型组件信息的字典,键为组件名称,值为对应的组件信息对象。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_components_by_type(component_type) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def get_enabled_components_info_by_type(
|
||||||
|
component_type: ComponentType,
|
||||||
|
) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||||
|
"""
|
||||||
|
获取指定类型的所有启用的组件信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 包含指定类型启用组件信息的字典,键为组件名称,值为对应的组件信息对象。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_enabled_components_by_type(component_type) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# === Action 查询方法 ===
|
||||||
|
def get_registered_action_info(action_name: str) -> Optional[ActionInfo]:
|
||||||
|
"""
|
||||||
|
获取指定 Action 的注册信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
action_name (str): Action 名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ActionInfo: Action 信息对象,如果 Action 不存在则返回 None。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_registered_action_info(action_name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_registered_command_info(command_name: str) -> Optional[CommandInfo]:
|
||||||
|
"""
|
||||||
|
获取指定 Command 的注册信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
command_name (str): Command 名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
CommandInfo: Command 信息对象,如果 Command 不存在则返回 None。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_registered_command_info(command_name)
|
||||||
|
|
||||||
|
|
||||||
|
# === EventHandler 特定查询方法 ===
|
||||||
|
def get_registered_event_handler_info(
|
||||||
|
event_handler_name: str,
|
||||||
|
) -> Optional[EventHandlerInfo]:
|
||||||
|
"""
|
||||||
|
获取指定 EventHandler 的注册信息。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
event_handler_name (str): EventHandler 名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
EventHandlerInfo: EventHandler 信息对象,如果 EventHandler 不存在则返回 None。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.get_registered_event_handler_info(event_handler_name)
|
||||||
|
|
||||||
|
|
||||||
|
# === 组件管理方法 ===
|
||||||
|
def globally_enable_component(component_name: str, component_type: ComponentType) -> bool:
|
||||||
|
"""
|
||||||
|
全局启用指定组件。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_name (str): 组件名称。
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 启用成功返回 True,否则返回 False。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return component_registry.enable_component(component_name, component_type)
|
||||||
|
|
||||||
|
|
||||||
|
async def globally_disable_component(component_name: str, component_type: ComponentType) -> bool:
|
||||||
|
"""
|
||||||
|
全局禁用指定组件。
|
||||||
|
|
||||||
|
**此函数是异步的,确保在异步环境中调用。**
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_name (str): 组件名称。
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 禁用成功返回 True,否则返回 False。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.component_registry import component_registry
|
||||||
|
|
||||||
|
return await component_registry.disable_component(component_name, component_type)
|
||||||
|
|
||||||
|
|
||||||
|
def locally_enable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
|
||||||
|
"""
|
||||||
|
局部启用指定组件。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_name (str): 组件名称。
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
stream_id (str): 消息流 ID。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 启用成功返回 True,否则返回 False。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.global_announcement_manager import global_announcement_manager
|
||||||
|
|
||||||
|
match component_type:
|
||||||
|
case ComponentType.ACTION:
|
||||||
|
return global_announcement_manager.enable_specific_chat_action(stream_id, component_name)
|
||||||
|
case ComponentType.COMMAND:
|
||||||
|
return global_announcement_manager.enable_specific_chat_command(stream_id, component_name)
|
||||||
|
case ComponentType.EVENT_HANDLER:
|
||||||
|
return global_announcement_manager.enable_specific_chat_event_handler(stream_id, component_name)
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"未知 component type: {component_type}")
|
||||||
|
|
||||||
|
|
||||||
|
def locally_disable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
|
||||||
|
"""
|
||||||
|
局部禁用指定组件。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component_name (str): 组件名称。
|
||||||
|
component_type (ComponentType): 组件类型。
|
||||||
|
stream_id (str): 消息流 ID。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 禁用成功返回 True,否则返回 False。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.global_announcement_manager import global_announcement_manager
|
||||||
|
|
||||||
|
match component_type:
|
||||||
|
case ComponentType.ACTION:
|
||||||
|
return global_announcement_manager.disable_specific_chat_action(stream_id, component_name)
|
||||||
|
case ComponentType.COMMAND:
|
||||||
|
return global_announcement_manager.disable_specific_chat_command(stream_id, component_name)
|
||||||
|
case ComponentType.EVENT_HANDLER:
|
||||||
|
return global_announcement_manager.disable_specific_chat_event_handler(stream_id, component_name)
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"未知 component type: {component_type}")
|
||||||
95
src/plugin_system/apis/plugin_manage_api.py
Normal file
95
src/plugin_system/apis/plugin_manage_api.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
from typing import Tuple, List
|
||||||
|
def list_loaded_plugins() -> List[str]:
|
||||||
|
"""
|
||||||
|
列出所有当前加载的插件。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 当前加载的插件名称列表。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return plugin_manager.list_loaded_plugins()
|
||||||
|
|
||||||
|
|
||||||
|
def list_registered_plugins() -> List[str]:
|
||||||
|
"""
|
||||||
|
列出所有已注册的插件。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 已注册的插件名称列表。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return plugin_manager.list_registered_plugins()
|
||||||
|
|
||||||
|
|
||||||
|
async def remove_plugin(plugin_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
卸载指定的插件。
|
||||||
|
|
||||||
|
**此函数是异步的,确保在异步环境中调用。**
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_name (str): 要卸载的插件名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 卸载是否成功。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return await plugin_manager.remove_registered_plugin(plugin_name)
|
||||||
|
|
||||||
|
|
||||||
|
async def reload_plugin(plugin_name: str) -> bool:
|
||||||
|
"""
|
||||||
|
重新加载指定的插件。
|
||||||
|
|
||||||
|
**此函数是异步的,确保在异步环境中调用。**
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_name (str): 要重新加载的插件名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 重新加载是否成功。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return await plugin_manager.reload_registered_plugin(plugin_name)
|
||||||
|
|
||||||
|
|
||||||
|
def load_plugin(plugin_name: str) -> Tuple[bool, int]:
|
||||||
|
"""
|
||||||
|
加载指定的插件。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_name (str): 要加载的插件名称。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[bool, int]: 加载是否成功,成功或失败个数。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return plugin_manager.load_registered_plugin_classes(plugin_name)
|
||||||
|
|
||||||
|
def add_plugin_directory(plugin_directory: str) -> bool:
|
||||||
|
"""
|
||||||
|
添加插件目录。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_directory (str): 要添加的插件目录路径。
|
||||||
|
Returns:
|
||||||
|
bool: 添加是否成功。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return plugin_manager.add_plugin_directory(plugin_directory)
|
||||||
|
|
||||||
|
def rescan_plugin_directory() -> Tuple[int, int]:
|
||||||
|
"""
|
||||||
|
重新扫描插件目录,加载新插件。
|
||||||
|
Returns:
|
||||||
|
Tuple[int, int]: 成功加载的插件数量和失败的插件数量。
|
||||||
|
"""
|
||||||
|
from src.plugin_system.core.plugin_manager import plugin_manager
|
||||||
|
|
||||||
|
return plugin_manager.rescan_plugin_directory()
|
||||||
@@ -442,7 +442,7 @@ class ComponentRegistry:
|
|||||||
command_info,
|
command_info,
|
||||||
)
|
)
|
||||||
|
|
||||||
# === 事件处理器特定查询方法 ===
|
# === EventHandler 特定查询方法 ===
|
||||||
|
|
||||||
def get_event_handler_registry(self) -> Dict[str, Type[BaseEventHandler]]:
|
def get_event_handler_registry(self) -> Dict[str, Type[BaseEventHandler]]:
|
||||||
"""获取事件处理器注册表"""
|
"""获取事件处理器注册表"""
|
||||||
@@ -467,9 +467,9 @@ class ComponentRegistry:
|
|||||||
"""获取所有插件"""
|
"""获取所有插件"""
|
||||||
return self._plugins.copy()
|
return self._plugins.copy()
|
||||||
|
|
||||||
def get_enabled_plugins(self) -> Dict[str, PluginInfo]:
|
# def get_enabled_plugins(self) -> Dict[str, PluginInfo]:
|
||||||
"""获取所有启用的插件"""
|
# """获取所有启用的插件"""
|
||||||
return {name: info for name, info in self._plugins.items() if info.enabled}
|
# return {name: info for name, info in self._plugins.items() if info.enabled}
|
||||||
|
|
||||||
def get_plugin_components(self, plugin_name: str) -> List[ComponentInfo]:
|
def get_plugin_components(self, plugin_name: str) -> List[ComponentInfo]:
|
||||||
"""获取插件的所有组件"""
|
"""获取插件的所有组件"""
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class GlobalAnnouncementManager:
|
|||||||
self._user_disabled_actions[chat_id].remove(action_name)
|
self._user_disabled_actions[chat_id].remove(action_name)
|
||||||
return True
|
return True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
logger.warning(f"动作 {action_name} 不在禁用列表中")
|
||||||
return False
|
return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ class GlobalAnnouncementManager:
|
|||||||
self._user_disabled_commands[chat_id].remove(command_name)
|
self._user_disabled_commands[chat_id].remove(command_name)
|
||||||
return True
|
return True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
logger.warning(f"命令 {command_name} 不在禁用列表中")
|
||||||
return False
|
return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ class GlobalAnnouncementManager:
|
|||||||
self._user_disabled_event_handlers[chat_id].remove(handler_name)
|
self._user_disabled_event_handlers[chat_id].remove(handler_name)
|
||||||
return True
|
return True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
logger.warning(f"事件处理器 {handler_name} 不在禁用列表中")
|
||||||
return False
|
return False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from src.common.logger import get_logger
|
from src.common.logger import get_logger
|
||||||
from src.plugin_system.base.plugin_base import PluginBase
|
from src.plugin_system.base.plugin_base import PluginBase
|
||||||
from src.plugin_system.base.component_types import ComponentType, PluginInfo, PythonDependency
|
from src.plugin_system.base.component_types import ComponentType, PythonDependency
|
||||||
from src.plugin_system.utils.manifest_utils import VersionComparator
|
from src.plugin_system.utils.manifest_utils import VersionComparator
|
||||||
from .component_registry import component_registry
|
from .component_registry import component_registry
|
||||||
from .dependency_manager import dependency_manager
|
from .dependency_manager import dependency_manager
|
||||||
@@ -75,7 +75,7 @@ class PluginManager:
|
|||||||
total_failed_registration = 0
|
total_failed_registration = 0
|
||||||
|
|
||||||
for plugin_name in self.plugin_classes.keys():
|
for plugin_name in self.plugin_classes.keys():
|
||||||
load_status, count = self._load_registered_plugin_classes(plugin_name)
|
load_status, count = self.load_registered_plugin_classes(plugin_name)
|
||||||
if load_status:
|
if load_status:
|
||||||
total_registered += 1
|
total_registered += 1
|
||||||
else:
|
else:
|
||||||
@@ -85,7 +85,73 @@ class PluginManager:
|
|||||||
|
|
||||||
return total_registered, total_failed_registration
|
return total_registered, total_failed_registration
|
||||||
|
|
||||||
async def remove_registered_plugin(self, plugin_name: str) -> None:
|
def load_registered_plugin_classes(self, plugin_name: str) -> Tuple[bool, int]:
|
||||||
|
# sourcery skip: extract-duplicate-method, extract-method
|
||||||
|
"""
|
||||||
|
加载已经注册的插件类
|
||||||
|
"""
|
||||||
|
plugin_class = self.plugin_classes.get(plugin_name)
|
||||||
|
if not plugin_class:
|
||||||
|
logger.error(f"插件 {plugin_name} 的插件类未注册或不存在")
|
||||||
|
return False, 1
|
||||||
|
try:
|
||||||
|
# 使用记录的插件目录路径
|
||||||
|
plugin_dir = self.plugin_paths.get(plugin_name)
|
||||||
|
|
||||||
|
# 如果没有记录,直接返回失败
|
||||||
|
if not plugin_dir:
|
||||||
|
return False, 1
|
||||||
|
|
||||||
|
plugin_instance = plugin_class(plugin_dir=plugin_dir) # 实例化插件(可能因为缺少manifest而失败)
|
||||||
|
if not plugin_instance:
|
||||||
|
logger.error(f"插件 {plugin_name} 实例化失败")
|
||||||
|
return False, 1
|
||||||
|
# 检查插件是否启用
|
||||||
|
if not plugin_instance.enable_plugin:
|
||||||
|
logger.info(f"插件 {plugin_name} 已禁用,跳过加载")
|
||||||
|
return False, 0
|
||||||
|
|
||||||
|
# 检查版本兼容性
|
||||||
|
is_compatible, compatibility_error = self._check_plugin_version_compatibility(
|
||||||
|
plugin_name, plugin_instance.manifest_data
|
||||||
|
)
|
||||||
|
if not is_compatible:
|
||||||
|
self.failed_plugins[plugin_name] = compatibility_error
|
||||||
|
logger.error(f"❌ 插件加载失败: {plugin_name} - {compatibility_error}")
|
||||||
|
return False, 1
|
||||||
|
if plugin_instance.register_plugin():
|
||||||
|
self.loaded_plugins[plugin_name] = plugin_instance
|
||||||
|
self._show_plugin_components(plugin_name)
|
||||||
|
return True, 1
|
||||||
|
else:
|
||||||
|
self.failed_plugins[plugin_name] = "插件注册失败"
|
||||||
|
logger.error(f"❌ 插件注册失败: {plugin_name}")
|
||||||
|
return False, 1
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
# manifest文件缺失
|
||||||
|
error_msg = f"缺少manifest文件: {str(e)}"
|
||||||
|
self.failed_plugins[plugin_name] = error_msg
|
||||||
|
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||||
|
return False, 1
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
# manifest文件格式错误或验证失败
|
||||||
|
traceback.print_exc()
|
||||||
|
error_msg = f"manifest验证失败: {str(e)}"
|
||||||
|
self.failed_plugins[plugin_name] = error_msg
|
||||||
|
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||||
|
return False, 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 其他错误
|
||||||
|
error_msg = f"未知错误: {str(e)}"
|
||||||
|
self.failed_plugins[plugin_name] = error_msg
|
||||||
|
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
||||||
|
logger.debug("详细错误信息: ", exc_info=True)
|
||||||
|
return False, 1
|
||||||
|
|
||||||
|
async def remove_registered_plugin(self, plugin_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
禁用插件模块
|
禁用插件模块
|
||||||
"""
|
"""
|
||||||
@@ -93,38 +159,40 @@ class PluginManager:
|
|||||||
raise ValueError("插件名称不能为空")
|
raise ValueError("插件名称不能为空")
|
||||||
if plugin_name not in self.loaded_plugins:
|
if plugin_name not in self.loaded_plugins:
|
||||||
logger.warning(f"插件 {plugin_name} 未加载")
|
logger.warning(f"插件 {plugin_name} 未加载")
|
||||||
return
|
return False
|
||||||
plugin_instance = self.loaded_plugins[plugin_name]
|
plugin_instance = self.loaded_plugins[plugin_name]
|
||||||
plugin_info = plugin_instance.plugin_info
|
plugin_info = plugin_instance.plugin_info
|
||||||
for component in plugin_info.components:
|
for component in plugin_info.components:
|
||||||
await component_registry.remove_component(component.name, component.component_type)
|
await component_registry.remove_component(component.name, component.component_type)
|
||||||
del self.loaded_plugins[plugin_name]
|
del self.loaded_plugins[plugin_name]
|
||||||
|
return True
|
||||||
|
|
||||||
async def reload_registered_plugin_module(self, plugin_name: str) -> None:
|
async def reload_registered_plugin(self, plugin_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
重载插件模块
|
重载插件模块
|
||||||
"""
|
"""
|
||||||
await self.remove_registered_plugin(plugin_name)
|
if not await self.remove_registered_plugin(plugin_name):
|
||||||
self._load_registered_plugin_classes(plugin_name)
|
return False
|
||||||
|
if not self.load_registered_plugin_classes(plugin_name)[0]:
|
||||||
|
return False
|
||||||
|
logger.debug(f"插件 {plugin_name} 重载成功")
|
||||||
|
return True
|
||||||
|
|
||||||
def rescan_plugin_directory(self) -> None:
|
def rescan_plugin_directory(self) -> Tuple[int, int]:
|
||||||
"""
|
"""
|
||||||
重新扫描插件根目录
|
重新扫描插件根目录
|
||||||
"""
|
"""
|
||||||
|
total_success = 0
|
||||||
|
total_fail = 0
|
||||||
for directory in self.plugin_directories:
|
for directory in self.plugin_directories:
|
||||||
if os.path.exists(directory):
|
if os.path.exists(directory):
|
||||||
logger.debug(f"重新扫描插件根目录: {directory}")
|
logger.debug(f"重新扫描插件根目录: {directory}")
|
||||||
self._load_plugin_modules_from_directory(directory)
|
success, fail = self._load_plugin_modules_from_directory(directory)
|
||||||
|
total_success += success
|
||||||
|
total_fail += fail
|
||||||
else:
|
else:
|
||||||
logger.warning(f"插件根目录不存在: {directory}")
|
logger.warning(f"插件根目录不存在: {directory}")
|
||||||
|
return total_success, total_fail
|
||||||
def get_loaded_plugins(self) -> List[PluginInfo]:
|
|
||||||
"""获取所有已加载的插件信息"""
|
|
||||||
return list(component_registry.get_all_plugins().values())
|
|
||||||
|
|
||||||
def get_enabled_plugins(self) -> List[PluginInfo]:
|
|
||||||
"""获取所有启用的插件信息"""
|
|
||||||
return list(component_registry.get_enabled_plugins().values())
|
|
||||||
|
|
||||||
def get_plugin_instance(self, plugin_name: str) -> Optional["PluginBase"]:
|
def get_plugin_instance(self, plugin_name: str) -> Optional["PluginBase"]:
|
||||||
"""获取插件实例
|
"""获取插件实例
|
||||||
@@ -235,6 +303,25 @@ class PluginManager:
|
|||||||
|
|
||||||
return dependency_manager.generate_requirements_file(all_dependencies, output_path)
|
return dependency_manager.generate_requirements_file(all_dependencies, output_path)
|
||||||
|
|
||||||
|
# === 查询方法 ===
|
||||||
|
def list_loaded_plugins(self) -> List[str]:
|
||||||
|
"""
|
||||||
|
列出所有当前加载的插件。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 当前加载的插件名称列表。
|
||||||
|
"""
|
||||||
|
return list(self.loaded_plugins.keys())
|
||||||
|
|
||||||
|
def list_registered_plugins(self) -> List[str]:
|
||||||
|
"""
|
||||||
|
列出所有已注册的插件类。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: 已注册的插件类名称列表。
|
||||||
|
"""
|
||||||
|
return list(self.plugin_classes.keys())
|
||||||
|
|
||||||
# === 私有方法 ===
|
# === 私有方法 ===
|
||||||
# == 目录管理 ==
|
# == 目录管理 ==
|
||||||
def _ensure_plugin_directories(self) -> None:
|
def _ensure_plugin_directories(self) -> None:
|
||||||
@@ -310,72 +397,6 @@ class PluginManager:
|
|||||||
self.failed_plugins[module_name] = error_msg
|
self.failed_plugins[module_name] = error_msg
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _load_registered_plugin_classes(self, plugin_name: str) -> Tuple[bool, int]:
|
|
||||||
# sourcery skip: extract-duplicate-method, extract-method
|
|
||||||
"""
|
|
||||||
加载已经注册的插件类
|
|
||||||
"""
|
|
||||||
plugin_class = self.plugin_classes.get(plugin_name)
|
|
||||||
if not plugin_class:
|
|
||||||
logger.error(f"插件 {plugin_name} 的插件类未注册或不存在")
|
|
||||||
return False, 1
|
|
||||||
try:
|
|
||||||
# 使用记录的插件目录路径
|
|
||||||
plugin_dir = self.plugin_paths.get(plugin_name)
|
|
||||||
|
|
||||||
# 如果没有记录,直接返回失败
|
|
||||||
if not plugin_dir:
|
|
||||||
return False, 1
|
|
||||||
|
|
||||||
plugin_instance = plugin_class(plugin_dir=plugin_dir) # 实例化插件(可能因为缺少manifest而失败)
|
|
||||||
if not plugin_instance:
|
|
||||||
logger.error(f"插件 {plugin_name} 实例化失败")
|
|
||||||
return False, 1
|
|
||||||
# 检查插件是否启用
|
|
||||||
if not plugin_instance.enable_plugin:
|
|
||||||
logger.info(f"插件 {plugin_name} 已禁用,跳过加载")
|
|
||||||
return False, 0
|
|
||||||
|
|
||||||
# 检查版本兼容性
|
|
||||||
is_compatible, compatibility_error = self._check_plugin_version_compatibility(
|
|
||||||
plugin_name, plugin_instance.manifest_data
|
|
||||||
)
|
|
||||||
if not is_compatible:
|
|
||||||
self.failed_plugins[plugin_name] = compatibility_error
|
|
||||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {compatibility_error}")
|
|
||||||
return False, 1
|
|
||||||
if plugin_instance.register_plugin():
|
|
||||||
self.loaded_plugins[plugin_name] = plugin_instance
|
|
||||||
self._show_plugin_components(plugin_name)
|
|
||||||
return True, 1
|
|
||||||
else:
|
|
||||||
self.failed_plugins[plugin_name] = "插件注册失败"
|
|
||||||
logger.error(f"❌ 插件注册失败: {plugin_name}")
|
|
||||||
return False, 1
|
|
||||||
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
# manifest文件缺失
|
|
||||||
error_msg = f"缺少manifest文件: {str(e)}"
|
|
||||||
self.failed_plugins[plugin_name] = error_msg
|
|
||||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
|
||||||
return False, 1
|
|
||||||
|
|
||||||
except ValueError as e:
|
|
||||||
# manifest文件格式错误或验证失败
|
|
||||||
traceback.print_exc()
|
|
||||||
error_msg = f"manifest验证失败: {str(e)}"
|
|
||||||
self.failed_plugins[plugin_name] = error_msg
|
|
||||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
|
||||||
return False, 1
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
# 其他错误
|
|
||||||
error_msg = f"未知错误: {str(e)}"
|
|
||||||
self.failed_plugins[plugin_name] = error_msg
|
|
||||||
logger.error(f"❌ 插件加载失败: {plugin_name} - {error_msg}")
|
|
||||||
logger.debug("详细错误信息: ", exc_info=True)
|
|
||||||
return False, 1
|
|
||||||
|
|
||||||
# == 兼容性检查 ==
|
# == 兼容性检查 ==
|
||||||
|
|
||||||
def _check_plugin_version_compatibility(self, plugin_name: str, manifest_data: Dict[str, Any]) -> Tuple[bool, str]:
|
def _check_plugin_version_compatibility(self, plugin_name: str, manifest_data: Dict[str, Any]) -> Tuple[bool, str]:
|
||||||
|
|||||||
Reference in New Issue
Block a user