fix:优化插件分身性能

feat:分身插件删除时清理文件
This commit is contained in:
jxxghp
2025-05-26 13:21:47 +08:00
parent e8ab20acf2
commit a6d1bd12a2
3 changed files with 129 additions and 85 deletions
+25 -8
View File
@@ -1,4 +1,5 @@
import mimetypes
import shutil
from typing import Annotated, Any, List, Optional
from fastapi import APIRouter, Depends, Header, HTTPException
@@ -331,10 +332,11 @@ def reset_plugin(plugin_id: str,
"""
根据插件ID重置插件配置及数据
"""
plugin_manager = PluginManager()
# 删除配置
PluginManager().delete_plugin_config(plugin_id)
plugin_manager.delete_plugin_config(plugin_id)
# 删除插件所有数据
PluginManager().delete_plugin_data(plugin_id)
plugin_manager.delete_plugin_data(plugin_id)
# 重新加载插件
reload_plugin(plugin_id)
return schemas.Response(success=True)
@@ -455,10 +457,11 @@ def set_plugin_config(plugin_id: str, conf: dict,
"""
更新插件配置
"""
plugin_manager = PluginManager()
# 保存配置
PluginManager().save_plugin_config(plugin_id, conf)
plugin_manager.save_plugin_config(plugin_id, conf)
# 重新生效插件
PluginManager().init_plugin(plugin_id, conf)
plugin_manager.init_plugin(plugin_id, conf)
# 注册插件服务
register_plugin(plugin_id)
return schemas.Response(success=True)
@@ -470,20 +473,34 @@ def uninstall_plugin(plugin_id: str,
"""
卸载插件
"""
config_oper = SystemConfigOper()
# 删除已安装信息
install_plugins = SystemConfigOper().get(SystemConfigKey.UserInstalledPlugins) or []
install_plugins = config_oper.get(SystemConfigKey.UserInstalledPlugins) or []
for plugin in install_plugins:
if plugin == plugin_id:
install_plugins.remove(plugin)
break
# 保存
SystemConfigOper().set(SystemConfigKey.UserInstalledPlugins, install_plugins)
config_oper.set(SystemConfigKey.UserInstalledPlugins, install_plugins)
# 移除插件API
remove_plugin_api(plugin_id)
# 移除插件服务
Scheduler().remove_plugin_job(plugin_id)
# 判断是否为分身
plugin_manager = PluginManager()
plugin_class = plugin_manager.plugins.get(plugin_id)
if getattr(plugin_class, "is_clone", False):
# 如果是分身插件,则删除分身数据和配置
plugin_manager.delete_plugin_config(plugin_id)
plugin_manager.delete_plugin_data(plugin_id)
# 删除分身文件
plugin_base_dir = settings.ROOT_PATH / "app" / "plugins" / plugin_id.lower()
if plugin_base_dir.exists():
try:
shutil.rmtree(plugin_base_dir)
except Exception as e:
logger.error(f"删除插件分身目录 {plugin_base_dir} 失败: {str(e)}")
# 移除插件
PluginManager().remove_plugin(plugin_id)
plugin_manager.remove_plugin(plugin_id)
return schemas.Response(success=True)
+45 -20
View File
@@ -226,13 +226,21 @@ class PluginManager(metaclass=Singleton):
logger.info("插件停止完成")
@property
def running_plugins(self):
def running_plugins(self) -> Dict[str, Any]:
"""
获取运行态插件列表
:return: 运行态插件列表
"""
return self._running_plugins
@property
def plugins(self) -> Dict[str, Any]:
"""
获取插件列表
:return: 插件列表
"""
return self._plugins
def reload_monitor(self):
"""
重新加载插件文件修改监测
@@ -1061,7 +1069,13 @@ class PluginManager(metaclass=Singleton):
# 修改插件文件内容
success, msg = self._modify_plugin_files(
clone_plugin_dir, plugin_id, clone_id, suffix, name, description, version, icon
plugin_dir=clone_plugin_dir,
original_id=plugin_id,
suffix=suffix,
name=name,
description=description,
version=version,
icon=icon
)
if not success:
@@ -1083,16 +1097,17 @@ class PluginManager(metaclass=Singleton):
# 复制原插件配置作为分身插件的初始配置
clone_config = original_config.copy()
# 可以在这里修改一些默认值,比如禁用分身插件
clone_config['enable'] = False # 默认禁用分身插件,让用户手动配置
# 默认禁用分身插件,让用户手动配置
clone_config['enable'] = False
clone_config['enabled'] = False
self.save_plugin_config(clone_id, clone_config)
logger.info(f"已为分身插件 {clone_id} 设置初始配置")
else:
logger.info(f"原插件 {plugin_id} 没有配置,分身插件 {clone_id} 将使用默认配置")
# 重新初始化插件系统以完全注册新插件
logger.info(f"正在重新注册插件系统以识别分身插件 {clone_id}...")
self.init_config()
# 注册分身插件的API和服务
logger.info(f"正在注册分身插件 {clone_id} ...")
PluginManager().reload_plugin(plugin_id)
# 确保分身插件正确初始化配置
if clone_id in self._running_plugins:
clone_instance = self._running_plugins[clone_id]
@@ -1102,11 +1117,6 @@ class PluginManager(metaclass=Singleton):
clone_instance.init_plugin(clone_config)
logger.info(f"分身插件 {clone_id} 配置重新初始化完成")
# 注册分身插件的API和服务
logger.info(f"正在注册分身插件 {clone_id} 的API和服务...")
from app.api.endpoints.plugin import register_plugin
register_plugin(clone_id)
logger.info(f"插件分身 {clone_id} 创建成功")
return True, "插件分身创建成功"
@@ -1114,14 +1124,13 @@ class PluginManager(metaclass=Singleton):
logger.error(f"创建插件分身失败:{str(e)}")
return False, f"创建插件分身失败:{str(e)}"
def _modify_plugin_files(self, plugin_dir: Path, original_id: str, clone_id: str,
suffix: str, name: str, description: str, version: str = None,
def _modify_plugin_files(self, plugin_dir: Path, original_id: str, suffix: str,
name: str, description: str, version: str = None,
icon: str = None) -> Tuple[bool, str]:
"""
修改插件文件中的类名和相关信息
:param plugin_dir: 插件目录
:param original_id: 原插件ID
:param clone_id: 分身插件ID
:param suffix: 分身后缀
:param name: 分身名称
:param description: 分身描述
@@ -1143,7 +1152,13 @@ class PluginManager(metaclass=Singleton):
init_file = plugin_dir / "__init__.py"
if init_file.exists():
success, msg = self._modify_python_file(
init_file, original_class_name, clone_class_name, name, description, version, icon
file_path=init_file,
original_class_name=original_class_name,
clone_class_name=clone_class_name,
name=name,
description=description,
version=version,
icon=icon
)
if not success:
return False, msg
@@ -1152,7 +1167,9 @@ class PluginManager(metaclass=Singleton):
dist_dir = plugin_dir / "dist"
if dist_dir.exists():
success, msg = self._modify_federation_files(
dist_dir, original_class_name, clone_class_name
dist_dir=dist_dir,
original_class_name=original_class_name,
clone_class_name=clone_class_name
)
if not success:
return False, msg
@@ -1163,7 +1180,8 @@ class PluginManager(metaclass=Singleton):
logger.error(f"修改插件文件失败:{str(e)}")
return False, f"修改插件文件失败:{str(e)}"
def _modify_python_file(self, file_path: Path, original_class_name: str,
@staticmethod
def _modify_python_file(file_path: Path, original_class_name: str,
clone_class_name: str, name: str, description: str,
version: str = None, icon: str = None) -> Tuple[bool, str]:
"""
@@ -1225,6 +1243,12 @@ class PluginManager(metaclass=Singleton):
else:
logger.info("未提供自定义图标,保持原插件图标")
# 添加分身标志
if "def init_plugin(self" in content:
init_index = content.index("def init_plugin(self")
# 在 def init_plugin(self 前添加 is_clone = True
content = content[:init_index] + "is_clone = True\n\n " + content[init_index:]
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
@@ -1303,7 +1327,8 @@ class PluginManager(metaclass=Singleton):
logger.error(f"修改联邦插件文件失败:{str(e)}")
return False, f"修改联邦插件文件失败:{str(e)}"
def _rename_federation_assets(self, dist_dir: Path, original_class_name: str, clone_class_name: str):
@staticmethod
def _rename_federation_assets(dist_dir: Path, original_class_name: str, clone_class_name: str):
"""
重命名联邦插件的资源文件,避免文件名冲突
"""
@@ -1328,5 +1353,5 @@ class PluginManager(metaclass=Singleton):
logger.debug(f"重命名联邦插件文件:{file_name} -> {new_name}")
except Exception as e:
logger.warning(f"重命名联邦插件资源文件失败:{str(e)}")
# 重命名失败不影响整体流程
logger.warning(f"重命名联邦插件资源文件失败:{str(e)}")
+2
View File
@@ -34,6 +34,8 @@ class _PluginBase(metaclass=ABCMeta):
plugin_desc: Optional[str] = ""
# 插件顺序
plugin_order: Optional[int] = 9999
# 是否为插件分身
is_clone: bool = False
def __init__(self):
# 插件数据