All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.leancloud.im.v2.AVIMMessageManager Maven / Gradle / Ivy

package cn.leancloud.im.v2;

import cn.leancloud.AVLogger;
import cn.leancloud.im.AVIMOptions;
import cn.leancloud.im.v2.annotation.AVIMMessageType;
import cn.leancloud.im.v2.messages.*;
import cn.leancloud.utils.LogUtil;
import cn.leancloud.utils.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.lang.annotation.IncompleteAnnotationException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;

public class AVIMMessageManager {
  protected static final AVLogger LOGGER = LogUtil.getLogger(AVIMMessageManager.class);

  static Map> messageTypesRepository =
          new HashMap<>();
  static AVIMMessageHandler defaultMessageHandler;
  static ConcurrentMap, Set> messageHandlerRepository =
          new ConcurrentHashMap, Set>();

  static AVIMConversationEventHandler conversationEventHandler;

  static {
    registerAVIMMessageType(AVIMTextMessage.class);
    registerAVIMMessageType(AVIMFileMessage.class);
    registerAVIMMessageType(AVIMImageMessage.class);
    registerAVIMMessageType(AVIMAudioMessage.class);
    registerAVIMMessageType(AVIMVideoMessage.class);
    registerAVIMMessageType(AVIMLocationMessage.class);
    registerAVIMMessageType(AVIMRecalledMessage.class);
  }

  /**
   * 注册自定义的消息类型
   *
   * @param messageType message type.
   */
  public static void registerAVIMMessageType(Class messageType) {
    AVIMMessageType type = messageType.getAnnotation(AVIMMessageType.class);
    if (type == null) {
      throw new IncompleteAnnotationException(AVIMMessageType.class, "type");
    }
    int messageTypeValue = type.type();

    messageTypesRepository.put(messageTypeValue, messageType);
    try {
      Method initializeMethod = messageType.getDeclaredMethod("computeFieldAttribute", Class.class);
      initializeMethod.setAccessible(true);
      initializeMethod.invoke(null, messageType);
    } catch (Exception e) {
      LOGGER.d("failed to initialize message Fields");
    }
  }

  /**
   * 注册一般情况下的消息handler,只有在没有类型的AVIMMessage或者没有其他handler时才会被调用
   *
   * 请在Application初始化时设置
   *
   * @param handler message handler.
   */
  public static void registerDefaultMessageHandler(AVIMMessageHandler handler) {
    defaultMessageHandler = handler;
  }

  /**
   * 注册特定消息格式的处理单元
   *
   * @param clazz 特定的消息类
   * @param handler message handler.
   */
  public static void registerMessageHandler(Class clazz,
                                            MessageHandler handler) {
    Set handlerSet = new CopyOnWriteArraySet<>();

    Set set = messageHandlerRepository.putIfAbsent(clazz, handlerSet);
    if (set != null) {
      handlerSet = set;
    }
    handlerSet.add(handler);
  }

  /**
   * 取消特定消息格式的处理单元
   *
   * @param clazz message class.
   * @param handler message handler.
   */
  public static void unregisterMessageHandler(Class clazz,
                                              MessageHandler handler) {
    Set handlerSet = messageHandlerRepository.get(clazz);
    if (handlerSet != null) {
      handlerSet.remove(handler);
    }
  }

  /**
   * 设置Conversataion相关事件的处理单元,
   *
   * 推荐在Application初始化时设置
   *
   * @param handler message handler.
   */
  public static void setConversationEventHandler(AVIMConversationEventHandler handler) {
    conversationEventHandler = handler;
  }

  protected static AVIMConversationEventHandler getConversationEventHandler() {
    return conversationEventHandler;
  }

  protected static void processMessage(AVIMMessage message, int convType, AVIMClient client, boolean hasMore,
                                       boolean isTransient) {
    // 如果已经通过拉获得了消息,则推的消息不回调
    if (client.getStorage().containMessage(message)) {
      return;
    }
    // hasMore 才设为 breakpoint
    // LogUtil.log.i("hasMore = " + hasMore);\
    if (!isTransient && AVIMOptions.getGlobalOptions().isMessageQueryCacheEnabled()) {
      client.getStorage().insertMessage(message, hasMore);
    }
    message = parseTypedMessage(message);
    final AVIMConversation conversation = client.getConversation(message.getConversationId(), convType);
    conversation.setLastMessage(message);
    if (!isTransient) {
      conversation.increaseUnreadCount(1, message.mentioned());
    }
    conversation.setLastMessageAt(new Date(message.getTimestamp()));

    retrieveAllMessageHandlers(message, conversation, false, null);
  }

  protected static void processMessageReceipt(AVIMMessage message, AVIMClient client, String from) {
    client.getStorage().updateMessage(message, message.getMessageId());
    message = parseTypedMessage(message);
    final AVIMConversation conversation = client.getConversation(message.getConversationId());
    retrieveAllMessageHandlers(message, conversation, true, from);
  }

  private static void retrieveAllMessageHandlers(AVIMMessage message,
                                                 AVIMConversation conversation, boolean receipt, String operator) {
    boolean messageProcessed = false;
    for (Map.Entry, Set> entry : messageHandlerRepository.entrySet()) {
      if (entry.getKey().isAssignableFrom(message.getClass())) {
        Set handlers = entry.getValue();
        if (handlers.size() > 0) {
          messageProcessed = true;
        }
        for (MessageHandler handler : handlers) {
          if (receipt) {
            handler.processEvent(Conversation.STATUS_ON_MESSAGE_RECEIPTED, operator, message,
                    conversation);
          } else {
            handler.processEvent(Conversation.STATUS_ON_MESSAGE, operator, message,
                    conversation);
          }
        }

      }
    }
    if (!messageProcessed && defaultMessageHandler != null) {
      if (receipt) {
        defaultMessageHandler.processEvent(Conversation.STATUS_ON_MESSAGE_RECEIPTED, operator, message,
                conversation);
      } else {
        defaultMessageHandler.processEvent(Conversation.STATUS_ON_MESSAGE, operator, message,
                conversation);
      }
    }
  }

  /**
   * 解析AVIMMessage对象的子类
   *
   * @param message message
   * @return Return the instance of AVIMTypedMessage
   */
  protected static AVIMMessage parseTypedMessage(AVIMMessage message) {
    int messageType = getMessageType(message.getContent());
    if (messageType != 0) {
      Class clazz = messageTypesRepository.get(messageType);
      if (clazz != null) {
        try {
          AVIMMessage typedMessage = clazz.newInstance();
          typedMessage.setConversationId(message.getConversationId());
          typedMessage.setFrom(message.getFrom());
          typedMessage.setDeliveredAt(message.getDeliveredAt());
          typedMessage.setTimestamp(message.getTimestamp());
          typedMessage.setContent(message.getContent());
          typedMessage.setMessageId(message.getMessageId());
          typedMessage.setMessageStatus(message.getMessageStatus());
          typedMessage.setMessageIOType(message.getMessageIOType());
          typedMessage.uniqueToken = message.uniqueToken;
          typedMessage.currentClient = message.currentClient;
          typedMessage.mentionAll = message.mentionAll;
          typedMessage.mentionList = message.mentionList;
          message = typedMessage;
        } catch (Exception e) {
        }
      }
    }
    return message;
  }

  private static int getMessageType(String messageContent) {
    if (!StringUtil.isEmpty(messageContent)) {
      try {
        JSONObject object = JSON.parseObject(messageContent);
        int type = object.getInteger("_lctype");
        return type;
      } catch (Exception e) {
        LOGGER.d("Parsing json data failed and use default messageType 0. cause: " + e.getMessage());
      }
    }
    return 0;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy