perf: 安装/更新插件后直接热重载而不重启;更新 plugin 指令

This commit is contained in:
Soulter
2025-03-08 00:20:48 +08:00
parent 9492fcde74
commit a5ffb0f8dc
5 changed files with 66 additions and 43 deletions

View File

@@ -14,6 +14,8 @@ star_map: Dict[str, StarMetadata] = {}
class StarMetadata:
"""
插件的元数据。
当 activated 为 False 时star_cls 可能为 None请不要在插件未激活时调用 star_cls 的方法。
"""
name: str

View File

@@ -168,7 +168,6 @@ class PluginManager:
async def reload(self, specified_plugin_name=None):
"""扫描并加载所有的插件 当 specified_module_path 指定时,重载指定插件"""
specified_module_path = None
if specified_plugin_name:
for smd in star_registry:
@@ -208,17 +207,23 @@ class PluginManager:
await self._unbind_plugin(smd.name, specified_module_path)
await self.load(specified_module_path)
async def load(self, specified_module_path=None, specified_dir_name=None):
"""载入插件。
当 specified_module_path 或者 specified_dir_name 不为 None 时,只载入指定的插件。
"""
inactivated_plugins: list = sp.get("inactivated_plugins", [])
inactivated_llm_tools: list = sp.get("inactivated_llm_tools", [])
alter_cmd = sp.get("alter_cmd", {})
plugin_modules = self._get_plugin_modules()
if plugin_modules is None:
return False, "未找到任何插件模块"
fail_rec = ""
inactivated_plugins: list = sp.get("inactivated_plugins", [])
inactivated_llm_tools: list = sp.get("inactivated_llm_tools", [])
alter_cmd = sp.get("alter_cmd", {})
# 导入插件模块,并尝试实例化插件类
for plugin_module in plugin_modules:
try:
@@ -232,8 +237,11 @@ class PluginManager:
path = "data.plugins." if not reserved else "packages."
path += root_dir_name + "." + module_str
# 检查是否需要载入指定的插件
if specified_module_path and path != specified_module_path:
continue
if specified_dir_name and root_dir_name != specified_dir_name:
continue
logger.info(f"正在载入插件 {root_dir_name} ...")
@@ -287,18 +295,22 @@ class PluginManager:
except Exception:
pass
if plugin_config:
metadata.config = plugin_config
try:
metadata.star_cls = metadata.star_cls_type(
context=self.context, config=plugin_config
)
except TypeError as _:
metadata.star_cls = metadata.star_cls_type(
context=self.context
)
if path not in inactivated_plugins:
# 只有没有禁用插件时才实例化插件类
if plugin_config:
metadata.config = plugin_config
try:
metadata.star_cls = metadata.star_cls_type(
context=self.context, config=plugin_config
)
except TypeError as _:
metadata.star_cls = metadata.star_cls_type(
context=self.context
)
else:
metadata.star_cls = metadata.star_cls_type(context=self.context)
else:
metadata.star_cls = metadata.star_cls_type(context=self.context)
logger.info(f"插件 {metadata.name} 已被禁用。")
metadata.module = module
metadata.root_dir_name = root_dir_name
@@ -331,19 +343,23 @@ class PluginManager:
)
classes = self._get_classes(module)
if plugin_config:
try:
obj = getattr(module, classes[0])(
context=self.context, config=plugin_config
) # 实例化插件类
except TypeError as _:
if path not in inactivated_plugins:
# 只有没有禁用插件时才实例化插件类
if plugin_config:
try:
obj = getattr(module, classes[0])(
context=self.context, config=plugin_config
) # 实例化插件类
except TypeError as _:
obj = getattr(module, classes[0])(
context=self.context
) # 实例化插件类
else:
obj = getattr(module, classes[0])(
context=self.context
) # 实例化插件类
else:
obj = getattr(module, classes[0])(
context=self.context
) # 实例化插件类
logger.info(f"插件 {metadata.name} 已被禁用。")
metadata = None
metadata = self._load_plugin_metadata(
@@ -426,7 +442,8 @@ class PluginManager:
async def install_plugin(self, repo_url: str, proxy=""):
plugin_path = await self.updator.install(repo_url, proxy)
# reload the plugin
await self.reload()
dir_name = os.path.basename(plugin_path)
await self.load(specified_dir_name=dir_name)
return plugin_path
async def uninstall_plugin(self, plugin_name: str):
@@ -576,4 +593,5 @@ class PluginManager:
os.remove(zip_file_path)
except BaseException as e:
logger.warning(f"删除插件压缩包失败: {str(e)}")
await self.reload()
# await self.reload()
await self.load(desti_dir)

View File

@@ -188,7 +188,7 @@ class PluginRoute(Route):
try:
logger.info(f"正在安装插件 {repo_url}")
await self.plugin_manager.install_plugin(repo_url, proxy)
self.core_lifecycle.restart()
# self.core_lifecycle.restart()
logger.info(f"安装插件 {repo_url} 成功。")
return Response().ok(None, "安装成功。").__dict__
except Exception as e:
@@ -203,7 +203,7 @@ class PluginRoute(Route):
file_path = f"data/temp/{file.filename}"
await file.save(file_path)
await self.plugin_manager.install_plugin_from_file(file_path)
self.core_lifecycle.restart()
# self.core_lifecycle.restart()
logger.info(f"安装插件 {file.filename} 成功")
return Response().ok(None, "安装成功。").__dict__
except Exception as e:
@@ -229,7 +229,8 @@ class PluginRoute(Route):
try:
logger.info(f"正在更新插件 {plugin_name}")
await self.plugin_manager.update_plugin(plugin_name, proxy)
self.core_lifecycle.restart()
# self.core_lifecycle.restart()
await self.plugin_manager.reload(plugin_name)
logger.info(f"更新插件 {plugin_name} 成功。")
return Response().ok(None, "更新成功。").__dict__
except Exception as e:

View File

@@ -339,7 +339,7 @@ export default {
this.upload_file = "";
this.onLoadingDialogResult(1, res.data.message);
this.dialog = false;
this.$refs.wfr.check();
// this.$refs.wfr.check();
}).catch((err) => {
this.loading_ = false;
this.onLoadingDialogResult(2, err, -1);
@@ -362,7 +362,7 @@ export default {
this.extension_url = "";
this.onLoadingDialogResult(1, res.data.message);
this.dialog = false;
this.$refs.wfr.check();
// this.$refs.wfr.check();
}).catch((err) => {
this.loading_ = false;
this.toast("安装插件失败: " + err, "error");

View File

@@ -164,8 +164,11 @@ AstrBot 指令:
plugin_list_info = "已加载的插件:\n"
for plugin in self.context.get_all_stars():
plugin_list_info += (
f"- `{plugin.name}` By {plugin.author}: {plugin.desc}\n"
f"- `{plugin.name}` By {plugin.author}: {plugin.desc}"
)
if not plugin.activated:
plugin_list_info += " (未启用)"
plugin_list_info += "\n"
if plugin_list_info.strip() == "":
plugin_list_info = "没有加载任何插件。"
@@ -199,12 +202,8 @@ AstrBot 指令:
if plugin is None:
event.set_result(MessageEventResult().message("未找到此插件。"))
return
help_msg = (
plugin.star_cls.__doc__
if plugin.star_cls.__doc__
else "帮助信息: 未提供"
)
help_msg += f"\n\n作者: {plugin.author}\n版本: {plugin.version}"
help_msg = ""
help_msg += f"\n\n✨ 作者: {plugin.author}\n✨ 版本: {plugin.version}"
command_handlers = []
command_names = []
for handler in star_handlers_registry:
@@ -221,13 +220,16 @@ AstrBot 指令:
command_names.append(filter_.group_name)
if len(command_handlers) > 0:
help_msg += "\n\n指令列表:\n"
help_msg += "\n\n🔧 指令列表:\n"
for i in range(len(command_handlers)):
help_msg += f"{command_names[i]}: {command_handlers[i].desc}\n"
help_msg += f"- {command_names[i]}"
if command_handlers[i].desc:
help_msg += f": {command_handlers[i].desc}"
help_msg += "\n"
help_msg += "\nTip: 指令的触发需要添加唤醒前缀,默认为 /。"
ret = f"插件 {oper1} 帮助信息:\n" + help_msg
ret = f"🧩 插件 {oper1} 帮助信息:\n" + help_msg
ret += "更多帮助信息请查看插件仓库 README。"
event.set_result(MessageEventResult().message(ret).use_t2i(False))