mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
refactor: 指令注册架构
This commit is contained in:
13
main.py
13
main.py
@@ -7,6 +7,7 @@ import time
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import colorlog
|
import colorlog
|
||||||
@@ -191,8 +192,14 @@ def start(first_time_init=False):
|
|||||||
import pkg.openai.session
|
import pkg.openai.session
|
||||||
import pkg.qqbot.manager
|
import pkg.qqbot.manager
|
||||||
import pkg.openai.dprompt
|
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
|
# 配置openai api_base
|
||||||
if "reverse_proxy" in config.openai_config and config.openai_config["reverse_proxy"] is not None:
|
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(
|
threading.Thread(
|
||||||
target=run_bot_wrapper
|
target=run_bot_wrapper
|
||||||
).start()
|
).start()
|
||||||
# 机器人暂时不能放在线程池中
|
|
||||||
# pkg.utils.context.get_thread_ctl().submit_sys_task(
|
|
||||||
# run_bot_wrapper
|
|
||||||
# )
|
|
||||||
finally:
|
finally:
|
||||||
# 判断若是Windows,输出选择模式可能会暂停程序的警告
|
# 判断若是Windows,输出选择模式可能会暂停程序的警告
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
|
|||||||
0
pkg/qqbot/cmds/__init__.py
Normal file
0
pkg/qqbot/cmds/__init__.py
Normal file
@@ -1,5 +1,10 @@
|
|||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import copy
|
import copy
|
||||||
|
import pkgutil
|
||||||
|
import traceback
|
||||||
|
import types
|
||||||
|
|
||||||
|
|
||||||
__commands_tree__ = {}
|
__commands_tree__ = {}
|
||||||
@@ -109,6 +114,9 @@ class Context:
|
|||||||
class AbstractCommand:
|
class AbstractCommand:
|
||||||
"""指令抽象类"""
|
"""指令抽象类"""
|
||||||
|
|
||||||
|
parent: type
|
||||||
|
"""父指令类"""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
"""指令名"""
|
"""指令名"""
|
||||||
|
|
||||||
@@ -179,6 +187,12 @@ class AbstractCommand:
|
|||||||
# 更新索引
|
# 更新索引
|
||||||
__tree_index__[cls.__module__ + '.' + cls.__name__] = path + [name]
|
__tree_index__[cls.__module__ + '.' + cls.__name__] = path + [name]
|
||||||
|
|
||||||
|
|
||||||
|
class CommandPrivilegeError(Exception):
|
||||||
|
"""指令权限不足或不存在异常"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# 传入Context对象,广搜命令树,返回执行结果
|
# 传入Context对象,广搜命令树,返回执行结果
|
||||||
# 若命令被处理,返回reply列表
|
# 若命令被处理,返回reply列表
|
||||||
# 若命令未被处理,继续执行下一级指令
|
# 若命令未被处理,继续执行下一级指令
|
||||||
@@ -198,12 +212,15 @@ def execute(context: Context) -> list:
|
|||||||
# 从树取出顶级指令
|
# 从树取出顶级指令
|
||||||
node = __commands_tree__
|
node = __commands_tree__
|
||||||
|
|
||||||
|
path = ""
|
||||||
|
|
||||||
# 搜当前顶层,找不到则报错
|
# 搜当前顶层,找不到则报错
|
||||||
while True:
|
while True:
|
||||||
|
path = path + ctx.crt_command + "."
|
||||||
try:
|
try:
|
||||||
# 检查权限
|
# 检查权限
|
||||||
if ctx.privilege < node[ctx.crt_command]['privilege']:
|
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)
|
execed, reply, ctx.crt_command = node[ctx.crt_command]['cls'].process(ctx)
|
||||||
if execed:
|
if execed:
|
||||||
@@ -214,4 +231,36 @@ def execute(context: Context) -> list:
|
|||||||
# 删除crt_params第一个参数
|
# 删除crt_params第一个参数
|
||||||
ctx.crt_params.pop(0)
|
ctx.crt_params.pop(0)
|
||||||
except KeyError:
|
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__)
|
||||||
|
|
||||||
|
|||||||
0
pkg/qqbot/cmds/session/__init__.py
Normal file
0
pkg/qqbot/cmds/session/__init__.py
Normal file
@@ -4,6 +4,8 @@ import pkg.openai.session
|
|||||||
import pkg.utils.context
|
import pkg.utils.context
|
||||||
|
|
||||||
class ResetCommand(AbstractCommand):
|
class ResetCommand(AbstractCommand):
|
||||||
|
parent: type = None
|
||||||
|
|
||||||
name = 'reset'
|
name = 'reset'
|
||||||
description = '重置当前会话'
|
description = '重置当前会话'
|
||||||
usage = 'reset'
|
usage = 'reset'
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import pkg.utils.updater
|
|||||||
import pkg.utils.context
|
import pkg.utils.context
|
||||||
import pkg.qqbot.message
|
import pkg.qqbot.message
|
||||||
import pkg.utils.credit as credit
|
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
|
from mirai import Image
|
||||||
|
|
||||||
@@ -36,22 +37,24 @@ def process_command(session_name: str, text_message: str, mgr, config,
|
|||||||
params = [cmd[1:]] + params
|
params = [cmd[1:]] + params
|
||||||
cmd = 'cfg'
|
cmd = 'cfg'
|
||||||
|
|
||||||
# 选择指令处理函数
|
# 包装参数
|
||||||
cmd_obj = cmdmodel.search(cmd)
|
context = cmdmgr.Context(
|
||||||
if cmd_obj is not None and (cmd_obj['admin_only'] is False or is_admin):
|
command=cmd,
|
||||||
cmd_func = cmd_obj['func']
|
crt_command=cmd,
|
||||||
reply = cmd_func(
|
params=params,
|
||||||
cmd=cmd,
|
crt_params=params,
|
||||||
params=params,
|
session_name=session_name,
|
||||||
session_name=session_name,
|
text_message=text_message,
|
||||||
text_message=text_message,
|
launcher_type=launcher_type,
|
||||||
launcher_type=launcher_type,
|
launcher_id=launcher_id,
|
||||||
launcher_id=launcher_id,
|
sender_id=sender_id,
|
||||||
sender_id=sender_id,
|
is_admin=is_admin,
|
||||||
is_admin=is_admin,
|
privilege=2 if is_admin else 1, # 普通用户1,管理员2
|
||||||
)
|
)
|
||||||
else:
|
try:
|
||||||
reply = ["[bot]err:未知的指令或权限不足: " + cmd]
|
reply = cmdmgr.execute(context)
|
||||||
|
except cmdmgr.CommandPrivilegeError as e:
|
||||||
|
reply = ["[bot]err:{}".format(e)]
|
||||||
|
|
||||||
return reply
|
return reply
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user