Flutter message concurrent processing, recursive query

Execute the receiveNewConversation method when receiving a new message

You can simulate the insertion of two data by yourself and delay the operation of inserting the session
When receiving a new session message, first record the session ID into the list until the first one is processed After finishing (clearing the session ID after inserting into the database), the second message with the same session ID is processed (always in empty recursion)
(See the one that can always monitor global during recursive processing. Does the conversation list contain data for a certain session, because it is being executed repeatedly)

The core concepts are: 1. Ensure that processing of multiple messages with the same session ID must be single-threaded, 2. When inserting the first message, it must be stuck, do not let the second message come in, and wait until the first message is inserted into the database before executing it. Article 2

Note: If you simply delay 100 milliseconds and then execute the second message with the same session ID, this method will still not be able to block the second message, and two sessions will still be inserted into the database at the same time. A executes the insertion at 12:01, and B The insertion is performed at 12:02. A takes two seconds and B takes one second. Both insert messages at the same time at 12:03, resulting in two sessions.

So we still need to add a transaction lock, lock it after the first one is executed, and then execute the second one after it is completed.

  //新会话限制列表,存放会话ID
  static List<String> newConversationList = [];

  //会话队列
  static List<WsImMessageQueue> wsImConversationQueue = [];

  //是否正在处理会话递归
  static bool wsImConversationQueueState = false;
//不存在会话,则保存会话ID到新会话列表,等插完数据库后再清除新会话列表。
// 第二条会话进来插入到消息列表要等待,等新会话列表没有这个会话ID才把消息插入数据库


  ///收到新会话处理
  receiveNewConversation(RecvChatMsg recvChatMsg, bool isOffLineMessage) {
    
    
    //会话队列添加数据
    Global.wsImConversationQueue.add(WsImMessageQueue(
        recvChatMsg: recvChatMsg, isOffLineMessage: isOffLineMessage));

    PrintUtil.prints(
        '$TAG 中台IM消息 插入会话消息到wsImConversationQueue: ${
    
    utf8.decode(recvChatMsg.body)}   Global.wsImConversationQueue的长度${
    
    Global.wsImConversationQueue.length}');

    if (!Global.wsImConversationQueueState) {
    
    
      Global.wsImConversationQueueState = true;
      //开始递归
      startProcessingConversationQueue(true);
      PrintUtil.prints(
          '$TAG 中台IM消息 递归完成:${
    
    Global.wsImConversationQueueState}');

    }
  }

  startProcessingConversationQueue(bool isExistMessage) {
    
    
    if (isExistMessage) {
    
    
      //不为空的时候执行
      if (Global.wsImConversationQueue.isNotEmpty) {
    
    
        PrintUtil.prints(
            '$TAG 中台IM消息 === > 开始执行递归方法体');
        //取第一个数据
        if (Global.wsImConversationQueue[0].recvChatMsg != null) {
    
    

          WsImMessage wsImMessage =
              addWsImMessage(Global.wsImConversationQueue[0].recvChatMsg);

          PrintUtil.prints(
              '$TAG 中台IM消息 === > 会话列表第一个会话ID${
    
    wsImMessage.conversationId}');

          //第一条新消息不会被拦截,第二条同会话的消息会被拦截,查询该会话是否在新会话列表里面,如果为true,不给执行,一直执行递归,直到第一条会话插入数据库成功再执行这个判断里面
          if (checkConversationId(wsImMessage.conversationId ?? '') == false) {
    
    
            PrintUtil.prints(
                '$TAG 中台IM消息 === > 第一个数据或者会话列表第一个会话ID已从新会话限制列表里面移除');
            WsImDBUtil().insertMessage(
                Global.wsImConversationQueue[0].recvChatMsg!,
                Global.wsImConversationQueue[0].isOffLineMessage);

            //如果下一条进来后还是没有查出来赋值,那还是会拦截不到,一般在一秒内完成,应该影响不大
            WsImConversationDb.queryId(wsImMessage.conversationId).then((value) {
    
    
              if (value.isEmpty) {
    
    
                if (wsImMessage.conversationId != null) {
    
    
                  //插入到新会话限制列表里面
                  Global.newConversationList.add(wsImMessage.conversationId!);
                  PrintUtil.prints(
                      '$TAG 中台IM消息 === > 没有该会话就添加会话ID到会话队列:${
    
    Global.newConversationList}');
                }
              } else {
    
    
              }
            });

            PrintUtil.prints(
                '$TAG 中台IM消息 === > 插入消息,新会话限制列表:${
    
    Global.newConversationList}');
            Global.wsImConversationQueue
                .remove(Global.wsImConversationQueue[0]);
            PrintUtil.prints(
                '$TAG 中台IM消息 === > 移除消息,消息队列还剩:${
    
    Global.wsImConversationQueue.length}');
          }

          Future.delayed(const Duration(milliseconds: 1000), () {
    
    
            //1秒后进行递归
            startProcessingConversationQueue(
                Global.wsImConversationQueue.isNotEmpty);
            PrintUtil.prints(
                '$TAG 中台IM消息 === > 递归完成或者下一个递归');
          });
        }
      }
    } else {
    
    
      PrintUtil.prints('$TAG 中台IM消息 === > 消息处理完成');
      Global.wsImConversationQueueState = false;
    }
  }

  //判断会话ID是否在新会话列表里面,存在说明要等待这会话ID插入数据完成后才进行其他新会话的插入
  bool checkConversationId(String id) {
    
    
    bool check = false;
    for (int i = 0; i < Global.newConversationList.length; i++) {
    
    
      if (id == Global.newConversationList[i]) {
    
    
        check = true;
      }
    }
    PrintUtil.prints(
        '$TAG 中台IM消息 === > 会话列表第一个会话ID在不在新会话限制列表里面:${
    
    check}   新会话限制列表:${
    
    Global.newConversationList}');
    return check;
  }

  ///添加消息内容
  WsImMessage addWsImMessage(RecvChatMsg? recvChatMsg) {
    
    
    //默认会话ID是:收到谁消息就是谁的会话ID
    String conId = 'c2c_${
    
    recvChatMsg?.fromUserId.toInt()}';

    //如果发送者是自己,且接收者不是自己,则是服务器下发的消息,会话ID是对方
    if ('${
    
    recvChatMsg?.fromUserId.toInt()}' == Global.userId) {
    
    
      if ('${recvChatMsg?.toUserId.toInt()}' != Global.userId) {
    
    
        conId = 'c2c_${
    
    recvChatMsg?.toUserId.toInt()}';
      }
    }

    WsImMessage wsImMessage = WsImMessage(
        userId: int.parse(Global.userId),
        conversationId: conId,
        serverMsgId: recvChatMsg?.serverMsgId.toInt(),
        fromUserId: recvChatMsg?.fromUserId.toInt(),
        toUserId: recvChatMsg?.toUserId.toInt(),
        sendTime: recvChatMsg?.sendTime.toInt(),
        messageBody: WsImMessageBody.fromJson(utf8.decode(recvChatMsg!.body)),
        messageState: WsImMessageState.wsImMessageSendSuccess,
        isSelf: 0,
        isRead: 0);

    return wsImMessage;
  }

Guess you like

Origin blog.csdn.net/weixin_44911775/article/details/133862725
Recommended