From 84ea2c41de51b1d23ecd5426660d71f3ddf74f31 Mon Sep 17 00:00:00 2001 From: Windpicker-owo <3431391539@qq.com> Date: Wed, 27 Aug 2025 01:55:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/napcat_adapter_plugin/event_types.py | 14 ++++ .../src/recv_handler/__init__.py | 2 + .../src/recv_handler/message_handler.py | 74 +++++++++++++++-- .../src/recv_handler/notice_handler.py | 4 + .../src/response_pool.py | 4 +- plugins/napcat_adapter_plugin/todo.md | 82 +++++++++++++++++++ 6 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 plugins/napcat_adapter_plugin/event_types.py diff --git a/plugins/napcat_adapter_plugin/event_types.py b/plugins/napcat_adapter_plugin/event_types.py new file mode 100644 index 000000000..bae6f422a --- /dev/null +++ b/plugins/napcat_adapter_plugin/event_types.py @@ -0,0 +1,14 @@ +class NapcatEvent: + # napcat插件事件枚举类 + ON_RECEIVED_TEXT = "napcat_on_received_text" + ON_RECEIVED_FACE = "napcat_on_received_face" + ON_RECEIVED_REPLY = "napcat_on_received_reply" + ON_RECEIVED_IMAGE = "napcat_on_received_image" + ON_RECEIVED_RECORD = "napcat_on_received_record" + ON_RECEIVED_VIDEO = "napcat_on_received_video" + ON_RECEIVED_AT = "napcat_on_received_at" + ON_RECEIVED_DICE = "napcat_on_received_dice" + ON_RECEIVED_SHAKE = "napcat_on_received_shake" + ON_RECEIVED_JSON = "napcat_on_received_json" + ON_RECEIVED_RPS = "napcat_on_received_rps" + ON_FRIEND_INPUT = "napcat_on_friend_input" diff --git a/plugins/napcat_adapter_plugin/src/recv_handler/__init__.py b/plugins/napcat_adapter_plugin/src/recv_handler/__init__.py index 422041b62..b2fb9bad1 100644 --- a/plugins/napcat_adapter_plugin/src/recv_handler/__init__.py +++ b/plugins/napcat_adapter_plugin/src/recv_handler/__init__.py @@ -35,6 +35,7 @@ class NoticeType: # 通知事件 class Notify: poke = "poke" # 戳一戳 + input_status = "input_status" # 正在输入 class GroupBan: ban = "ban" # 禁言 @@ -56,6 +57,7 @@ class RealMessageType: # 实际消息分类 reply = "reply" # 回复消息 forward = "forward" # 转发消息 node = "node" # 转发消息节点 + json = "json" # json消息 class MessageSentType: diff --git a/plugins/napcat_adapter_plugin/src/recv_handler/message_handler.py b/plugins/napcat_adapter_plugin/src/recv_handler/message_handler.py index deb5b8502..9153134bf 100644 --- a/plugins/napcat_adapter_plugin/src/recv_handler/message_handler.py +++ b/plugins/napcat_adapter_plugin/src/recv_handler/message_handler.py @@ -1,3 +1,5 @@ +from ...event_types import NapcatEvent +from src.plugin_system.core.event_manager import event_manager from src.common.logger import get_logger logger = get_logger("napcat_adapter") @@ -327,12 +329,14 @@ class MessageHandler: case RealMessageType.text: ret_seg = await self.handle_text_message(sub_message) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_TEXT,message_seg=ret_seg) seg_message.append(ret_seg) else: logger.warning("text处理失败") case RealMessageType.face: ret_seg = await self.handle_face_message(sub_message) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_FACE,message_seg=ret_seg) seg_message.append(ret_seg) else: logger.warning("face处理失败或不支持") @@ -340,6 +344,7 @@ class MessageHandler: if not in_reply: ret_seg = await self.handle_reply_message(sub_message) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_REPLY,message_seg=ret_seg) seg_message += ret_seg else: logger.warning("reply处理失败") @@ -347,6 +352,7 @@ class MessageHandler: logger.debug(f"开始处理图片消息段") ret_seg = await self.handle_image_message(sub_message) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_IMAGE,message_seg=ret_seg) seg_message.append(ret_seg) logger.debug(f"图片处理成功,添加到消息段") else: @@ -355,6 +361,7 @@ class MessageHandler: case RealMessageType.record: ret_seg = await self.handle_record_message(sub_message) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_RECORD,message_seg=ret_seg) seg_message.clear() seg_message.append(ret_seg) break # 使得消息只有record消息 @@ -363,6 +370,7 @@ class MessageHandler: case RealMessageType.video: ret_seg = await self.handle_video_message(sub_message) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_VIDEO,message_seg=ret_seg) seg_message.append(ret_seg) else: logger.warning("video处理失败") @@ -373,17 +381,33 @@ class MessageHandler: raw_message.get("group_id"), ) if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_AT,message_seg=ret_seg) seg_message.append(ret_seg) else: logger.warning("at处理失败") case RealMessageType.rps: - logger.warning("暂时不支持猜拳魔法表情解析") + ret_seg = await self.handle_rps_message(sub_message) + if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_RPS,message_seg=ret_seg) + seg_message.append(ret_seg) + else: + logger.warning("rps处理失败") case RealMessageType.dice: - logger.warning("暂时不支持骰子表情解析") + ret_seg = await self.handle_dice_message(sub_message) + if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_DICE,message_seg=ret_seg) + seg_message.append(ret_seg) + else: + logger.warning("dice处理失败") case RealMessageType.shake: - # 预计等价于戳一戳 - logger.warning("暂时不支持窗口抖动解析") + ret_seg = await self.handle_shake_message(sub_message) + if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_SHAKE,message_seg=ret_seg) + seg_message.append(ret_seg) + else: + logger.warning("shake处理失败") case RealMessageType.share: + print("\n\n哦哦哦噢噢噢哦哦你收到了一个超级无敌SHARE消息,快速速把你刚刚收到的消息截图发到MoFox-Bot群里!!!!\n\n") logger.warning("暂时不支持链接解析") case RealMessageType.forward: messages = await self._get_forward_message(sub_message) @@ -396,7 +420,15 @@ class MessageHandler: else: logger.warning("转发消息处理失败") case RealMessageType.node: + print("\n\n哦哦哦噢噢噢哦哦你收到了一个超级无敌NODE消息,快速速把你刚刚收到的消息截图发到MoFox-Bot群里!!!!\n\n") logger.warning("不支持转发消息节点解析") + case RealMessageType.json: + ret_seg = await self.handle_json_message(sub_message) + if ret_seg: + await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_JSON,message_seg=ret_seg) + seg_message.append(ret_seg) + else: + logger.warning("json处理失败") case _: logger.warning(f"未知消息类型: {sub_message_type}") @@ -643,25 +675,49 @@ class MessageHandler: processed_message: Seg if image_count < 5 and image_count > 0: # 处理图片数量小于5的情况,此时解析图片为base64 - logger.trace("图片数量小于5,开始解析图片为base64") + logger.info("图片数量小于5,开始解析图片为base64") processed_message = await self._recursive_parse_image_seg( handled_message, True ) elif image_count > 0: - logger.trace("图片数量大于等于5,开始解析图片为占位符") + logger.info("图片数量大于等于5,开始解析图片为占位符") # 处理图片数量大于等于5的情况,此时解析图片为占位符 processed_message = await self._recursive_parse_image_seg( handled_message, False ) else: # 处理没有图片的情况,此时直接返回 - logger.trace("没有图片,直接返回") + logger.info("没有图片,直接返回") processed_message = handled_message # 添加转发消息提示 forward_hint = Seg(type="text", data="这是一条转发消息:\n") return Seg(type="seglist", data=[forward_hint, processed_message]) + async def handle_dice_message(self, raw_message: dict) -> Seg: + message_data: dict = raw_message.get("data",{}) + res = message_data.get("result","") + return Seg(type="text", data=f"[扔了一个骰子,点数是{res}]") + + async def handle_shake_message(self, raw_message: dict) -> Seg: + return Seg(type="text", data="[向你发送了窗口抖动,现在你的屏幕猛烈地震了一下!]") + + async def handle_json_message(self, raw_message: dict) -> Seg: + message_data: str = raw_message.get("data","").get("data","") + res = json.loads(message_data) + return Seg(type="json", data=res) + + async def handle_rps_message(self, raw_message: dict) -> Seg: + message_data: dict = raw_message.get("data",{}) + res = message_data.get("result","") + if res == "1": + shape = "布" + elif res == "2": + shape = "剪刀" + else: + shape = "石头" + return Seg(type="text", data=f"[发送了一个魔法猜拳表情,结果是:{shape}]") + async def _recursive_parse_image_seg(self, seg_data: Seg, to_image: bool) -> Seg: # sourcery skip: merge-else-if-into-elif if to_image: @@ -688,7 +744,7 @@ class MessageHandler: return Seg(type="text", data="[表情包]") return Seg(type="emoji", data=encoded_image) else: - logger.trace(f"不处理类型: {seg_data.type}") + logger.info(f"不处理类型: {seg_data.type}") return seg_data else: if seg_data.type == "seglist": @@ -702,7 +758,7 @@ class MessageHandler: elif seg_data.type == "emoji": return Seg(type="text", data="[动画表情]") else: - logger.trace(f"不处理类型: {seg_data.type}") + logger.info(f"不处理类型: {seg_data.type}") return seg_data async def _handle_forward_message(self, message_list: list, layer: int) -> Tuple[Seg, int] | Tuple[None, int]: diff --git a/plugins/napcat_adapter_plugin/src/recv_handler/notice_handler.py b/plugins/napcat_adapter_plugin/src/recv_handler/notice_handler.py index a35f9b01c..d1b5602db 100644 --- a/plugins/napcat_adapter_plugin/src/recv_handler/notice_handler.py +++ b/plugins/napcat_adapter_plugin/src/recv_handler/notice_handler.py @@ -115,6 +115,10 @@ class NoticeHandler: handled_message, user_info = await self.handle_poke_notify(raw_message, group_id, user_id) else: logger.warning("戳一戳消息被禁用,取消戳一戳处理") + case NoticeType.Notify.input_status: + from src.plugin_system.core.event_manager import event_manager + from ...event_types import NapcatEvent + await event_manager.trigger_event(NapcatEvent.ON_FRIEND_INPUT) case _: logger.warning(f"不支持的notify类型: {notice_type}.{sub_type}") case NoticeType.group_ban: diff --git a/plugins/napcat_adapter_plugin/src/response_pool.py b/plugins/napcat_adapter_plugin/src/response_pool.py index 09ada32e0..ede85d04d 100644 --- a/plugins/napcat_adapter_plugin/src/response_pool.py +++ b/plugins/napcat_adapter_plugin/src/response_pool.py @@ -12,7 +12,7 @@ response_time_dict: Dict = {} async def get_response(request_id: str, timeout: int = 10) -> dict: response = await asyncio.wait_for(_get_response(request_id), timeout) _ = response_time_dict.pop(request_id) - logger.trace(f"响应信息id: {request_id} 已从响应字典中取出") + logger.info(f"响应信息id: {request_id} 已从响应字典中取出") return response async def _get_response(request_id: str) -> dict: @@ -28,7 +28,7 @@ async def put_response(response: dict): now_time = time.time() response_dict[echo_id] = response response_time_dict[echo_id] = now_time - logger.trace(f"响应信息id: {echo_id} 已存入响应字典") + logger.info(f"响应信息id: {echo_id} 已存入响应字典") async def check_timeout_response() -> None: diff --git a/plugins/napcat_adapter_plugin/todo.md b/plugins/napcat_adapter_plugin/todo.md index 8ec0027bc..483426826 100644 --- a/plugins/napcat_adapter_plugin/todo.md +++ b/plugins/napcat_adapter_plugin/todo.md @@ -1,3 +1,5 @@ +# TODO List: + [x] logger使用主程序的 [ ] 使用插件系统的config系统 [ ] 接收从napcat传递的所有信息 @@ -5,3 +7,83 @@ [ ] 单独一个模块负责与主程序通信 [ ] 使用event系统完善接口api + +--- +Event分为两种,一种是对外输出的event,由napcat插件自主触发并传递参数,另一种是接收外界输入的event,由外部插件触发并向napcat传递参数 + + +## 例如, + +### 对外输出的event: + +napcat_on_received_text -> (message_seg: Seg) 接受到qq的文字消息,会向handler传递一个Seg +napcat_on_received_face -> (message_seg: Seg) 接受到qq的表情消息,会向handler传递一个Seg +napcat_on_received_reply -> (message_seg: Seg) 接受到qq的回复消息,会向handler传递一个Seg +napcat_on_received_image -> (message_seg: Seg) 接受到qq的图片消息,会向handler传递一个Seg +napcat_on_received_image -> (message_seg: Seg) 接受到qq的图片消息,会向handler传递一个Seg +napcat_on_received_record -> (message_seg: Seg) 接受到qq的语音消息,会向handler传递一个Seg +napcat_on_received_rps -> (message_seg: Seg) 接受到qq的猜拳魔法表情,会向handler传递一个Seg +napcat_on_received_friend_invitation -> (user_id: str) 接受到qq的好友请求,会向handler传递一个user_id +... + +此类event不接受外部插件的触发,只能由napcat插件统一触发。 + +外部插件需要编写handler并订阅此类事件。 +```python +from src.plugin_system.core.event_manager import event_manager +from src.plugin_system.base.base_event import HandlerResult + +class MyEventHandler(BaseEventHandler): + handler_name = "my_handler" + handler_description = "我的自定义事件处理器" + weight = 10 # 权重,越大越先执行 + intercept_message = False # 是否拦截消息 + init_subscribe = ["napcat_on_received_text"] # 初始订阅的事件 + + async def execute(self, params: dict) -> HandlerResult: + """处理事件""" + try: + message = params.get("message_seg") + print(f"收到消息: {message.data}") + + # 业务逻辑处理 + # ... + + return HandlerResult( + success=True, + continue_process=True, # 是否继续让其他处理器处理 + message="处理成功", + handler_name=self.handler_name + ) + except Exception as e: + return HandlerResult( + success=False, + continue_process=True, + message=f"处理失败: {str(e)}", + handler_name=self.handler_name + ) + +``` + +### 接收外界输入的event: + +napcat_kick_group <- (user_id, group_id) 踢出某个群组中的某个用户 +napcat_mute_user <- (user_id, group_id, time) 禁言某个群组中的某个用户 +napcat_unmute_user <- (user_id, group_id) 取消禁言某个群组中的某个用户 +napcat_mute_group <- (user_id, group_id) 禁言某个群组 +napcat_unmute_group <- (user_id, group_id) 取消禁言某个群组 +napcat_add_friend <- (user_id) 向某个用户发出好友请求 +napcat_accept_friend <- (user_id) 接收某个用户的好友请求 +napcat_reject_friend <- (user_id) 拒绝某个用户的好友请求 +... +此类事件只由外部插件触发并传递参数,由napcat完成请求任务。 + +外部插件需要触发此类的event并传递正确的参数。 + +```python +from src.plugin_system.core.event_manager import event_manager + +# 触发事件 +await event_manager.trigger_event("napcat_accept_friend", user_id = 1234123) +``` +