refactor: 指令注册架构

This commit is contained in:
Rock Chin
2023-03-28 03:12:19 +00:00
parent b799de7995
commit e228225178
6 changed files with 81 additions and 24 deletions

13
main.py
View File

@@ -7,6 +7,7 @@ import time
import logging
import sys
import traceback
try:
import colorlog
@@ -191,8 +192,14 @@ def start(first_time_init=False):
import pkg.openai.session
import pkg.qqbot.manager
import pkg.openai.dprompt
import pkg.qqbot.cmds.mgr
pkg.openai.dprompt.register_all()
try:
pkg.openai.dprompt.register_all()
pkg.qqbot.cmds.mgr.register_all()
except Exception as e:
logging.error(e)
traceback.print_exc()
# 配置openai api_base
if "reverse_proxy" in config.openai_config and config.openai_config["reverse_proxy"] is not None:
@@ -271,10 +278,6 @@ def start(first_time_init=False):
threading.Thread(
target=run_bot_wrapper
).start()
# 机器人暂时不能放在线程池中
# pkg.utils.context.get_thread_ctl().submit_sys_task(
# run_bot_wrapper
# )
finally:
# 判断若是Windows输出选择模式可能会暂停程序的警告
if os.name == 'nt':

View File

View File

@@ -1,5 +1,10 @@
import importlib
import inspect
import logging
import copy
import pkgutil
import traceback
import types
__commands_tree__ = {}
@@ -109,6 +114,9 @@ class Context:
class AbstractCommand:
"""指令抽象类"""
parent: type
"""父指令类"""
name: str
"""指令名"""
@@ -179,6 +187,12 @@ class AbstractCommand:
# 更新索引
__tree_index__[cls.__module__ + '.' + cls.__name__] = path + [name]
class CommandPrivilegeError(Exception):
"""指令权限不足或不存在异常"""
pass
# 传入Context对象广搜命令树返回执行结果
# 若命令被处理返回reply列表
# 若命令未被处理,继续执行下一级指令
@@ -198,12 +212,15 @@ def execute(context: Context) -> list:
# 从树取出顶级指令
node = __commands_tree__
path = ""
# 搜当前顶层,找不到则报错
while True:
path = path + ctx.crt_command + "."
try:
# 检查权限
if ctx.privilege < node[ctx.crt_command]['privilege']:
raise ValueError('权限不足')
raise CommandPrivilegeError('权限不足: {}'.format(path[:-1]))
# 执行
execed, reply, ctx.crt_command = node[ctx.crt_command]['cls'].process(ctx)
if execed:
@@ -214,4 +231,36 @@ def execute(context: Context) -> list:
# 删除crt_params第一个参数
ctx.crt_params.pop(0)
except KeyError:
raise ValueError('找不到指令: {}'.format(ctx.command))
raise CommandPrivilegeError('找不到指令: {}'.format(path[:-1]))
def register_all():
"""启动时调用此函数注册所有指令
递归处理pkg.qqbot.cmds包下及其子包下所有模块的所有继承于AbstractCommand的类
"""
# 模块遍历其中的继承于AbstractCommand的类进行注册
# 包:递归处理包下的模块
# 排除__开头的属性
import pkg.qqbot.cmds
def walk(module, prefix, path_prefix):
# 排除不处于pkg.qqbot.cmds中的包
if not module.__name__.startswith('pkg.qqbot.cmds'):
return
for item in pkgutil.iter_modules(module.__path__):
if item.name.startswith('__'):
continue
if item.ispkg:
walk(__import__(module.__name__ + '.' + item.name, fromlist=['']), prefix + item.name + '.', path_prefix + item.name + '/')
else:
m = __import__(module.__name__ + '.' + item.name, fromlist=[''])
for name, cls in inspect.getmembers(m, inspect.isclass):
# 检查是否为指令类
if cls.__module__ == m.__name__ and issubclass(cls, AbstractCommand) and cls != AbstractCommand:
cls.register(cls, cls.name, cls.parent)
walk(pkg.qqbot.cmds, '', '')
logging.debug(__commands_tree__)

View File

View File

@@ -4,6 +4,8 @@ import pkg.openai.session
import pkg.utils.context
class ResetCommand(AbstractCommand):
parent: type = None
name = 'reset'
description = '重置当前会话'
usage = 'reset'

View File

@@ -13,7 +13,8 @@ import pkg.utils.updater
import pkg.utils.context
import pkg.qqbot.message
import pkg.utils.credit as credit
import pkg.qqbot.cmds.model as cmdmodel
# import pkg.qqbot.cmds.model as cmdmodel
import pkg.qqbot.cmds.mgr as cmdmgr
from mirai import Image
@@ -36,22 +37,24 @@ def process_command(session_name: str, text_message: str, mgr, config,
params = [cmd[1:]] + params
cmd = 'cfg'
# 选择指令处理函
cmd_obj = cmdmodel.search(cmd)
if cmd_obj is not None and (cmd_obj['admin_only'] is False or is_admin):
cmd_func = cmd_obj['func']
reply = cmd_func(
cmd=cmd,
params=params,
session_name=session_name,
text_message=text_message,
launcher_type=launcher_type,
launcher_id=launcher_id,
sender_id=sender_id,
is_admin=is_admin,
)
else:
reply = ["[bot]err:未知的指令或权限不足: " + cmd]
# 包装参
context = cmdmgr.Context(
command=cmd,
crt_command=cmd,
params=params,
crt_params=params,
session_name=session_name,
text_message=text_message,
launcher_type=launcher_type,
launcher_id=launcher_id,
sender_id=sender_id,
is_admin=is_admin,
privilege=2 if is_admin else 1, # 普通用户1管理员2
)
try:
reply = cmdmgr.execute(context)
except cmdmgr.CommandPrivilegeError as e:
reply = ["[bot]err:{}".format(e)]
return reply
except Exception as e: