From f96ae56bceed2bbe750f54e60216e02fed39d057 Mon Sep 17 00:00:00 2001 From: Rock Chin <1010553892@qq.com> Date: Mon, 20 Mar 2023 12:50:25 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8F=92=E4=BB=B6=20(#286)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/plugin/host.py | 17 ++++++ pkg/qqbot/cmds/model.py | 1 + pkg/qqbot/cmds/plugin.py | 113 +++++++++++++++++++++++++++++++++++++++ pkg/qqbot/cmds/system.py | 91 ------------------------------- 4 files changed, 131 insertions(+), 91 deletions(-) create mode 100644 pkg/qqbot/cmds/plugin.py diff --git a/pkg/plugin/host.py b/pkg/plugin/host.py index a8163f16..ae3aee63 100644 --- a/pkg/plugin/host.py +++ b/pkg/plugin/host.py @@ -5,6 +5,7 @@ import importlib import os import pkgutil import sys +import shutil import traceback import pkg.utils.context as context @@ -160,6 +161,22 @@ def install_plugin(repo_url: str): main.reset_logging() +def uninstall_plugin(plugin_name: str) -> str: + """ 卸载插件 """ + if plugin_name not in __plugins__: + raise Exception("插件不存在") + + # 获取文件夹路径 + plugin_path = __plugins__[plugin_name]['path'].replace("\\", "/") + + # 剪切路径为plugins/插件名 + plugin_path = plugin_path.split("plugins/")[1].split("/")[0] + + # 删除文件夹 + shutil.rmtree("plugins/"+plugin_path) + return "plugins/"+plugin_path + + class EventContext: """ 事件上下文 """ eid = 0 diff --git a/pkg/qqbot/cmds/model.py b/pkg/qqbot/cmds/model.py index 3758022b..b8bb2743 100644 --- a/pkg/qqbot/cmds/model.py +++ b/pkg/qqbot/cmds/model.py @@ -42,3 +42,4 @@ def search(cmd: str) -> dict: import pkg.qqbot.cmds.func import pkg.qqbot.cmds.system import pkg.qqbot.cmds.session +import pkg.qqbot.cmds.plugin diff --git a/pkg/qqbot/cmds/plugin.py b/pkg/qqbot/cmds/plugin.py new file mode 100644 index 00000000..3f26de9d --- /dev/null +++ b/pkg/qqbot/cmds/plugin.py @@ -0,0 +1,113 @@ +from pkg.qqbot.cmds.model import command +import pkg.utils.context + +import os +import threading +import logging + + +def plugin_operation(cmd, params, is_admin): + reply = [] + + import pkg.plugin.host as plugin_host + import pkg.utils.updater as updater + + plugin_list = plugin_host.__plugins__ + + if len(params) == 0: + reply_str = "[bot]所有插件({}):\n".format(len(plugin_host.__plugins__)) + idx = 0 + for key in plugin_host.iter_plugins_name(): + plugin = plugin_list[key] + reply_str += "\n#{} {} {}\n{}\nv{}\n作者: {}\n"\ + .format((idx+1), plugin['name'], + "[已禁用]" if not plugin['enabled'] else "", + plugin['description'], + plugin['version'], plugin['author']) + + if updater.is_repo("/".join(plugin['path'].split('/')[:-1])): + remote_url = updater.get_remote_url("/".join(plugin['path'].split('/')[:-1])) + if remote_url != "https://github.com/RockChinQ/QChatGPT" and remote_url != "https://gitee.com/RockChin/QChatGPT": + reply_str += "源码: "+remote_url+"\n" + + idx += 1 + + reply = [reply_str] + elif params[0] == 'update': + # 更新所有插件 + if is_admin: + def closure(): + import pkg.utils.context + updated = [] + for key in plugin_list: + plugin = plugin_list[key] + if updater.is_repo("/".join(plugin['path'].split('/')[:-1])): + success = updater.pull_latest("/".join(plugin['path'].split('/')[:-1])) + if success: + updated.append(plugin['name']) + + # 检查是否有requirements.txt + pkg.utils.context.get_qqbot_manager().notify_admin("正在安装依赖...") + for key in plugin_list: + plugin = plugin_list[key] + if os.path.exists("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt"): + logging.info("{}检测到requirements.txt,安装依赖".format(plugin['name'])) + import pkg.utils.pkgmgr + pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt") + + import main + main.reset_logging() + + pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated))) + + threading.Thread(target=closure).start() + reply = ["[bot]正在更新所有插件,请勿重复发起..."] + else: + reply = ["[bot]err:权限不足"] + elif params[0] == 'del' or params[0] == 'delete': + if is_admin: + if len(params) < 2: + reply = ["[bot]err:未指定插件名"] + else: + plugin_name = params[1] + if plugin_name in plugin_list: + unin_path = plugin_host.uninstall_plugin(plugin_name) + reply = ["[bot]已删除插件: {} ({}), 请发送 !reload 重载插件".format(plugin_name, unin_path)] + else: + reply = ["[bot]err:未找到插件: {}, 请使用!plugin指令查看插件列表".format(plugin_name)] + else: + reply = ["[bot]err:权限不足,请使用管理员账号私聊发起"] + elif params[0].startswith("http"): + if is_admin: + + def closure(): + try: + plugin_host.install_plugin(params[0]) + pkg.utils.context.get_qqbot_manager().notify_admin("插件安装成功,请发送 !reload 指令重载插件") + except Exception as e: + logging.error("插件安装失败:{}".format(e)) + pkg.utils.context.get_qqbot_manager().notify_admin("插件安装失败:{}".format(e)) + + threading.Thread(target=closure, args=()).start() + reply = ["[bot]正在安装插件..."] + else: + reply = ["[bot]err:权限不足,请使用管理员账号私聊发起"] + else: + reply = ["[bot]err:未知参数: {}".format(params)] + + return reply + + +@command( + "plugin", + "插件相关操作", + "!plugin\n!plugin <插件仓库地址>", + [], + False +) +def cmd_plugin(cmd: str, params: list, session_name: str, + text_message: str, launcher_type: str, launcher_id: int, + sender_id: int, is_admin: bool) -> list: + """插件相关操作""" + reply = plugin_operation(cmd, params, is_admin) + return reply \ No newline at end of file diff --git a/pkg/qqbot/cmds/system.py b/pkg/qqbot/cmds/system.py index 9b6e4379..1d6c6717 100644 --- a/pkg/qqbot/cmds/system.py +++ b/pkg/qqbot/cmds/system.py @@ -84,97 +84,6 @@ def cmd_version(cmd: str, params: list, session_name: str, return reply -def plugin_operation(cmd, params, is_admin): - reply = [] - - import pkg.plugin.host as plugin_host - import pkg.utils.updater as updater - - plugin_list = plugin_host.__plugins__ - - if len(params) == 0: - reply_str = "[bot]所有插件({}):\n".format(len(plugin_host.__plugins__)) - idx = 0 - for key in plugin_host.iter_plugins_name(): - plugin = plugin_list[key] - reply_str += "\n#{} {} {}\n{}\nv{}\n作者: {}\n"\ - .format((idx+1), plugin['name'], - "[已禁用]" if not plugin['enabled'] else "", - plugin['description'], - plugin['version'], plugin['author']) - - if updater.is_repo("/".join(plugin['path'].split('/')[:-1])): - remote_url = updater.get_remote_url("/".join(plugin['path'].split('/')[:-1])) - if remote_url != "https://github.com/RockChinQ/QChatGPT" and remote_url != "https://gitee.com/RockChin/QChatGPT": - reply_str += "源码: "+remote_url+"\n" - - idx += 1 - - reply = [reply_str] - elif params[0] == 'update': - # 更新所有插件 - if is_admin: - def closure(): - import pkg.utils.context - updated = [] - for key in plugin_list: - plugin = plugin_list[key] - if updater.is_repo("/".join(plugin['path'].split('/')[:-1])): - success = updater.pull_latest("/".join(plugin['path'].split('/')[:-1])) - if success: - updated.append(plugin['name']) - - # 检查是否有requirements.txt - pkg.utils.context.get_qqbot_manager().notify_admin("正在安装依赖...") - for key in plugin_list: - plugin = plugin_list[key] - if os.path.exists("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt"): - logging.info("{}检测到requirements.txt,安装依赖".format(plugin['name'])) - import pkg.utils.pkgmgr - pkg.utils.pkgmgr.install_requirements("/".join(plugin['path'].split('/')[:-1])+"/requirements.txt") - - import main - main.reset_logging() - - pkg.utils.context.get_qqbot_manager().notify_admin("已更新插件: {}".format(", ".join(updated))) - - threading.Thread(target=closure).start() - reply = ["[bot]正在更新所有插件,请勿重复发起..."] - else: - reply = ["[bot]err:权限不足"] - elif params[0].startswith("http"): - if is_admin: - - def closure(): - try: - plugin_host.install_plugin(params[0]) - pkg.utils.context.get_qqbot_manager().notify_admin("插件安装成功,请发送 !reload 指令重载插件") - except Exception as e: - logging.error("插件安装失败:{}".format(e)) - pkg.utils.context.get_qqbot_manager().notify_admin("插件安装失败:{}".format(e)) - - threading.Thread(target=closure, args=()).start() - reply = ["[bot]正在安装插件..."] - else: - reply = ["[bot]err:权限不足,请使用管理员账号私聊发起"] - return reply - - -@command( - "plugin", - "插件相关操作", - "!plugin\n!plugin <插件仓库地址>", - [], - False -) -def cmd_plugin(cmd: str, params: list, session_name: str, - text_message: str, launcher_type: str, launcher_id: int, - sender_id: int, is_admin: bool) -> list: - """插件相关操作""" - reply = plugin_operation(cmd, params, is_admin) - return reply - - @command( "reload", "执行热重载",