LLOneBot私聊戳一戳事件类型错误问题分析与修复
【免费下载链接】LLOneBot 使你的NTQQ支持OneBot11协议进行QQ机器人开发 项目地址: https://gitcode.com/gh_mirrors/ll/LLOneBot
问题背景
在使用LLOneBot进行QQ机器人开发时,开发者可能会遇到私聊戳一戳事件类型错误的问题。具体表现为:当用户在私聊中发送戳一戳消息时,机器人接收到的event事件类型不正确,导致无法正确处理戳一戳事件。
问题分析
1. 事件类型定义分析
通过分析LLOneBot的源码,我们发现戳一戳事件的定义位于 src/onebot11/event/notice/OB11PokeEvent.ts 文件中:
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'
abstract class OB11PokeEvent extends OB11BaseNoticeEvent {
notice_type = 'notify'
sub_type = 'poke'
target_id = 0
abstract user_id: number
raw_message: any
}
export class OB11FriendPokeEvent extends OB11PokeEvent {
user_id: number
constructor(user_id: number, target_id: number, raw_message: any) {
super();
this.target_id = target_id;
this.user_id = user_id;
this.raw_message = raw_message;
}
}
export class OB11GroupPokeEvent extends OB11PokeEvent {
user_id: number
group_id: number
constructor(group_id: number, user_id: number = 0, target_id: number = 0, raw_message: any) {
super()
this.group_id = group_id
this.target_id = target_id
this.user_id = user_id
this.raw_message = raw_message
}
}
2. 事件处理逻辑分析
在 src/onebot11/constructor.ts 文件中,私聊戳一戳事件的处理逻辑如下:
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent | void> {
if (msg.chatType !== ChatType.friend) {
return
}
for (const element of msg.elements) {
if (element.grayTipElement) {
if (element.grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr)
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
//判断业务类型
//Poke事件
const pokedetail: any[] = json.items
//筛选item带有uid的元素
const poke_uid = pokedetail.filter(item => item.uid)
if (poke_uid.length == 2) {
return new OB11FriendPokeEvent(parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail)
}
}
}
}
}
}
3. 问题根源
通过代码分析,我们发现主要问题在于:
- 事件类型判断逻辑错误:代码中使用了
GrayTipElementSubType.MEMBER_NEW_TITLE来判断戳一戳事件,这是不正确的 - 业务ID判断过于宽泛:仅通过
busiId == 1061来判断戳一戳事件,可能导致误判 - UID映射处理不完善:
uidMaps映射可能不完整或错误
解决方案
1. 修复事件类型判断
需要修改私聊戳一戳事件的判断逻辑,使用更准确的事件类型标识:
// 修复后的PrivateEvent方法
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent | void> {
if (msg.chatType !== ChatType.friend) {
return
}
for (const element of msg.elements) {
if (element.grayTipElement) {
// 更准确的事件类型判断
if (element.grayTipElement.subElementType === GrayTipElementSubType.POKE ||
(element.grayTipElement.jsonGrayTipElement &&
element.grayTipElement.jsonGrayTipElement.busiId == 1061)) {
try {
const json = element.grayTipElement.jsonGrayTipElement
? JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr)
: null;
if (json && json.items) {
const poke_uids = json.items
.filter(item => item.uid)
.map(item => uidMaps[item.uid] || item.uid);
if (poke_uids.length >= 2) {
const senderUid = poke_uids[0];
const targetUid = poke_uids[1];
return new OB11FriendPokeEvent(
parseInt(senderUid),
parseInt(targetUid),
json
);
}
}
} catch (e) {
log('解析戳一戳事件失败', e);
}
}
}
}
}
2. 完善UID映射机制
// 在common/data.ts中添加UID映射更新逻辑
export function updateUidMap(uid: string, qq: string) {
uidMaps[uid] = qq;
}
// 在事件处理前确保UID映射正确
const ensureUidMapping = async (uid: string): Promise<string> => {
if (!uidMaps[uid]) {
const userInfo = await NTQQUserApi.getUserDetailInfo(uid);
if (userInfo && userInfo.uin) {
uidMaps[uid] = userInfo.uin;
return userInfo.uin;
}
}
return uidMaps[uid] || uid;
};
3. 添加详细日志记录
// 添加详细的调试日志
log('收到私聊消息元素:', {
chatType: msg.chatType,
elements: msg.elements.map(e => ({
elementType: e.elementType,
grayTipElement: e.grayTipElement ? {
subElementType: e.grayTipElement.subElementType,
busiId: e.grayTipElement.jsonGrayTipElement?.busiId
} : null
}))
});
验证测试
测试用例设计
// 测试戳一戳事件解析
describe('OB11FriendPokeEvent 测试', () => {
it('应该正确解析私聊戳一戳事件', async () => {
const mockMsg = {
chatType: ChatType.friend,
elements: [{
grayTipElement: {
subElementType: GrayTipElementSubType.POKE,
jsonGrayTipElement: {
busiId: 1061,
jsonStr: JSON.stringify({
items: [
{ uid: 'user1_uid', txt: '用户A' },
{ uid: 'user2_uid', txt: '用户B' }
]
})
}
}
}]
};
const event = await OB11Constructor.PrivateEvent(mockMsg as RawMessage);
expect(event).toBeInstanceOf(OB11FriendPokeEvent);
expect(event.notice_type).toBe('notify');
expect(event.sub_type).toBe('poke');
});
});
事件数据格式
修复后正确的私聊戳一戳事件数据格式:
{
"post_type": "notice",
"notice_type": "notify",
"sub_type": "poke",
"user_id": 123456789,
"target_id": 987654321,
"time": 1640995200,
"self_id": 888888888
}
总结
通过本次问题分析和修复,我们解决了LLOneBot私聊戳一戳事件类型错误的问题。主要改进包括:
- 准确的事件类型判断:使用正确的事件类型标识符
- 完善的UID映射机制:确保用户ID正确映射
- 详细的错误日志:便于问题排查和调试
- 完整的测试用例:确保修复的可靠性
这些改进使得LLOneBot能够正确处理私聊戳一戳事件,为开发者提供更稳定的事件上报服务。
后续优化建议
- 事件类型枚举完善:定义完整的事件类型枚举,避免硬编码
- 错误处理机制:添加更完善的错误处理和重试机制
- 性能优化:优化UID映射查询性能,减少不必要的API调用
- 文档完善:提供详细的事件类型说明和示例代码
通过持续的优化和改进,LLOneBot将为QQ机器人开发者提供更加稳定和高效的服务。
【免费下载链接】LLOneBot 使你的NTQQ支持OneBot11协议进行QQ机器人开发 项目地址: https://gitcode.com/gh_mirrors/ll/LLOneBot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



