LLOneBot私聊戳一戳事件类型错误问题分析与修复

LLOneBot私聊戳一戳事件类型错误问题分析与修复

【免费下载链接】LLOneBot 使你的NTQQ支持OneBot11协议进行QQ机器人开发 【免费下载链接】LLOneBot 项目地址: 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. 问题根源

通过代码分析,我们发现主要问题在于:

  1. 事件类型判断逻辑错误:代码中使用了 GrayTipElementSubType.MEMBER_NEW_TITLE 来判断戳一戳事件,这是不正确的
  2. 业务ID判断过于宽泛:仅通过 busiId == 1061 来判断戳一戳事件,可能导致误判
  3. 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私聊戳一戳事件类型错误的问题。主要改进包括:

  1. 准确的事件类型判断:使用正确的事件类型标识符
  2. 完善的UID映射机制:确保用户ID正确映射
  3. 详细的错误日志:便于问题排查和调试
  4. 完整的测试用例:确保修复的可靠性

这些改进使得LLOneBot能够正确处理私聊戳一戳事件,为开发者提供更稳定的事件上报服务。

后续优化建议

  1. 事件类型枚举完善:定义完整的事件类型枚举,避免硬编码
  2. 错误处理机制:添加更完善的错误处理和重试机制
  3. 性能优化:优化UID映射查询性能,减少不必要的API调用
  4. 文档完善:提供详细的事件类型说明和示例代码

通过持续的优化和改进,LLOneBot将为QQ机器人开发者提供更加稳定和高效的服务。

【免费下载链接】LLOneBot 使你的NTQQ支持OneBot11协议进行QQ机器人开发 【免费下载链接】LLOneBot 项目地址: https://gitcode.com/gh_mirrors/ll/LLOneBot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值