接入event

This commit is contained in:
Windpicker-owo
2025-08-27 01:55:14 +08:00
parent 441ba8f62d
commit 84ea2c41de
6 changed files with 169 additions and 11 deletions

View File

@@ -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"

View File

@@ -35,6 +35,7 @@ class NoticeType: # 通知事件
class Notify: class Notify:
poke = "poke" # 戳一戳 poke = "poke" # 戳一戳
input_status = "input_status" # 正在输入
class GroupBan: class GroupBan:
ban = "ban" # 禁言 ban = "ban" # 禁言
@@ -56,6 +57,7 @@ class RealMessageType: # 实际消息分类
reply = "reply" # 回复消息 reply = "reply" # 回复消息
forward = "forward" # 转发消息 forward = "forward" # 转发消息
node = "node" # 转发消息节点 node = "node" # 转发消息节点
json = "json" # json消息
class MessageSentType: class MessageSentType:

View File

@@ -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 from src.common.logger import get_logger
logger = get_logger("napcat_adapter") logger = get_logger("napcat_adapter")
@@ -327,12 +329,14 @@ class MessageHandler:
case RealMessageType.text: case RealMessageType.text:
ret_seg = await self.handle_text_message(sub_message) ret_seg = await self.handle_text_message(sub_message)
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_TEXT,message_seg=ret_seg)
seg_message.append(ret_seg) seg_message.append(ret_seg)
else: else:
logger.warning("text处理失败") logger.warning("text处理失败")
case RealMessageType.face: case RealMessageType.face:
ret_seg = await self.handle_face_message(sub_message) ret_seg = await self.handle_face_message(sub_message)
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_FACE,message_seg=ret_seg)
seg_message.append(ret_seg) seg_message.append(ret_seg)
else: else:
logger.warning("face处理失败或不支持") logger.warning("face处理失败或不支持")
@@ -340,6 +344,7 @@ class MessageHandler:
if not in_reply: if not in_reply:
ret_seg = await self.handle_reply_message(sub_message) ret_seg = await self.handle_reply_message(sub_message)
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_REPLY,message_seg=ret_seg)
seg_message += ret_seg seg_message += ret_seg
else: else:
logger.warning("reply处理失败") logger.warning("reply处理失败")
@@ -347,6 +352,7 @@ class MessageHandler:
logger.debug(f"开始处理图片消息段") logger.debug(f"开始处理图片消息段")
ret_seg = await self.handle_image_message(sub_message) ret_seg = await self.handle_image_message(sub_message)
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_IMAGE,message_seg=ret_seg)
seg_message.append(ret_seg) seg_message.append(ret_seg)
logger.debug(f"图片处理成功,添加到消息段") logger.debug(f"图片处理成功,添加到消息段")
else: else:
@@ -355,6 +361,7 @@ class MessageHandler:
case RealMessageType.record: case RealMessageType.record:
ret_seg = await self.handle_record_message(sub_message) ret_seg = await self.handle_record_message(sub_message)
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_RECORD,message_seg=ret_seg)
seg_message.clear() seg_message.clear()
seg_message.append(ret_seg) seg_message.append(ret_seg)
break # 使得消息只有record消息 break # 使得消息只有record消息
@@ -363,6 +370,7 @@ class MessageHandler:
case RealMessageType.video: case RealMessageType.video:
ret_seg = await self.handle_video_message(sub_message) ret_seg = await self.handle_video_message(sub_message)
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_VIDEO,message_seg=ret_seg)
seg_message.append(ret_seg) seg_message.append(ret_seg)
else: else:
logger.warning("video处理失败") logger.warning("video处理失败")
@@ -373,17 +381,33 @@ class MessageHandler:
raw_message.get("group_id"), raw_message.get("group_id"),
) )
if ret_seg: if ret_seg:
await event_manager.trigger_event(NapcatEvent.ON_RECEIVED_AT,message_seg=ret_seg)
seg_message.append(ret_seg) seg_message.append(ret_seg)
else: else:
logger.warning("at处理失败") logger.warning("at处理失败")
case RealMessageType.rps: 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: 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: case RealMessageType.shake:
# 预计等价于戳一戳 ret_seg = await self.handle_shake_message(sub_message)
logger.warning("暂时不支持窗口抖动解析") 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: case RealMessageType.share:
print("\n\n哦哦哦噢噢噢哦哦你收到了一个超级无敌SHARE消息快速速把你刚刚收到的消息截图发到MoFox-Bot群里\n\n")
logger.warning("暂时不支持链接解析") logger.warning("暂时不支持链接解析")
case RealMessageType.forward: case RealMessageType.forward:
messages = await self._get_forward_message(sub_message) messages = await self._get_forward_message(sub_message)
@@ -396,7 +420,15 @@ class MessageHandler:
else: else:
logger.warning("转发消息处理失败") logger.warning("转发消息处理失败")
case RealMessageType.node: case RealMessageType.node:
print("\n\n哦哦哦噢噢噢哦哦你收到了一个超级无敌NODE消息快速速把你刚刚收到的消息截图发到MoFox-Bot群里\n\n")
logger.warning("不支持转发消息节点解析") 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 _: case _:
logger.warning(f"未知消息类型: {sub_message_type}") logger.warning(f"未知消息类型: {sub_message_type}")
@@ -643,25 +675,49 @@ class MessageHandler:
processed_message: Seg processed_message: Seg
if image_count < 5 and image_count > 0: if image_count < 5 and image_count > 0:
# 处理图片数量小于5的情况此时解析图片为base64 # 处理图片数量小于5的情况此时解析图片为base64
logger.trace("图片数量小于5开始解析图片为base64") logger.info("图片数量小于5开始解析图片为base64")
processed_message = await self._recursive_parse_image_seg( processed_message = await self._recursive_parse_image_seg(
handled_message, True handled_message, True
) )
elif image_count > 0: elif image_count > 0:
logger.trace("图片数量大于等于5开始解析图片为占位符") logger.info("图片数量大于等于5开始解析图片为占位符")
# 处理图片数量大于等于5的情况此时解析图片为占位符 # 处理图片数量大于等于5的情况此时解析图片为占位符
processed_message = await self._recursive_parse_image_seg( processed_message = await self._recursive_parse_image_seg(
handled_message, False handled_message, False
) )
else: else:
# 处理没有图片的情况,此时直接返回 # 处理没有图片的情况,此时直接返回
logger.trace("没有图片,直接返回") logger.info("没有图片,直接返回")
processed_message = handled_message processed_message = handled_message
# 添加转发消息提示 # 添加转发消息提示
forward_hint = Seg(type="text", data="这是一条转发消息:\n") forward_hint = Seg(type="text", data="这是一条转发消息:\n")
return Seg(type="seglist", data=[forward_hint, processed_message]) 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: async def _recursive_parse_image_seg(self, seg_data: Seg, to_image: bool) -> Seg:
# sourcery skip: merge-else-if-into-elif # sourcery skip: merge-else-if-into-elif
if to_image: if to_image:
@@ -688,7 +744,7 @@ class MessageHandler:
return Seg(type="text", data="[表情包]") return Seg(type="text", data="[表情包]")
return Seg(type="emoji", data=encoded_image) return Seg(type="emoji", data=encoded_image)
else: else:
logger.trace(f"不处理类型: {seg_data.type}") logger.info(f"不处理类型: {seg_data.type}")
return seg_data return seg_data
else: else:
if seg_data.type == "seglist": if seg_data.type == "seglist":
@@ -702,7 +758,7 @@ class MessageHandler:
elif seg_data.type == "emoji": elif seg_data.type == "emoji":
return Seg(type="text", data="[动画表情]") return Seg(type="text", data="[动画表情]")
else: else:
logger.trace(f"不处理类型: {seg_data.type}") logger.info(f"不处理类型: {seg_data.type}")
return seg_data return seg_data
async def _handle_forward_message(self, message_list: list, layer: int) -> Tuple[Seg, int] | Tuple[None, int]: async def _handle_forward_message(self, message_list: list, layer: int) -> Tuple[Seg, int] | Tuple[None, int]:

View File

@@ -115,6 +115,10 @@ class NoticeHandler:
handled_message, user_info = await self.handle_poke_notify(raw_message, group_id, user_id) handled_message, user_info = await self.handle_poke_notify(raw_message, group_id, user_id)
else: else:
logger.warning("戳一戳消息被禁用,取消戳一戳处理") 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 _: case _:
logger.warning(f"不支持的notify类型: {notice_type}.{sub_type}") logger.warning(f"不支持的notify类型: {notice_type}.{sub_type}")
case NoticeType.group_ban: case NoticeType.group_ban:

View File

@@ -12,7 +12,7 @@ response_time_dict: Dict = {}
async def get_response(request_id: str, timeout: int = 10) -> dict: async def get_response(request_id: str, timeout: int = 10) -> dict:
response = await asyncio.wait_for(_get_response(request_id), timeout) response = await asyncio.wait_for(_get_response(request_id), timeout)
_ = response_time_dict.pop(request_id) _ = response_time_dict.pop(request_id)
logger.trace(f"响应信息id: {request_id} 已从响应字典中取出") logger.info(f"响应信息id: {request_id} 已从响应字典中取出")
return response return response
async def _get_response(request_id: str) -> dict: async def _get_response(request_id: str) -> dict:
@@ -28,7 +28,7 @@ async def put_response(response: dict):
now_time = time.time() now_time = time.time()
response_dict[echo_id] = response response_dict[echo_id] = response
response_time_dict[echo_id] = now_time 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: async def check_timeout_response() -> None:

View File

@@ -1,3 +1,5 @@
# TODO List:
[x] logger使用主程序的 [x] logger使用主程序的
[ ] 使用插件系统的config系统 [ ] 使用插件系统的config系统
[ ] 接收从napcat传递的所有信息 [ ] 接收从napcat传递的所有信息
@@ -5,3 +7,83 @@
[ ] 单独一个模块负责与主程序通信 [ ] 单独一个模块负责与主程序通信
[ ] 使用event系统完善接口api [ ] 使用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)
```