|
@@ -0,0 +1,970 @@
|
|
|
+import {
|
|
|
+ ConversationType,
|
|
|
+ EventEmitter,
|
|
|
+ MessageDirection,
|
|
|
+ MessageType,
|
|
|
+ ReceivedStatus,
|
|
|
+ notEmptyString,
|
|
|
+ logger
|
|
|
+} from "@rongcloud/engine";
|
|
|
+import {
|
|
|
+ init,
|
|
|
+ connect,
|
|
|
+ disconnect,
|
|
|
+ addEventListener,
|
|
|
+ Events,
|
|
|
+ sendReadReceiptResponseV2,
|
|
|
+ recallMessage,
|
|
|
+ deleteMessages,
|
|
|
+ getServerTime,
|
|
|
+ sendMessage,
|
|
|
+ getCurrentUserId,
|
|
|
+ sendImageMessage,
|
|
|
+ ImageMessage,
|
|
|
+ FileMessage,
|
|
|
+ sendFileMessage,
|
|
|
+ clearMessagesUnreadStatus,
|
|
|
+ TextMessage,
|
|
|
+ ReferenceMessage,
|
|
|
+ saveTextMessageDraft,
|
|
|
+ registerMessageType
|
|
|
+} from "@rongcloud/imlib-next";
|
|
|
+import Service from "./service";
|
|
|
+import ConversationManager from "./conversation";
|
|
|
+import MessageManager from "./message";
|
|
|
+import { ConversationStore, LangStore } from "./storage";
|
|
|
+import { CoreEvent } from "./enum/event";
|
|
|
+import { Languages } from "./enum/languages";
|
|
|
+import { LogTagId } from "./enum/logEnums";
|
|
|
+import { file2Base64, getConversationKey, isEqual } from "./utils";
|
|
|
+// 需要排除的消息
|
|
|
+function isExcludeMessage(messageType) {
|
|
|
+ return ["RC:Delivered"].indexOf(messageType) !== -1;
|
|
|
+}
|
|
|
+function createMessageId() {
|
|
|
+ return ~~(Math.random() * 0xffffff);
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 是否初始化过
|
|
|
+ */
|
|
|
+let hasInit = false;
|
|
|
+class Core extends EventEmitter {
|
|
|
+ constructor() {
|
|
|
+ super();
|
|
|
+ /**
|
|
|
+ * 记录切换会话时的时间
|
|
|
+ */
|
|
|
+ this.switchTimes = {};
|
|
|
+ // 缓存已读回执
|
|
|
+ this.receiptRequstCache = [];
|
|
|
+ this._fileCache = {};
|
|
|
+ if (Core.INSTANCE) {
|
|
|
+ return Core.INSTANCE;
|
|
|
+ }
|
|
|
+ this.conversationManager = new ConversationManager();
|
|
|
+ this.messageManager = new MessageManager();
|
|
|
+ this._conversationStorage = new ConversationStore();
|
|
|
+ this._langStore = new LangStore();
|
|
|
+ Core.INSTANCE = this;
|
|
|
+ }
|
|
|
+ init(option) {
|
|
|
+ if (hasInit) {
|
|
|
+ logger.error(LogTagId.A_KIT_INIT_O, { msg: "禁止多次初始化!" });
|
|
|
+ }
|
|
|
+ if (!option.libOption || !notEmptyString(option.libOption.appkey)) {
|
|
|
+ logger.error(LogTagId.A_KIT_INIT_O, {
|
|
|
+ msg: "参数错误:libOption.appkey 为必传字段!",
|
|
|
+ data: option
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this._appkey = option.libOption.appkey;
|
|
|
+ // 初始化 imlib
|
|
|
+ init(option.libOption);
|
|
|
+ option.conversationPullCount = option.conversationPullCount
|
|
|
+ ? option.conversationPullCount
|
|
|
+ : 30;
|
|
|
+ this.conversationManager.setPullCount({
|
|
|
+ pullCount: option.conversationPullCount
|
|
|
+ });
|
|
|
+ this.customMessage = option.customMessage;
|
|
|
+ this.service = new Service(option.service);
|
|
|
+ // 注册消息
|
|
|
+ this.setListener();
|
|
|
+ hasInit = true;
|
|
|
+ // 初始化完毕
|
|
|
+ this.emit(CoreEvent.INIT);
|
|
|
+ }
|
|
|
+ connect(token, reconnectKickEnable) {
|
|
|
+ return connect(
|
|
|
+ token,
|
|
|
+ reconnectKickEnable
|
|
|
+ );
|
|
|
+ }
|
|
|
+ disconnect() {
|
|
|
+ // 清除当前用户内存态数据
|
|
|
+ this.conversationManager.clearLocalConversation();
|
|
|
+ this.messageManager.clearLocalConversation();
|
|
|
+ this.service.clearMyProfileCache();
|
|
|
+ return disconnect();
|
|
|
+ }
|
|
|
+ getTime() {
|
|
|
+ if (!this.startLocalTime || this.startServerTime) {
|
|
|
+ this.startLocalTime = Date.now();
|
|
|
+ this.startServerTime = getServerTime();
|
|
|
+ }
|
|
|
+ return Date.now() - this.startLocalTime + this.startServerTime;
|
|
|
+ }
|
|
|
+ get currentConversation() {
|
|
|
+ return this._currentConversation;
|
|
|
+ }
|
|
|
+ set currentConversation(conversation) {
|
|
|
+ this._currentConversation = conversation;
|
|
|
+ }
|
|
|
+ setListener() {
|
|
|
+ addEventListener(Events.CONNECTED, () => {
|
|
|
+ this._currentUsreId = getCurrentUserId();
|
|
|
+ this._conversationStorage.init(this._appkey, this._currentUsreId);
|
|
|
+ this._langStore.init(this._appkey, this._currentUsreId);
|
|
|
+ this.emit(CoreEvent.CONNECTED, true);
|
|
|
+ this.emit(CoreEvent.LANGUAGE_CHANGED, { lang: this.lang });
|
|
|
+ });
|
|
|
+ addEventListener(Events.DISCONNECT, () => {
|
|
|
+ this.currentConversation = null;
|
|
|
+ this.emit(CoreEvent.SWITCH_CONVERSATION, this.currentConversation);
|
|
|
+ this.emit(CoreEvent.CONNECTED, false);
|
|
|
+ });
|
|
|
+ addEventListener(Events.CONVERSATION, event => {
|
|
|
+ logger.info(LogTagId.A_KIT_CONVERSATION_LISTENER_S, event);
|
|
|
+ let updatedConversationList = event.conversationList;
|
|
|
+ // 将用户要自己接管的会话排除掉
|
|
|
+ if (
|
|
|
+ this.customIntercept &&
|
|
|
+ typeof this.customIntercept.interceptConversation === "function"
|
|
|
+ ) {
|
|
|
+ updatedConversationList = updatedConversationList.filter(one => {
|
|
|
+ const isMatch = this.customIntercept.interceptConversation(
|
|
|
+ one.conversation
|
|
|
+ );
|
|
|
+ return !isMatch;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 会话更新可能是由一些消息触发的
|
|
|
+ updatedConversationList = updatedConversationList.filter(one => {
|
|
|
+ if (
|
|
|
+ one.updatedItems &&
|
|
|
+ one.updatedItems.latestMessage &&
|
|
|
+ one.updatedItems.latestMessage.val
|
|
|
+ ) {
|
|
|
+ const messageType = one.updatedItems.latestMessage.val.messageType;
|
|
|
+ return !isExcludeMessage(messageType);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ if (updatedConversationList.length) {
|
|
|
+ this.conversationManager.update(updatedConversationList);
|
|
|
+ this.emit(CoreEvent.CONVERSATION, updatedConversationList);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ addEventListener(Events.MESSAGES, event => {
|
|
|
+ logger.info(LogTagId.A_KIT_MESSAGE_LISTENER_S, event);
|
|
|
+ let messages = event.messages;
|
|
|
+ // 收到的新消息读取状态在sdk中已经被置为已读,需要重置回未读
|
|
|
+ messages.forEach(message => {
|
|
|
+ if (message.conversationType === ConversationType.PRIVATE) {
|
|
|
+ if (message.receivedStatus === ReceivedStatus.READ) {
|
|
|
+ message.receivedStatus = ReceivedStatus.UNREAD;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 将用户要接管的消息全部排除
|
|
|
+ if (
|
|
|
+ this.customIntercept &&
|
|
|
+ typeof this.customIntercept.interceptMessage === "function"
|
|
|
+ ) {
|
|
|
+ messages = messages.filter(message => {
|
|
|
+ const isMatch = this.customIntercept.interceptMessage(message);
|
|
|
+ return !isMatch;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 用户处理消息【供客户对消息进行加解密操作】
|
|
|
+ if (
|
|
|
+ this.customDisplayMessage &&
|
|
|
+ this.customDisplayMessage.willDisplayMessages &&
|
|
|
+ typeof this.customDisplayMessage.willDisplayMessages === "function"
|
|
|
+ ) {
|
|
|
+ messages = messages.map(message => {
|
|
|
+ let content = this.customDisplayMessage.willDisplayMessages(
|
|
|
+ message.content,
|
|
|
+ message.conversationType,
|
|
|
+ message.targetId,
|
|
|
+ message.messageType
|
|
|
+ );
|
|
|
+ message.content = content;
|
|
|
+ return message;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ messages = messages.filter(message => {
|
|
|
+ return !isExcludeMessage(message.messageType);
|
|
|
+ });
|
|
|
+ if (!messages.length) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const localMessages = this.messageManager.setLocalMessages(messages);
|
|
|
+ // 收到新消息后,需要判断这些消息中是否有对应当前选中会话的消息
|
|
|
+ if (this.currentConversation && localMessages.new.length) {
|
|
|
+ this.emit(CoreEvent.MESSAGES, localMessages.new);
|
|
|
+ }
|
|
|
+ if (localMessages.remove && localMessages.remove.length) {
|
|
|
+ this.emit(CoreEvent.DELETE_MESSAGE, localMessages.remove);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ addEventListener(Events.PULL_OFFLINE_MESSAGE_FINISHED, () => {
|
|
|
+ this.emit(CoreEvent.PULL_OFFLINE_MESSAGE_FINISHED);
|
|
|
+ });
|
|
|
+ addEventListener(Events.TYPING_STATUS, event => {
|
|
|
+ this.emit(CoreEvent.TYPING_STATUS, event);
|
|
|
+ });
|
|
|
+ // 收到单聊已读回执
|
|
|
+ addEventListener(Events.READ_RECEIPT_RECEIVED, event => {
|
|
|
+ const { conversation, sentTime } = event;
|
|
|
+ const conversationResult = this.conversationManager.findConversation(
|
|
|
+ conversation
|
|
|
+ );
|
|
|
+ if (conversationResult) {
|
|
|
+ const targetConversation =
|
|
|
+ conversationResult.source[conversationResult.index];
|
|
|
+ // 判断是否为最后一条消息,更新会话的latestMessage
|
|
|
+ const latestMessage = targetConversation.latestMessage;
|
|
|
+ if (latestMessage.sentTime && latestMessage.sentTime === sentTime) {
|
|
|
+ this.conversationManager.update([
|
|
|
+ {
|
|
|
+ conversation: targetConversation,
|
|
|
+ updatedItems: {
|
|
|
+ latestMessage: {
|
|
|
+ time: Date.now(),
|
|
|
+ val: {
|
|
|
+ ...latestMessage,
|
|
|
+ receivedStatus: ReceivedStatus.READ
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ // 抛出会话更新通知
|
|
|
+ this.emit(CoreEvent.CONVERSATION, targetConversation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 更新本地消息数据中的对应消息
|
|
|
+ const messages = this.messageManager.getLocalMessage(conversation, 0, 0);
|
|
|
+ const index = messages.list.findIndex(one => one.sentTime === sentTime);
|
|
|
+ if (index !== -1) {
|
|
|
+ // const message = {
|
|
|
+ // ...messages.list[index],
|
|
|
+ // };
|
|
|
+ messages.list.forEach(message => {
|
|
|
+ message.receivedStatus = ReceivedStatus.READ;
|
|
|
+ this.messageManager.updateMessage(message);
|
|
|
+ this.emit(CoreEvent.UPDATE_MESSAGE, message);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 更新单聊已读状态
|
|
|
+ this._conversationStorage.updateUnReadTime(
|
|
|
+ sentTime,
|
|
|
+ conversation.conversationType,
|
|
|
+ conversation.targetId,
|
|
|
+ conversation.channelId
|
|
|
+ );
|
|
|
+ this.emit(CoreEvent.READ_RECEIPT_RECEIVED, event);
|
|
|
+ });
|
|
|
+ // 收到群组已读回执请求
|
|
|
+ addEventListener(Events.MESSAGE_RECEIPT_REQUEST, event => {
|
|
|
+ const { conversation, messageUId } = event;
|
|
|
+ if (isEqual(this.currentConversation, conversation)) {
|
|
|
+ // 既是当前会话, 则直接抛出收到的数据通知UI端
|
|
|
+ this.emit(CoreEvent.MESSAGE_RECEIPT_REQUEST, event);
|
|
|
+ } else {
|
|
|
+ const key = getConversationKey(conversation);
|
|
|
+ if (this.switchTimes[key]) {
|
|
|
+ const messages = this.messageManager.getLocalMessage(
|
|
|
+ conversation,
|
|
|
+ 0,
|
|
|
+ 0
|
|
|
+ );
|
|
|
+ // 方案并不完美,在消息量较大的情况下,由于内存中存储的消息量较少,可能会造成查不到之前的消息
|
|
|
+ const index = messages.list.findIndex(message => {
|
|
|
+ return (
|
|
|
+ message.messageUId === messageUId &&
|
|
|
+ message.receivedTime < this.switchTimes[key]
|
|
|
+ );
|
|
|
+ });
|
|
|
+ if (index === -1) {
|
|
|
+ // 将其进行缓存,待切换会话时传给消息列表
|
|
|
+ this.receiptRequstCache.push(event);
|
|
|
+ } else {
|
|
|
+ // 表示已经读过这条消息,直接发送已读响应
|
|
|
+ sendReadReceiptResponseV2(
|
|
|
+ conversation.targetId,
|
|
|
+ {
|
|
|
+ [event.senderUserId]: [event.messageUId]
|
|
|
+ },
|
|
|
+ conversation.channelId
|
|
|
+ );
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 将其进行缓存,待切换会话时传给消息列表
|
|
|
+ this.receiptRequstCache.push(event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 收到群聊已读回执响应
|
|
|
+ addEventListener(Events.MESSAGE_RECEIPT_RESPONSE, event => {
|
|
|
+ this.emit(CoreEvent.MESSAGE_RECEIPT_RESPONSE, event);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ createConversation(conversation) {
|
|
|
+ return this.conversationManager.create(conversation);
|
|
|
+ }
|
|
|
+ deleteConversation(conversation) {
|
|
|
+ this.currentConversation = null;
|
|
|
+ this.emit(CoreEvent.SWITCH_CONVERSATION, this.currentConversation);
|
|
|
+ return this.conversationManager.remove(conversation);
|
|
|
+ }
|
|
|
+ setConversationToTop(option, status) {
|
|
|
+ return this.conversationManager.changeTopStatus(option, status);
|
|
|
+ }
|
|
|
+ setConversationNotificationStatus(option, status) {
|
|
|
+ return this.conversationManager.changeNotificationStatus(option, status);
|
|
|
+ }
|
|
|
+ referenceMessage(message) {
|
|
|
+ this.emit(CoreEvent.REFERENCE_MESSAGE, message);
|
|
|
+ }
|
|
|
+ recallMessage(message) {
|
|
|
+ recallMessage(
|
|
|
+ {
|
|
|
+ conversationType: message.conversationType,
|
|
|
+ targetId: message.targetId,
|
|
|
+ channelId: message.channelId
|
|
|
+ },
|
|
|
+ {
|
|
|
+ messageUId: message.messageUId,
|
|
|
+ sentTime: message.sentTime
|
|
|
+ }
|
|
|
+ ).then(res => {
|
|
|
+ if (res.code !== 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const result = this.messageManager.recallMessage(message);
|
|
|
+ if (result) {
|
|
|
+ this.emit(CoreEvent.UPDATE_MESSAGE, result);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ deleteMessage(message) {
|
|
|
+ deleteMessages(
|
|
|
+ {
|
|
|
+ conversationType: message.conversationType,
|
|
|
+ targetId: message.targetId,
|
|
|
+ channelId: message.channelId
|
|
|
+ },
|
|
|
+ [
|
|
|
+ {
|
|
|
+ messageUId: message.messageUId,
|
|
|
+ sentTime: message.sentTime,
|
|
|
+ messageDirection: message.messageDirection
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ ).then(res => {
|
|
|
+ if (res.code !== 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const result = this.messageManager.deleteMessage(message);
|
|
|
+ if (result) {
|
|
|
+ this.emit(CoreEvent.DELETE_MESSAGE, [message]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ registerMessageType(
|
|
|
+ messageType,
|
|
|
+ isPersited,
|
|
|
+ isCounted,
|
|
|
+ prototypes,
|
|
|
+ isStatusMessage
|
|
|
+ ) {
|
|
|
+ return registerMessageType(
|
|
|
+ messageType,
|
|
|
+ isPersited,
|
|
|
+ isCounted,
|
|
|
+ prototypes,
|
|
|
+ isStatusMessage
|
|
|
+ );
|
|
|
+ }
|
|
|
+ getConversationProfile(conversationOption) {
|
|
|
+ return this.service
|
|
|
+ .getConversationProfile([conversationOption])
|
|
|
+ .then(res => {
|
|
|
+ if (!res || !res.length) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return res[0];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ getConversationList(more = false) {
|
|
|
+ return this.conversationManager
|
|
|
+ .getList(more, this._conversationStorage)
|
|
|
+ .then(conversationList => {
|
|
|
+ // 整理出每个会话的三个属性
|
|
|
+ const conversationOptions = conversationList.map(conversation => {
|
|
|
+ return {
|
|
|
+ conversationType: conversation.conversationType,
|
|
|
+ targetId: conversation.targetId,
|
|
|
+ channelId: conversation.channelId
|
|
|
+ };
|
|
|
+ });
|
|
|
+ return this.service
|
|
|
+ .getConversationProfile(conversationOptions)
|
|
|
+ .then(profileList => {
|
|
|
+ // 将会话列表和profile合并
|
|
|
+ return conversationList.map(conversation => {
|
|
|
+ return {
|
|
|
+ conversation,
|
|
|
+ profile: profileList.find(profile => {
|
|
|
+ if (profile) {
|
|
|
+ if (isEqual(profile, conversation)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ })
|
|
|
+ };
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ return conversationList.map(conversation => {
|
|
|
+ return {
|
|
|
+ conversation
|
|
|
+ };
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ getMyProfile() {
|
|
|
+ const id = getCurrentUserId();
|
|
|
+ if (!id) {
|
|
|
+ throw new Error("Unable to get the current user ID.");
|
|
|
+ }
|
|
|
+ return this.service.getUserProfile(id);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 判断消息是否为用户类自定义消息
|
|
|
+ * @param message IAReceivedMessage
|
|
|
+ * @returns boolean
|
|
|
+ */
|
|
|
+ isCustomUserMessage(message) {
|
|
|
+ if (!this.customMessage) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const customUserMessage = this.customMessage.userMessage;
|
|
|
+ return (
|
|
|
+ customUserMessage && customUserMessage[message.messageType] !== undefined
|
|
|
+ );
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 生成自定义的用户类消息 message内容
|
|
|
+ * @param message
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+ createCustomUserMessageDom(message) {
|
|
|
+ console.log(message, "createCustomUserMessageDom");
|
|
|
+ if (!this.customMessage) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ const customUserMessage = this.customMessage.userMessage;
|
|
|
+ if (customUserMessage) {
|
|
|
+ return customUserMessage[message.messageType](message);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 判断消息是否为通知类自定义消息
|
|
|
+ * @param message IAReceivedMessage
|
|
|
+ * @returns boolean
|
|
|
+ */
|
|
|
+ isCustomNotifyMessage(message) {
|
|
|
+ if (!this.customMessage) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const customNotifyMessage = this.customMessage.notifyMessage;
|
|
|
+ return (
|
|
|
+ customNotifyMessage &&
|
|
|
+ customNotifyMessage[message.messageType] !== undefined
|
|
|
+ );
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 生成自定义的通知类消息的message内容
|
|
|
+ * @param message
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+ createCustomNotifyMessageDom(message) {
|
|
|
+ if (!this.customMessage) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const customNotifyMessage = this.customMessage.notifyMessage;
|
|
|
+ if (customNotifyMessage) {
|
|
|
+ return customNotifyMessage[message.messageType](message);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 判断消息是传递会话 lastmessage 展示描述
|
|
|
+ * @param message IAReceivedMessage
|
|
|
+ * @returns boolean
|
|
|
+ */
|
|
|
+ isCustomLastMessage(message) {
|
|
|
+ if (!this.customMessage) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const customUserMessage = this.customMessage.lastMessage;
|
|
|
+ return (
|
|
|
+ customUserMessage && customUserMessage[message.messageType] !== undefined
|
|
|
+ );
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 生成自定义的通知类消息的message内容
|
|
|
+ * @param message
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+ createCustomLastMessageDom(message) {
|
|
|
+ if (!this.customMessage) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const customNotifyMessage = this.customMessage.lastMessage;
|
|
|
+ if (customNotifyMessage) {
|
|
|
+ return customNotifyMessage[message.messageType](message);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ clearMessagesUnreadStatus(conversation) {
|
|
|
+ clearMessagesUnreadStatus(conversation);
|
|
|
+ // 因为在开发过程中,发现清理未读数后,发现sdk并没有发出conversation事件,因此需要手动更新
|
|
|
+ this.conversationManager.update([
|
|
|
+ {
|
|
|
+ conversation,
|
|
|
+ updatedItems: {
|
|
|
+ unreadMessageCount: {
|
|
|
+ time: Date.now(),
|
|
|
+ val: 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ this.emit(CoreEvent.UPDATE_CONVERSATION, [
|
|
|
+ { ...conversation, unreadMessageCount: 0 }
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ saveTextMessageDraft(conversation, content) {
|
|
|
+ saveTextMessageDraft(conversation, content).then(res => {
|
|
|
+ // 保存成功
|
|
|
+ if (res.code === 0) {
|
|
|
+ this.emit(CoreEvent.SWITCH_CONVERSATION, this.currentConversation);
|
|
|
+ } else {
|
|
|
+ // 草稿保存失败
|
|
|
+ console.log(res.code, res.msg);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param conversation 会话
|
|
|
+ * @param start 开始时间,默认从最新一条的时间开始
|
|
|
+ * @param count 获取数量,默认20条
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+ getMessages(conversation, startTime = 0, count = 20) {
|
|
|
+ const unReadTime = this._conversationStorage.getUnReadTime(
|
|
|
+ conversation.conversationType,
|
|
|
+ conversation.targetId,
|
|
|
+ conversation.channelId
|
|
|
+ );
|
|
|
+ return this.messageManager.getMessages(
|
|
|
+ conversation,
|
|
|
+ startTime,
|
|
|
+ count,
|
|
|
+ unReadTime
|
|
|
+ );
|
|
|
+ }
|
|
|
+ getGroupMemberProfile(conversationOption, userId) {
|
|
|
+ if (conversationOption.conversationType === ConversationType.GROUP) {
|
|
|
+ if (!userId) return null;
|
|
|
+ return this.service.getGroupMembers(conversationOption).then(members => {
|
|
|
+ const index = members.findIndex(member => member.id === userId);
|
|
|
+ if (index !== -1) {
|
|
|
+ return members[index];
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ getGroupMembers(conversation) {
|
|
|
+ return this.service.getGroupMembers(conversation);
|
|
|
+ }
|
|
|
+ selectConversation(conversation) {
|
|
|
+ console.log(conversation, "selectConversation");
|
|
|
+ console.log(this.currentConversation, "this.currentConversation");
|
|
|
+ if (
|
|
|
+ this.currentConversation &&
|
|
|
+ isEqual(this.currentConversation, conversation)
|
|
|
+ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 如果会话不存在,则主动创建
|
|
|
+ if (!this.conversationManager.findConversation(conversation)) {
|
|
|
+ this.createConversation(conversation);
|
|
|
+ this.emit(CoreEvent.CONVERSATION, this.currentConversation);
|
|
|
+ }
|
|
|
+ // 存储当前切换的时间
|
|
|
+ if (this.currentConversation) {
|
|
|
+ const key = getConversationKey(this.currentConversation);
|
|
|
+ this.switchTimes[key] = this.getTime();
|
|
|
+ // 截取当前会话下消息列表的长度,只保留最新的100条
|
|
|
+ this.messageManager.cutMessages();
|
|
|
+ }
|
|
|
+ this.currentConversation = conversation;
|
|
|
+ this.messageManager.currentConversation = this.currentConversation;
|
|
|
+ this.emit(CoreEvent.SWITCH_CONVERSATION, this.currentConversation);
|
|
|
+ this.receiptRequstCache.forEach(one => {
|
|
|
+ // 切换会话的时候,直接将回执通知UI层处理
|
|
|
+ if (isEqual(one.conversation, this.currentConversation)) {
|
|
|
+ this.emit(CoreEvent.MESSAGE_RECEIPT_REQUEST, one);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ getConversation(option) {
|
|
|
+ const result = this.conversationManager.findConversation(option);
|
|
|
+ if (result && result.index !== -1) {
|
|
|
+ return this.service.getConversationProfile([option]).then(profileList => {
|
|
|
+ const profile = profileList[0];
|
|
|
+ return { conversation: result.source[result.index], profile };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return Promise.resolve(null);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 发送文本消息
|
|
|
+ * 在各个阶段,会抛出不同的事件
|
|
|
+ * @param conversation
|
|
|
+ * @param message
|
|
|
+ * @param option
|
|
|
+ */
|
|
|
+ sendMessage(conversation, message, option) {
|
|
|
+ const messageId = createMessageId();
|
|
|
+ // const preMessage = Object.assign({},message);
|
|
|
+ const messageContent = message.content;
|
|
|
+ let preMessage = message;
|
|
|
+ // 发送的是引用消息,则抛出关闭引用消息窗口
|
|
|
+ if (message.messageType === MessageType.REFERENCE) {
|
|
|
+ this.emit(CoreEvent.CLOSE_REFERENCE);
|
|
|
+ preMessage = new ReferenceMessage(Object.assign({}, messageContent));
|
|
|
+ }
|
|
|
+ if (message.messageType === MessageType.TextMessage) {
|
|
|
+ preMessage = new TextMessage({ content: messageContent.content });
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ message.messageType === MessageType.TextMessage ||
|
|
|
+ message.messageType === MessageType.REFERENCE
|
|
|
+ ) {
|
|
|
+ message.content = this._willSendMessage(
|
|
|
+ message.content,
|
|
|
+ conversation.conversationType,
|
|
|
+ conversation.targetId,
|
|
|
+ message.messageType
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return this.decorateMessage(
|
|
|
+ conversation,
|
|
|
+ messageId,
|
|
|
+ preMessage,
|
|
|
+ sendMessage(conversation, message, option)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ sendImageMessage(conversationOption, msgBody, hooks, options) {
|
|
|
+ // 使用闭包的方式保存messageId,方便消息回来后调用
|
|
|
+ const messageId = createMessageId();
|
|
|
+ this._fileCache[messageId] = msgBody;
|
|
|
+ const decorate = base64 => {
|
|
|
+ msgBody = this._willSendMessage(
|
|
|
+ msgBody,
|
|
|
+ conversationOption.conversationType,
|
|
|
+ conversationOption.targetId,
|
|
|
+ MessageType.IMAGE
|
|
|
+ );
|
|
|
+ return this.decorateMessage(
|
|
|
+ conversationOption,
|
|
|
+ messageId,
|
|
|
+ new ImageMessage({
|
|
|
+ content: base64,
|
|
|
+ imageUri: ""
|
|
|
+ }),
|
|
|
+ sendImageMessage(
|
|
|
+ conversationOption,
|
|
|
+ msgBody,
|
|
|
+ {
|
|
|
+ onProgress: progress => {
|
|
|
+ this.emit(CoreEvent.UPLOAD_PROGRESS, {
|
|
|
+ messageId,
|
|
|
+ progress
|
|
|
+ });
|
|
|
+ if (typeof hooks.onProgress === "function") {
|
|
|
+ hooks.onProgress(progress);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onComplete: fileInfo => {
|
|
|
+ this.emit(CoreEvent.UPLOAD_COMPLETE, {
|
|
|
+ messageId,
|
|
|
+ fileInfo
|
|
|
+ });
|
|
|
+ if (typeof hooks.onComplete === "function") {
|
|
|
+ hooks.onComplete(fileInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ options
|
|
|
+ )
|
|
|
+ );
|
|
|
+ };
|
|
|
+ return file2Base64(msgBody.file)
|
|
|
+ .then(base64 => {
|
|
|
+ decorate(base64);
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ decorate("");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ sendFileMessage(conversationOption, msgBody, hooks, options) {
|
|
|
+ const messageId = createMessageId();
|
|
|
+ const file = msgBody.file;
|
|
|
+ this._fileCache[messageId] = file;
|
|
|
+ msgBody = this._willSendMessage(
|
|
|
+ msgBody,
|
|
|
+ conversationOption.conversationType,
|
|
|
+ conversationOption.targetId,
|
|
|
+ MessageType.FILE
|
|
|
+ );
|
|
|
+ return this.decorateMessage(
|
|
|
+ conversationOption,
|
|
|
+ messageId,
|
|
|
+ new FileMessage({
|
|
|
+ name: file.name,
|
|
|
+ size: file.size,
|
|
|
+ type: file.type,
|
|
|
+ fileUrl: ""
|
|
|
+ }),
|
|
|
+ sendFileMessage(
|
|
|
+ conversationOption,
|
|
|
+ msgBody,
|
|
|
+ {
|
|
|
+ onProgress: progress => {
|
|
|
+ this.emit(CoreEvent.UPLOAD_PROGRESS, {
|
|
|
+ messageId,
|
|
|
+ progress
|
|
|
+ });
|
|
|
+ if (typeof hooks.onProgress === "function") {
|
|
|
+ hooks.onProgress(progress);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onComplete: fileInfo => {
|
|
|
+ this.emit(CoreEvent.UPLOAD_COMPLETE, {
|
|
|
+ messageId,
|
|
|
+ fileInfo
|
|
|
+ });
|
|
|
+ if (typeof hooks.onComplete === "function") {
|
|
|
+ hooks.onComplete(fileInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ options
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+ resendMessage(conversation, message) {
|
|
|
+ // 删除之前失败消息
|
|
|
+ this.messageManager.deleteMessage(message);
|
|
|
+ this.emit(CoreEvent.DELETE_MESSAGE, [message]);
|
|
|
+ let newMessage = null;
|
|
|
+ const content = message.content;
|
|
|
+ switch (message.messageType) {
|
|
|
+ case "RC:TxtMsg":
|
|
|
+ let option = null;
|
|
|
+ if (content.mentionedInfo) {
|
|
|
+ option = content.mentionedInfo;
|
|
|
+ option.isMentioned = true;
|
|
|
+ }
|
|
|
+ newMessage = new TextMessage({ content: content.content });
|
|
|
+ this.sendMessage(conversation, newMessage, option);
|
|
|
+ break;
|
|
|
+ case "RC:ImgMsg":
|
|
|
+ const imgFile = this._fileCache[message.messageId];
|
|
|
+ this.sendImageMessage(conversation, imgFile, {
|
|
|
+ onProgress: () => {},
|
|
|
+ onComplete: () => {}
|
|
|
+ });
|
|
|
+ delete this._fileCache[message.messageId];
|
|
|
+ break;
|
|
|
+ case "RC:FileMsg":
|
|
|
+ const file = this._fileCache[message.messageId];
|
|
|
+ this.sendFileMessage(
|
|
|
+ conversation,
|
|
|
+ { file },
|
|
|
+ {
|
|
|
+ onProgress: () => {},
|
|
|
+ onComplete: () => {}
|
|
|
+ }
|
|
|
+ );
|
|
|
+ delete this._fileCache[message.messageId];
|
|
|
+ break;
|
|
|
+ case "RC:ReferenceMsg":
|
|
|
+ newMessage = new ReferenceMessage({
|
|
|
+ referMsgUserId: content.referMsgUserId,
|
|
|
+ referMsg: content.referMsg,
|
|
|
+ content: content.content,
|
|
|
+ objName: content.objName
|
|
|
+ });
|
|
|
+ this.sendMessage(conversation, newMessage, option);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 消息发送前回调
|
|
|
+ * willSendMessage 初始化时有客户传递
|
|
|
+ * @param content
|
|
|
+ * @param conversationType
|
|
|
+ * @param targetId
|
|
|
+ * @param messageType
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+ _willSendMessage(content, conversationType, targetId, messageType) {
|
|
|
+ if (
|
|
|
+ this.customDisplayMessage &&
|
|
|
+ this.customDisplayMessage.willSendMessage &&
|
|
|
+ typeof this.customDisplayMessage.willSendMessage === "function"
|
|
|
+ ) {
|
|
|
+ content = this.customDisplayMessage.willSendMessage(
|
|
|
+ content,
|
|
|
+ conversationType,
|
|
|
+ targetId,
|
|
|
+ messageType
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 发送消息的装饰器
|
|
|
+ * @param conversationOption
|
|
|
+ * @param messageId
|
|
|
+ * @param messageBody
|
|
|
+ * @param action
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+ decorateMessage(conversationOption, messageId, messageBody, action) {
|
|
|
+ // 构建显示用的临时消息
|
|
|
+ const tempMessage = {
|
|
|
+ targetId: conversationOption.targetId,
|
|
|
+ channelId: conversationOption.channelId,
|
|
|
+ conversationType: conversationOption.conversationType,
|
|
|
+ messageType: messageBody.messageType,
|
|
|
+ content: messageBody.content,
|
|
|
+ sentTime: Date.now(),
|
|
|
+ messageDirection: MessageDirection.SEND,
|
|
|
+ senderUserId: getCurrentUserId(),
|
|
|
+ receivedTime: undefined,
|
|
|
+ isPersited: messageBody.isPersited,
|
|
|
+ isCounted: messageBody.isCounted,
|
|
|
+ messageUId: "sending_" + messageId,
|
|
|
+ isOffLineMessage: false,
|
|
|
+ canIncludeExpansion: false,
|
|
|
+ receivedStatus: ReceivedStatus.UNREAD,
|
|
|
+ messageId
|
|
|
+ };
|
|
|
+ // 插入临时消息
|
|
|
+ this.messageManager.insertMessage(tempMessage);
|
|
|
+ // 发出增加消息的事件
|
|
|
+ this.emit(CoreEvent.MESSAGES, [tempMessage]);
|
|
|
+ // 更新会话的最后一条消息
|
|
|
+ const findResult = this.conversationManager.findConversation(
|
|
|
+ conversationOption
|
|
|
+ );
|
|
|
+ let resultConversation = null;
|
|
|
+ if (findResult) {
|
|
|
+ resultConversation = findResult.source[findResult.index];
|
|
|
+ const updatedConversation = {
|
|
|
+ conversation: resultConversation,
|
|
|
+ updatedItems: {
|
|
|
+ latestMessage: {
|
|
|
+ time: Date.now(),
|
|
|
+ val: tempMessage
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ this.conversationManager.update([updatedConversation]);
|
|
|
+ this.emit(CoreEvent.UPDATE_CONVERSATION, [
|
|
|
+ { ...resultConversation, latestMessage: tempMessage }
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ // 发出正在发送的事件通知
|
|
|
+ this.emit(CoreEvent.MESSAGE_SENDING, tempMessage);
|
|
|
+ // 发送消息
|
|
|
+ return action.then(res => {
|
|
|
+ const message = res.data ? res.data : tempMessage;
|
|
|
+ message.messageId = messageId;
|
|
|
+ if (message && message.content) {
|
|
|
+ // 发送成功调用 willDisplayMessages 处理消息
|
|
|
+ if (
|
|
|
+ this.customDisplayMessage &&
|
|
|
+ this.customDisplayMessage.willDisplayMessages &&
|
|
|
+ typeof this.customDisplayMessage.willDisplayMessages === "function"
|
|
|
+ ) {
|
|
|
+ message.content = this.customDisplayMessage.willDisplayMessages(
|
|
|
+ message.content,
|
|
|
+ message.conversationType,
|
|
|
+ message.targetId,
|
|
|
+ message.messageType
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (res.code === 0) {
|
|
|
+ // 发送成功后 imlib 会自动通知会话更新
|
|
|
+ // 只需要更新消息列表
|
|
|
+ this.messageManager.updateMessage(message);
|
|
|
+ // 消息发送成功的事件通知
|
|
|
+ this.emit(CoreEvent.MESSAGE_SEND_SUCCESS, message);
|
|
|
+ delete this._fileCache[message.messageId];
|
|
|
+ } else {
|
|
|
+ // 发送失败后,更新会话列表
|
|
|
+ if (findResult) {
|
|
|
+ // const resultConversation = findResult.source[findResult.index];
|
|
|
+ // 由于消息发送失败, messageUId为空,借用这个字段标志消息状态
|
|
|
+ message.messageUId = "fail_" + message.messageId;
|
|
|
+ const updatedConversation = {
|
|
|
+ conversation: resultConversation,
|
|
|
+ updatedItems: {
|
|
|
+ latestMessage: {
|
|
|
+ time: Date.now(),
|
|
|
+ val: message
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ this.conversationManager.update([updatedConversation]);
|
|
|
+ this.emit(CoreEvent.UPDATE_CONVERSATION, [
|
|
|
+ { ...resultConversation, latestMessage: message }
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ this.messageManager.updateMessage(message);
|
|
|
+ // 消息发送失败的事件通知
|
|
|
+ this.emit(CoreEvent.MESSAGE_SEND_FAIL, message);
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default new Core();
|