From 91746448a35c28201fa848467a59bcd54d232a17 Mon Sep 17 00:00:00 2001 From: Rock Chin <1010553892@qq.com> Date: Fri, 21 Apr 2023 16:36:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B6=88=E6=81=AF=E6=BA=90=E9=80=82?= =?UTF-8?q?=E9=85=8D=E5=99=A8=E6=A8=A1=E5=9E=8B=E5=8F=8AYiriMirai=E7=9A=84?= =?UTF-8?q?=E9=80=82=E9=85=8D=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/qqbot/adapter.py | 75 +++++++++++++++ pkg/qqbot/models/im.py | 49 ---------- pkg/qqbot/{models => sources}/__init__.py | 0 pkg/qqbot/sources/yirimirai.py | 106 ++++++++++++++++++++++ 4 files changed, 181 insertions(+), 49 deletions(-) create mode 100644 pkg/qqbot/adapter.py delete mode 100644 pkg/qqbot/models/im.py rename pkg/qqbot/{models => sources}/__init__.py (100%) create mode 100644 pkg/qqbot/sources/yirimirai.py diff --git a/pkg/qqbot/adapter.py b/pkg/qqbot/adapter.py new file mode 100644 index 00000000..23407564 --- /dev/null +++ b/pkg/qqbot/adapter.py @@ -0,0 +1,75 @@ +# MessageSource的适配器 +import typing + +import mirai + +class MessageSourceAdapter: + def __init__(self, config: dict): + pass + + def send_message( + self, + target_type: str, + target_id: str, + message: mirai.MessageChain + ): + """发送消息 + + Args: + target_type (str): 目标类型,`person`或`group` + target_id (str): 目标ID + message (mirai.MessageChain): YiriMirai库的消息链 + """ + raise NotImplementedError + + def reply_message( + self, + message_source: mirai.MessageEvent, + message: mirai.MessageChain + ): + """回复消息 + + Args: + message_source (mirai.MessageEvent): YiriMirai消息源事件 + message (mirai.MessageChain): YiriMirai库的消息链 + """ + raise NotImplementedError + + def register_listener( + self, + event_type: typing.Type[mirai.Event], + callback: typing.Callable[[mirai.Event], None] + ): + """注册事件监听器 + + Args: + event_type (typing.Type[mirai.Event]): YiriMirai事件类型 + callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件 + """ + raise NotImplementedError + + def unregister_listener( + self, + event_type: typing.Type[mirai.Event], + callback: typing.Callable[[mirai.Event], None] + ): + """注销事件监听器 + + Args: + event_type (typing.Type[mirai.Event]): YiriMirai事件类型 + callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件 + """ + raise NotImplementedError + + def run_sync(self): + """以阻塞的方式运行适配器""" + raise NotImplementedError + + def kill(self) -> bool: + """关闭适配器 + + Returns: + bool: 是否成功关闭,热重载时若此函数返回False则不会重载MessageSource底层 + """ + raise NotImplementedError + \ No newline at end of file diff --git a/pkg/qqbot/models/im.py b/pkg/qqbot/models/im.py deleted file mode 100644 index 6ec9293e..00000000 --- a/pkg/qqbot/models/im.py +++ /dev/null @@ -1,49 +0,0 @@ -# IM 框架调用的抽象层 -from mirai import MessageChain, Event - - -class AbstractIM: - """IM框架抽象模型""" - def __init__(self): - raise NotImplementedError - - def run(self): - """启动IM框架接口, 阻塞方法""" - raise NotImplementedError - - def __send_private_msg__(self, user, msg: MessageChain): - """发送私聊消息""" - raise NotImplementedError - - def send_private_msg(self, user, msg: MessageChain): - """发送私聊消息, 供上层调用, 解决兼容性问题后再调用__send_private_msg__, 请勿重写此方法""" - return self.__send_private_msg__(user, self.message_chain_convertor(msg)) - - def __send_group_msg__(self, group, msg: MessageChain): - """发送群消息""" - raise NotImplementedError - - def send_group_msg(self, group, msg: MessageChain): - """发送群消息, 供上层调用, 解决兼容性问题后再调用__send_group_msg__, 请勿重写此方法""" - return self.__send_group_msg__(group, self.message_chain_convertor(msg)) - - def __register_handler__(self, event, handler): - """注册事件处理器""" - raise NotImplementedError - - def register_handler(self, event: Event, handler): - """注册事件处理器, 供上层调用, 解决兼容性问题后再调用__register_handler__, 请勿重写此方法""" - return self.register_handler(self.event_convertor(event), handler) - - def event_convertor(self, event: Event): - """事件转换器""" - raise NotImplementedError - - def message_chain_convertor(self, msg: MessageChain): - """消息链转换器""" - raise NotImplementedError - - def get_bot_instance(self): - """获取IM框架机器人实例""" - raise NotImplementedError - diff --git a/pkg/qqbot/models/__init__.py b/pkg/qqbot/sources/__init__.py similarity index 100% rename from pkg/qqbot/models/__init__.py rename to pkg/qqbot/sources/__init__.py diff --git a/pkg/qqbot/sources/yirimirai.py b/pkg/qqbot/sources/yirimirai.py new file mode 100644 index 00000000..dcc3b8d4 --- /dev/null +++ b/pkg/qqbot/sources/yirimirai.py @@ -0,0 +1,106 @@ +from ..adapter import MessageSourceAdapter +import mirai +import mirai.models.bus + +import asyncio +import typing + +class YiriMiraiAdapter(MessageSourceAdapter): + """YiriMirai适配器""" + bot: mirai.Mirai + + def __init__(self, config: dict): + """初始化YiriMirai的对象""" + if 'adapter' not in config or \ + config['adapter'] == 'WebSocketAdapter': + self.bot = mirai.Mirai( + qq=config['qq'], + adapter=mirai.WebSocketAdapter( + host=config['host'], + port=config['port'], + verify_key=config['verifyKey'] + ) + ) + elif config['adapter'] == 'HTTPAdapter': + self.bot = mirai.Mirai( + qq=config['qq'], + adapter=mirai.HTTPAdapter( + host=config['host'], + port=config['port'], + verify_key=config['verifyKey'] + ) + ) + else: + raise Exception('Unknown adapter for YiriMirai: ' + config['adapter']) + + def send_message( + self, + target_type: str, + target_id: str, + message: mirai.MessageChain + ): + """发送消息 + + Args: + target_type (str): 目标类型,`person`或`group` + target_id (str): 目标ID + message (mirai.MessageChain): YiriMirai库的消息链 + """ + task = None + if target_type == 'person': + task = self.bot.send_friend_message(int(target_id), message) + elif target_type == 'group': + task = self.bot.send_group_message(int(target_id), message) + else: + raise Exception('Unknown target type: ' + target_type) + + asyncio.run(task) + + def reply_message( + self, + message_source: mirai.MessageEvent, + message: mirai.MessageChain + ): + """回复消息 + + Args: + message_source (mirai.MessageEvent): YiriMirai消息源事件 + message (mirai.MessageChain): YiriMirai库的消息链 + """ + asyncio.run(self.bot.send(message_source, message)) + + def register_listener( + self, + event_type: typing.Type[mirai.Event], + callback: typing.Callable[[mirai.Event], None] + ): + """注册事件监听器 + + Args: + event_type (typing.Type[mirai.Event]): YiriMirai事件类型 + callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件 + """ + self.bot.on(event_type)(callback) + + def unregister_listener( + self, + event_type: typing.Type[mirai.Event], + callback: typing.Callable[[mirai.Event], None] + ): + """注销事件监听器 + + Args: + event_type (typing.Type[mirai.Event]): YiriMirai事件类型 + callback (typing.Callable[[mirai.Event], None]): 回调函数,接收一个参数,为YiriMirai事件 + """ + assert isinstance(self.bot, mirai.Mirai) + bus = self.bot.bus + assert isinstance(bus, mirai.models.bus.ModelEventBus) + + bus.unsubscribe(event_type, callback) + + def run_sync(self): + self.bot.run() + + def kill(self) -> bool: + return False