react-native-agora-chat
Version:
react native chat sdk
1,459 lines (1,405 loc) • 125 kB
text/typescript
import type { NativeEventEmitter } from 'react-native';
import { BaseManager } from './__internal__/Base';
import {
MTackConversationRead,
MTackGroupMessageRead,
MTackMessageRead,
MTaddReaction,
MTaddRemoteAndLocalConversationsMark,
MTasyncFetchGroupAcks,
MTclearAllMessages,
MTcreateChatThread,
MTdeleteAllMessageAndConversation,
MTdeleteConversation,
MTdeleteMessagesBeforeTimestamp,
MTdeleteMessagesWithTs,
MTdeleteRemoteAndLocalConversationsMark,
MTdeleteRemoteConversation,
MTdestroyChatThread,
MTdownloadAndParseCombineMessage,
MTdownloadAttachment,
MTdownloadAttachmentInCombine,
MTdownloadThumbnail,
MTdownloadThumbnailInCombine,
MTfetchChatThreadDetail,
MTfetchChatThreadMember,
MTfetchChatThreadsWithParentId,
MTfetchConversationsByOptions,
MTfetchConversationsFromServerWithPage,
MTfetchHistoryMessages,
MTfetchHistoryMessagesByOptions,
MTfetchJoinedChatThreads,
MTfetchJoinedChatThreadsWithParentId,
MTfetchLastMessageWithChatThreads,
MTfetchPinnedMessages,
MTfetchReactionDetail,
MTfetchReactionList,
MTfetchSupportLanguages,
MTgetConversation,
MTgetConversationsFromServer,
MTgetConversationsFromServerWithCursor,
MTgetLatestMessage,
MTgetLatestMessageFromOthers,
MTgetMessage,
MTgetMessageThread,
MTgetMsgCount,
MTgetPinInfo,
MTgetPinnedConversationsFromServerWithCursor,
MTgetReactionList,
MTgetThreadConversation,
MTgetUnreadMessageCount,
MTgetUnreadMsgCount,
MTgroupAckCount,
MTimportMessages,
MTinsertMessage,
MTjoinChatThread,
MTleaveChatThread,
MTloadAllConversations,
MTloadMsgWithKeywords,
MTloadMsgWithMsgType,
MTloadMsgWithStartId,
MTloadMsgWithTime,
MTmarkAllChatMsgAsRead,
MTmarkAllMessagesAsRead,
MTmarkMessageAsRead,
MTmessageReactionDidChange,
MTmodifyMessage,
MTonChatThreadCreated,
MTonChatThreadDestroyed,
MTonChatThreadUpdated,
MTonChatThreadUserRemoved,
MTonCmdMessagesReceived,
MTonConversationHasRead,
MTonConversationUpdate,
MTonGroupMessageRead,
MTonMessageContentChanged,
MTonMessagePinChanged,
MTonMessagesDelivered,
MTonMessagesRead,
MTonMessagesRecalled,
MTonMessagesReceived,
MTonReadAckForGroupMessageUpdated,
MTpinConversation,
MTpinMessage,
MTpinnedMessages,
MTrecallMessage,
MTremoveMemberFromChatThread,
MTremoveMessage,
MTremoveMessagesFromServerWithMsgIds,
MTremoveMessagesFromServerWithTs,
MTremoveReaction,
MTreportMessage,
MTresendMessage,
MTsearchChatMsgFromDB,
MTsendMessage,
MTsyncConversationExt,
MTtranslateMessage,
MTunpinMessage,
MTupdateChatMessage,
MTupdateChatThreadSubject,
MTupdateConversationMessage,
} from './__internal__/Consts';
import { Native } from './__internal__/Native';
import { ChatClient } from './ChatClient';
import type { ChatMessageEventListener } from './ChatEvents';
import { chatlog } from './common/ChatConst';
import {
ChatConversation,
ChatConversationFetchOptions,
ChatConversationMarkType,
ChatConversationType,
ChatSearchDirection,
} from './common/ChatConversation';
import { ChatCursorResult } from './common/ChatCursorResult';
import { ChatError } from './common/ChatError';
import { ChatGroupMessageAck } from './common/ChatGroup';
import {
ChatFetchMessageOptions,
ChatMessage,
ChatMessageBody,
ChatMessageChatType,
ChatMessagePinInfo,
ChatMessageSearchScope,
ChatMessageStatus,
ChatMessageStatusCallback,
ChatMessageType,
} from './common/ChatMessage';
import {
ChatMessageReaction,
ChatMessageReactionEvent,
ChatReactionOperation,
} from './common/ChatMessageReaction';
import {
ChatMessageThread,
ChatMessageThreadEvent,
} from './common/ChatMessageThread';
import { ChatTranslateLanguage } from './common/ChatTranslateLanguage';
/**
* The chat manager class, responsible for sending and receiving messages, managing conversations (including loading and deleting conversations), and downloading attachments.
*
* The sample code for sending a text message is as follows:
*
* ```typescript
* let msg = ChatMessage.createTextMessage(
* 'asteriskhx2',
* Date.now().toString(),
* ChatMessageChatType.PeerChat
* );
* let callback = new (class s implements ChatMessageStatusCallback {
* onProgress(progress: number): void {
* chatlog.log('ConnectScreen.sendMessage.onProgress ', progress);
* }
* onError(error: ChatError): void {
* chatlog.log('ConnectScreen.sendMessage.onError ', error);
* }
* onSuccess(): void {
* chatlog.log('ConnectScreen.sendMessage.onSuccess');
* }
* onReadAck(): void {
* chatlog.log('ConnectScreen.sendMessage.onReadAck');
* }
* onDeliveryAck(): void {
* chatlog.log('ConnectScreen.sendMessage.onDeliveryAck');
* }
* onStatusChanged(status: ChatMessageStatus): void {
* chatlog.log('ConnectScreen.sendMessage.onStatusChanged ', status);
* }
* })();
* ChatClient.getInstance()
* .chatManager.sendMessage(msg, callback)
* .then((nmsg: ChatMessage) => {
* chatlog.log(`${msg}, ${nmsg}`);
* })
* .catch();
* ```
*/
export class ChatManager extends BaseManager {
static TAG = 'ChatManager';
private _messageListeners: Set<ChatMessageEventListener>;
constructor() {
super();
this._messageListeners = new Set<ChatMessageEventListener>();
}
public setNativeListener(event: NativeEventEmitter) {
chatlog.log(`${ChatManager.TAG}: setNativeListener: `);
this._eventEmitter = event;
event.removeAllListeners(MTonMessagesReceived);
event.addListener(MTonMessagesReceived, this.onMessagesReceived.bind(this));
event.removeAllListeners(MTonCmdMessagesReceived);
event.addListener(
MTonCmdMessagesReceived,
this.onCmdMessagesReceived.bind(this)
);
event.removeAllListeners(MTonMessagesRead);
event.addListener(MTonMessagesRead, this.onMessagesRead.bind(this));
event.removeAllListeners(MTonGroupMessageRead);
event.addListener(MTonGroupMessageRead, this.onGroupMessageRead.bind(this));
event.removeAllListeners(MTonMessagesDelivered);
event.addListener(
MTonMessagesDelivered,
this.onMessagesDelivered.bind(this)
);
event.removeAllListeners(MTonMessagesRecalled);
event.addListener(MTonMessagesRecalled, this.onMessagesRecalled.bind(this));
event.removeAllListeners(MTonConversationUpdate);
event.addListener(
MTonConversationUpdate,
this.onConversationsUpdate.bind(this)
);
event.removeAllListeners(MTonConversationHasRead);
event.addListener(
MTonConversationHasRead,
this.onConversationHasRead.bind(this)
);
event.removeAllListeners(MTonReadAckForGroupMessageUpdated);
event.addListener(
MTonReadAckForGroupMessageUpdated,
this.onReadAckForGroupMessageUpdated.bind(this)
);
event.removeAllListeners(MTmessageReactionDidChange);
event.addListener(
MTmessageReactionDidChange,
this.onMessageReactionDidChange.bind(this)
);
event.removeAllListeners(MTonChatThreadCreated);
event.addListener(
MTonChatThreadCreated,
this.onChatMessageThreadCreated.bind(this)
);
event.removeAllListeners(MTonChatThreadUpdated);
event.addListener(
MTonChatThreadUpdated,
this.onChatMessageThreadUpdated.bind(this)
);
event.removeAllListeners(MTonChatThreadDestroyed);
event.addListener(
MTonChatThreadDestroyed,
this.onChatMessageThreadDestroyed.bind(this)
);
event.removeAllListeners(MTonChatThreadUserRemoved);
event.addListener(
MTonChatThreadUserRemoved,
this.onChatMessageThreadUserRemoved.bind(this)
);
event.removeAllListeners(MTonMessageContentChanged);
event.addListener(
MTonMessageContentChanged,
this.onMessageContentChanged.bind(this)
);
event.removeAllListeners(MTonMessagePinChanged);
event.addListener(
MTonMessagePinChanged,
this.onMessagePinChanged.bind(this)
);
}
private filterUnsupportedMessage(messages: ChatMessage[]): ChatMessage[] {
return messages.filter((message: ChatMessage) => {
return message.body.type !== ('unknown' as ChatMessageType);
});
}
private createReceiveMessage(messages: any[]): ChatMessage[] {
let list: Array<ChatMessage> = [];
messages.forEach((message: any) => {
let m = ChatMessage.createReceiveMessage(message);
list.push(m);
});
return this.filterUnsupportedMessage(list);
}
private onMessagesReceived(messages: any[]): void {
chatlog.log(`${ChatManager.TAG}: onMessagesReceived: `, messages);
if (this._messageListeners.size === 0) {
return;
}
let list: Array<ChatMessage> = this.createReceiveMessage(messages);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessagesReceived?.(list);
});
}
private onCmdMessagesReceived(messages: any[]): void {
chatlog.log(`${ChatManager.TAG}: onCmdMessagesReceived: `, messages);
if (this._messageListeners.size === 0) {
return;
}
let list: Array<ChatMessage> = this.createReceiveMessage(messages);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onCmdMessagesReceived?.(list);
});
}
private onMessagesRead(messages: any[]): void {
chatlog.log(`${ChatManager.TAG}: onMessagesRead: `, messages);
if (this._messageListeners.size === 0) {
return;
}
let list: Array<ChatMessage> = this.createReceiveMessage(messages);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessagesRead?.(list);
});
}
private onGroupMessageRead(messages: any[]): void {
chatlog.log(`${ChatManager.TAG}: onGroupMessageRead: `, messages);
if (this._messageListeners.size === 0) {
return;
}
let list: Array<ChatGroupMessageAck> = [];
messages.forEach((message: any) => {
let m = new ChatGroupMessageAck(message);
list.push(m);
});
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onGroupMessageRead?.(messages);
});
}
private onMessagesDelivered(messages: any[]): void {
chatlog.log(`${ChatManager.TAG}: onMessagesDelivered: `, messages);
if (this._messageListeners.size === 0) {
return;
}
let list: Array<ChatMessage> = this.createReceiveMessage(messages);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessagesDelivered?.(list);
});
}
private onMessagesRecalled(messages: any[]): void {
chatlog.log(`${ChatManager.TAG}: onMessagesRecalled: `, messages);
if (this._messageListeners.size === 0) {
return;
}
let list: Array<ChatMessage> = this.createReceiveMessage(messages);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessagesRecalled?.(list);
});
}
private onConversationsUpdate(): void {
chatlog.log(`${ChatManager.TAG}: onConversationsUpdate: `);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onConversationsUpdate?.();
});
}
private onConversationHasRead(params: any): void {
chatlog.log(`${ChatManager.TAG}: onConversationHasRead: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
let from = params?.from;
let to = params?.to;
listener.onConversationRead?.(from, to);
});
}
private onReadAckForGroupMessageUpdated(params: any): void {
chatlog.log(
`${ChatManager.TAG}: onReadAckForGroupMessageUpdated: `,
params
);
}
private onMessageReactionDidChange(params: any): void {
chatlog.log(
`${ChatManager.TAG}: onMessageReactionDidChange: `,
JSON.stringify(params)
);
if (this._messageListeners.size === 0) {
return;
}
const list: Array<ChatMessageReactionEvent> = [];
Object.entries(params).forEach((v: [string, any]) => {
const convId = v[1].conversationId;
const msgId = v[1].messageId;
const ll: Array<ChatMessageReaction> = [];
Object.entries(v[1].reactions).forEach((vv: [string, any]) => {
ll.push(new ChatMessageReaction(vv[1]));
});
const o: Array<ChatReactionOperation> = [];
Object.entries(v[1].operations).forEach((vv: [string, any]) => {
o.push(ChatReactionOperation.fromNative(vv[1]));
});
list.push(
new ChatMessageReactionEvent({
convId: convId,
msgId: msgId,
reactions: ll,
operations: o,
})
);
});
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessageReactionDidChange?.(list);
});
}
private onChatMessageThreadCreated(params: any): void {
chatlog.log(`${ChatManager.TAG}: onChatMessageThreadCreated: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onChatMessageThreadCreated?.(new ChatMessageThreadEvent(params));
});
}
private onChatMessageThreadUpdated(params: any): void {
chatlog.log(`${ChatManager.TAG}: onChatMessageThreadUpdated: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onChatMessageThreadUpdated?.(new ChatMessageThreadEvent(params));
});
}
private onChatMessageThreadDestroyed(params: any): void {
chatlog.log(`${ChatManager.TAG}: onChatMessageThreadDestroyed: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onChatMessageThreadDestroyed?.(
new ChatMessageThreadEvent(params)
);
});
}
private onChatMessageThreadUserRemoved(params: any): void {
chatlog.log(`${ChatManager.TAG}: onChatMessageThreadUserRemoved: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onChatMessageThreadUserRemoved?.(
new ChatMessageThreadEvent(params)
);
});
}
private onMessageContentChanged(params: any): void {
chatlog.log(`${ChatManager.TAG}: onMessageContentChanged: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessageContentChanged?.(
ChatMessage.createReceiveMessage(params.message),
params.lastModifyOperatorId,
params.lastModifyTime
);
});
}
private onMessagePinChanged(params: any): void {
chatlog.log(`${ChatManager.TAG}: onMessagePinChanged: `, params);
this._messageListeners.forEach((listener: ChatMessageEventListener) => {
listener.onMessagePinChanged?.({
messageId: params.messageId,
convId: params.conversationId,
pinOperation: params.pinOperation,
pinInfo: new ChatMessagePinInfo(params.pinInfo),
});
});
}
private static handleSendMessageCallback(
self: ChatManager,
message: ChatMessage,
callback?: ChatMessageStatusCallback
): void {
ChatManager.handleMessageCallback(MTsendMessage, self, message, callback);
}
private static handleResendMessageCallback(
self: ChatManager,
message: ChatMessage,
callback?: ChatMessageStatusCallback
): void {
ChatManager.handleMessageCallback(MTresendMessage, self, message, callback);
}
private static handleDownloadAttachmentCallback(
self: ChatManager,
message: ChatMessage,
callback?: ChatMessageStatusCallback
): void {
ChatManager.handleMessageCallback(
MTdownloadAttachment,
self,
message,
callback
);
}
private static handleDownloadThumbnailCallback(
self: ChatManager,
message: ChatMessage,
callback?: ChatMessageStatusCallback
): void {
ChatManager.handleMessageCallback(
MTdownloadThumbnail,
self,
message,
callback
);
}
private static handleDownloadFileCallback(
self: ChatManager,
message: ChatMessage,
method: string,
callback?: ChatMessageStatusCallback
): void {
ChatManager.handleMessageCallback(method, self, message, callback);
}
/**
* Adds a message listener.
*
* @param listener The message listener to add.
*/
public addMessageListener(listener: ChatMessageEventListener): void {
chatlog.log(`${ChatManager.TAG}: addMessageListener: `);
this._messageListeners.add(listener);
}
/**
* Removes the message listener.
*
* @param listener The message listener to remove.
*/
public removeMessageListener(listener: ChatMessageEventListener): void {
chatlog.log(`${ChatManager.TAG}: removeMessageListener: `);
this._messageListeners.delete(listener);
}
/**
* Removes all message listeners.
*/
public removeAllMessageListener(): void {
chatlog.log(`${ChatManager.TAG}: removeAllMessageListener: `);
this._messageListeners.clear();
}
/**
* Sends a message.
*
* **Note**
*
* - For a voice or image message or a message with an attachment, the SDK will automatically upload the attachment.
* - You can determine whether to upload the attachment to the chat sever by setting {@link ChatOptions}.
*
* @param message The message object to be sent. Ensure that you set this parameter.
* @param callback The listener that listens for message changes.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async sendMessage(
message: ChatMessage,
callback?: ChatMessageStatusCallback
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: sendMessage: ${message.msgId}, ${message.localTime}`,
message
);
message.status = ChatMessageStatus.PROGRESS;
ChatManager.handleSendMessageCallback(this, message, callback);
let r: any = await Native._callMethod(MTsendMessage, {
[MTsendMessage]: message,
});
Native.checkErrorFromResult(r);
}
/**
* Resends a message.
*
* @param message The message object to be resent.
* @param callback The listener that listens for message changes.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async resendMessage(
message: ChatMessage,
callback: ChatMessageStatusCallback
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: resendMessage: ${message.msgId}, ${message.localTime}`,
message
);
if (
message.msgId !== message.localMsgId &&
message.status === ChatMessageStatus.SUCCESS
) {
callback.onError(
message.localMsgId,
new ChatError({ code: 1, description: 'The message had send success' })
);
return;
}
message.status = ChatMessageStatus.PROGRESS;
ChatManager.handleResendMessageCallback(this, message, callback);
let r: any = await Native._callMethod(MTresendMessage, {
[MTsendMessage]: message,
});
Native.checkErrorFromResult(r);
}
/**
* Sends the read receipt to the server.
*
* This method applies to one-to-one chats only.
*
* **Note**
*
* This method takes effect only when you set {@link ChatOptions.requireAck} as `true`.
*
* To send a group message read receipt, you can call {@link sendGroupMessageReadAck}.
*
* We recommend that you call {@link sendConversationReadAck} when opening the chat page. In other cases, you can call this method to reduce the number of method calls.
*
* @param message The message for which the read receipt is to be sent.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async sendMessageReadAck(message: ChatMessage): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: sendMessageReadAck: ${message.msgId}, ${message.localTime}`,
message
);
let r: any = await Native._callMethod(MTackMessageRead, {
[MTackMessageRead]: {
to: message.from,
msg_id: message.msgId,
},
});
Native.checkErrorFromResult(r);
}
/**
* Sends the group message receipt to the server.
*
* **Note**
*
* - This method takes effect only after you set {@link ChatOptions.requireAck} and {@link ChatMessage.needGroupAck} as `true`.
* - This method applies to group messages only. To send a read receipt for a one-to-one chat message, you can call {@link sendMessageReadAck}; to send a conversation read receipt, you can call {@link sendConversationReadAck}.
*
* @param msgId The message ID.
* @param groupId The group ID.
* @param opt The extension information, which is a custom keyword that specifies a custom action or command.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async sendGroupMessageReadAck(
msgId: string,
groupId: string,
opt?: { content: string }
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: sendGroupMessageReadAck: ${msgId}, ${groupId}`
);
let s = opt?.content
? {
msg_id: msgId,
group_id: groupId,
content: opt?.content,
}
: {
msg_id: msgId,
group_id: groupId,
};
let r: any = await Native._callMethod(MTackGroupMessageRead, {
[MTackGroupMessageRead]: s,
});
Native.checkErrorFromResult(r);
}
/**
* Sends the conversation read receipt to the server.
*
* **Note**
*
* - This method is valid only for one-to-one conversations.
* - After this method is called, the sever will set the message status from unread to read.
* - The SDK triggers the {@link ChatMessageEventListener.onConversationRead} callback on the client of the message sender, notifying that the messages are read. This also applies to multi-device scenarios.
*
* @param convId The conversation ID.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async sendConversationReadAck(convId: string): Promise<void> {
chatlog.log(`${ChatManager.TAG}: sendConversationReadAck: ${convId}`);
let r: any = await Native._callMethod(MTackConversationRead, {
[MTackConversationRead]: {
convId: convId,
},
});
Native.checkErrorFromResult(r);
}
/**
* Recalls the sent message.
*
* @param msgId The message ID.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async recallMessage(msgId: string): Promise<void> {
chatlog.log(`${ChatManager.TAG}: recallMessage: ${msgId}`);
let r: any = await Native._callMethod(MTrecallMessage, {
[MTrecallMessage]: {
msg_id: msgId,
},
});
Native.checkErrorFromResult(r);
}
/**
* Gets a message from the local database by message ID.
*
* @param msgId The message ID.
* @returns The message.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getMessage(msgId: string): Promise<ChatMessage | undefined> {
chatlog.log(`${ChatManager.TAG}: getMessage: ${msgId}`);
let r: any = await Native._callMethod(MTgetMessage, {
[MTgetMessage]: {
msg_id: msgId,
},
});
Native.checkErrorFromResult(r);
const rr = r?.[MTgetMessage];
if (rr) {
return new ChatMessage(rr);
}
return undefined;
}
/**
* Marks all conversations as read.
*
* This method is for the local conversations only.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async markAllConversationsAsRead(): Promise<void> {
chatlog.log(`${ChatManager.TAG}: markAllConversationsAsRead: `);
let r: any = await Native._callMethod(MTmarkAllChatMsgAsRead);
Native.checkErrorFromResult(r);
}
/**
* Gets the count of the unread messages.
*
* @returns The count of the unread messages.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getUnreadCount(): Promise<number> {
chatlog.log(`${ChatManager.TAG}: getUnreadCount: `);
let r: any = await Native._callMethod(MTgetUnreadMessageCount);
Native.checkErrorFromResult(r);
return r?.[MTgetUnreadMessageCount] as number;
}
/**
* Inserts a message to the conversation in the local database.
*
* For example, when a notification messages is received, a message can be constructed and written to the conversation. If the message to insert already exits (msgId or localMsgId is existed), the insertion fails.
*
* The message will be inserted based on the Unix timestamp included in it. Upon message insertion, the SDK will automatically update attributes of the conversation, including `latestMessage`.
*
* @param message The message to be inserted.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async insertMessage(message: ChatMessage): Promise<void> {
chatlog.log(`${ChatManager.TAG}: insertMessage: `, message);
let r: any = await Native._callMethod(MTinsertMessage, {
[MTinsertMessage]: {
msg: message,
},
});
Native.checkErrorFromResult(r);
}
/**
* Updates the local message.
*
* The message will be updated both in the memory and local database.
*
* @return The updated message.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async updateMessage(message: ChatMessage): Promise<ChatMessage> {
chatlog.log(
`${ChatManager.TAG}: updateMessage: ${message.msgId}, ${message.localTime}`,
message
);
let r: any = await Native._callMethod(MTupdateChatMessage, {
[MTupdateChatMessage]: {
message: message,
},
});
Native.checkErrorFromResult(r);
const rr = r?.[MTupdateChatMessage];
return new ChatMessage(rr);
}
/**
* Imports messages to the local database.
*
* You can only import messages that you sent or received.
*
* @param messages The messages to import.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async importMessages(messages: Array<ChatMessage>): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: importMessages: ${messages.length}`,
messages
);
let r: any = await Native._callMethod(MTimportMessages, {
[MTimportMessages]: {
messages: messages,
},
});
Native.checkErrorFromResult(r);
}
/**
* Downloads the message attachment.
*
* **Note** This method is only used to download messages attachment in combine type message or thread type.
*
* **Note** The bottom layer will not get the original message object and will use the json converted message object.
*
* You can also call this method if the attachment fails to be downloaded automatically.
*
* @param message The ID of the message with the attachment to be downloaded.
* @param callback The listener that listens for message changes.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async downloadAttachmentInCombine(
message: ChatMessage,
callback?: ChatMessageStatusCallback
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: downloadAttachmentInCombine: ${message.msgId}, ${message.localTime}`,
message
);
ChatManager.handleDownloadFileCallback(
this,
message,
MTdownloadAttachmentInCombine,
callback
);
let r: any = await Native._callMethod(MTdownloadAttachmentInCombine, {
[MTdownloadAttachmentInCombine]: {
message: message,
},
});
Native.checkErrorFromResult(r);
}
/**
* Downloads the message thumbnail.
*
* **Note** This method is only used to download messages thumbnail in combine type message.
*
* @param message The ID of the message with the thumbnail to be downloaded. Only the image messages and video messages have a thumbnail.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async downloadThumbnailInCombine(
message: ChatMessage,
callback?: ChatMessageStatusCallback
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: downloadThumbnailInCombine: ${message.msgId}, ${message.localTime}`,
message
);
ChatManager.handleDownloadFileCallback(
this,
message,
MTdownloadThumbnailInCombine,
callback
);
let r: any = await Native._callMethod(MTdownloadThumbnailInCombine, {
[MTdownloadThumbnailInCombine]: {
message: message,
},
});
Native.checkErrorFromResult(r);
}
/**
* Downloads the message attachment.
*
* You can also call this method if the attachment fails to be downloaded automatically.
*
* @param message The ID of the message with the attachment to be downloaded.
* @param callback The listener that listens for message changes.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async downloadAttachment(
message: ChatMessage,
callback?: ChatMessageStatusCallback
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: downloadAttachment: ${message.msgId}, ${message.localTime}`,
message
);
ChatManager.handleDownloadAttachmentCallback(this, message, callback);
let r: any = await Native._callMethod(MTdownloadAttachment, {
[MTdownloadAttachment]: {
message: message,
},
});
Native.checkErrorFromResult(r);
}
/**
* Downloads the message thumbnail.
*
* @param message The ID of the message with the thumbnail to be downloaded. Only the image messages and video messages have a thumbnail.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async downloadThumbnail(
message: ChatMessage,
callback?: ChatMessageStatusCallback
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: downloadThumbnail: ${message.msgId}, ${message.localTime}`,
message
);
ChatManager.handleDownloadThumbnailCallback(this, message, callback);
let r: any = await Native._callMethod(MTdownloadThumbnail, {
[MTdownloadThumbnail]: {
message: message,
},
});
Native.checkErrorFromResult(r);
}
/**
* Uses the pagination to get messages in the specified conversation from the server.
*
* **note** If the conversation object does not exist, this method will create it.
*
* @param convId The conversation ID.
* @param chatType The conversation type. See {@link ChatConversationType}.
* @params params
* - pageSize: The number of messages that you expect to get on each page. The value range is [1,50].
* - startMsgId: The starting message ID for query. After this parameter is set, the SDK retrieves messages, starting from the specified one, in the reverse chronological order of when the server receives them. If this parameter is set an empty string, the SDK retrieves messages, starting from the latest one, in the reverse chronological order of when the server receives them.
* - direction: The message search direction. See {@link ChatSearchDirection}.
* - (Default) `ChatSearchDirection.Up`: Messages are retrieved in the descending order of the Unix timestamp included in them.
* - `ChatSearchDirection.Down`: Messages are retrieved in the ascending order of the Unix timestamp included in them.
* @returns The list of retrieved messages (excluding the one with the starting ID) and the cursor for the next query.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async fetchHistoryMessages(
convId: string,
chatType: ChatConversationType,
params: {
pageSize?: number;
startMsgId?: string;
direction?: ChatSearchDirection;
}
): Promise<ChatCursorResult<ChatMessage>> {
chatlog.log(
`${ChatManager.TAG}: fetchHistoryMessages: ${convId}, ${chatType}, ${params}`
);
let r: any = await Native._callMethod(MTfetchHistoryMessages, {
[MTfetchHistoryMessages]: {
convId: convId,
convType: chatType as number,
pageSize: params.pageSize ?? 20,
startMsgId: params.startMsgId ?? '',
direction: params.direction ?? ChatSearchDirection.UP,
},
});
Native.checkErrorFromResult(r);
let ret = new ChatCursorResult<ChatMessage>({
cursor: r?.[MTfetchHistoryMessages].cursor,
list: r?.[MTfetchHistoryMessages].list,
opt: {
map: (param: any) => {
return new ChatMessage(param);
},
},
});
return ret;
}
/**
* retrieve the history message for the specified session from the server.
*
* **note** If the conversation object does not exist, this method will create it.
*
* @param convId The conversation ID.
* @param chatType The conversation type. See {@link ChatConversationType}.
* @param params -
* - options: The parameter configuration class for pulling historical messages from the server. See {@link ChatFetchMessageOptions}.
* - cursor: The cursor position from which to start querying data.
* - pageSize: The number of messages that you expect to get on each page. The value range is [1,50].
*
* @returns The list of retrieved messages (excluding the one with the starting ID) and the cursor for the next query.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async fetchHistoryMessagesByOptions(
convId: string,
chatType: ChatConversationType,
params?: {
options?: ChatFetchMessageOptions;
cursor?: string;
pageSize?: number;
}
): Promise<ChatCursorResult<ChatMessage>> {
chatlog.log(
`${ChatManager.TAG}: fetchHistoryMessagesByOptions: ${convId}, ${chatType}, ${params}`
);
let r: any = await Native._callMethod(MTfetchHistoryMessagesByOptions, {
[MTfetchHistoryMessagesByOptions]: {
convId: convId,
convType: chatType as number,
pageSize: params?.pageSize ?? 20,
cursor: params?.cursor ?? '',
options: params?.options,
},
});
Native.checkErrorFromResult(r);
let ret = new ChatCursorResult<ChatMessage>({
cursor: r?.[MTfetchHistoryMessagesByOptions].cursor,
list: r?.[MTfetchHistoryMessagesByOptions].list,
opt: {
map: (param: any) => {
return new ChatMessage(param);
},
},
});
return ret;
}
/**
* Retrieves messages with keywords in a conversation from the local database.
*
* @param keywords The keywords for query.
* @param timestamp The starting Unix timestamp in the message for query. The unit is millisecond. After this parameter is set, the SDK retrieves messages, starting from the specified one, according to the message search direction.
* If you set this parameter as a negative value, the SDK retrieves messages, starting from the current time, in the descending order of the timestamp included in them.
* @param maxCount The maximum number of messages to retrieve each time. The value range is [1,400].
* @param from The user ID or group ID for retrieval. Usually, it is the conversation ID.
* @param direction The message search direction. See {@link ChatSearchDirection}.
* - (Default) `ChatSearchDirection.Up`: Messages are retrieved in the descending order of the Unix timestamp included in them.
* - `ChatSearchDirection.Down`: Messages are retrieved in the ascending order of the Unix timestamp included in them.
* @returns The list of retrieved messages (excluding the one with the starting timestamp). If no message is obtained, an empty list is returned.
*
* @throws A description of the exception. See {@link ChatError}.
*
* @deprecated 2024-04-22. Use {@link getMsgsWithKeyword} instead.
*/
public async searchMsgFromDB(
keywords: string,
timestamp: number = -1,
maxCount: number = 20,
from: string = '',
direction: ChatSearchDirection = ChatSearchDirection.UP
): Promise<Array<ChatMessage>> {
chatlog.log(
`${ChatManager.TAG}: searchMsgFromDB: ${keywords}, ${timestamp}, ${maxCount}, ${from}`
);
let r: any = await Native._callMethod(MTsearchChatMsgFromDB, {
[MTsearchChatMsgFromDB]: {
keywords: keywords,
timeStamp: timestamp,
maxCount: maxCount,
from: from,
direction: direction === ChatSearchDirection.UP ? 'up' : 'down',
},
});
Native.checkErrorFromResult(r);
let ret = new Array<ChatMessage>(0);
const rr: Array<any> = r?.[MTsearchChatMsgFromDB];
if (rr) {
rr.forEach((element) => {
ret.push(new ChatMessage(element));
});
}
return ret;
}
/**
* Retrieves messages with keywords from the local database.
*
* @param keywords The keywords for query.
* @param timestamp The starting Unix timestamp in the message for query. The unit is millisecond. After this parameter is set, the SDK retrieves messages, starting from the specified one, according to the message search direction.
* If you set this parameter as a negative value, the SDK retrieves messages, starting from the current time, in the descending order of the timestamp included in them.
* @param maxCount The maximum number of messages to retrieve each time. The value range is [1,400].
* @param from The user ID or group ID for retrieval. Usually, it is the conversation ID.
* @param direction The message search direction. See {@link ChatSearchDirection}.
* - (Default) `ChatSearchDirection.Up`: Messages are retrieved in the descending order of the Unix timestamp included in them.
* - `ChatSearchDirection.Down`: Messages are retrieved in the ascending order of the Unix timestamp included in them.
* @returns The list of retrieved messages (excluding the one with the starting timestamp). If no message is obtained, an empty list is returned.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getMsgsWithKeyword(params: {
keywords: string;
timestamp?: number;
maxCount?: number;
from?: string;
direction?: ChatSearchDirection;
searchScope?: ChatMessageSearchScope;
}): Promise<Array<ChatMessage>> {
const {
keywords,
timestamp = -1,
maxCount = 20,
from = '',
direction = ChatSearchDirection.UP,
searchScope = ChatMessageSearchScope.All,
} = params;
chatlog.log(
`${ChatManager.TAG}: searchMsgFromDB: ${keywords}, ${timestamp}, ${maxCount}, ${from}`
);
let r: any = await Native._callMethod(MTsearchChatMsgFromDB, {
[MTsearchChatMsgFromDB]: {
keywords: keywords,
timeStamp: timestamp,
maxCount: maxCount,
from: from,
direction: direction === ChatSearchDirection.UP ? 'up' : 'down',
searchScope: searchScope,
},
});
Native.checkErrorFromResult(r);
let ret = new Array<ChatMessage>(0);
const rr: Array<any> = r?.[MTsearchChatMsgFromDB];
if (rr) {
rr.forEach((element) => {
ret.push(new ChatMessage(element));
});
}
return ret;
}
/**
* Uses the pagination to get read receipts for group messages from the server.
*
* For how to send read receipts for group messages, see {@link sendConversationReadAck}.
*
* @param msgId The message ID.
* @param startAckId The starting read receipt ID for query. After this parameter is set, the SDK retrieves read receipts, from the specified one, in the reverse chronological order of when the server receives them.
* If this parameter is set as `null` or an empty string, the SDK retrieves read receipts, from the latest one, in the reverse chronological order of when the server receives them.
* @param pageSize The number of read receipts for the group message that you expect to get on each page. The value range is [1,400].
* @returns The list of retrieved read receipts (excluding the one with the starting ID) and the cursor for the next query.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async fetchGroupAcks(
msgId: string,
groupId: string,
startAckId: string,
pageSize: number = 0
): Promise<ChatCursorResult<ChatGroupMessageAck>> {
chatlog.log(
`${ChatManager.TAG}: asyncFetchGroupAcks: ${msgId}, ${startAckId}, ${pageSize}`
);
let r: any = await Native._callMethod(MTasyncFetchGroupAcks, {
[MTasyncFetchGroupAcks]: {
msg_id: msgId,
ack_id: startAckId,
pageSize: pageSize,
group_id: groupId,
},
});
Native.checkErrorFromResult(r);
let ret = new ChatCursorResult<ChatGroupMessageAck>({
cursor: r?.[MTasyncFetchGroupAcks].cursor,
list: r?.[MTasyncFetchGroupAcks].list,
opt: {
map: (param: any) => {
return new ChatGroupMessageAck(param);
},
},
});
return ret;
}
/**
* Deletes the specified conversation and its historical messages from the server.
*
* @param convId The conversation ID.
* @param convType The conversation type. See {@link ChatConversationType}.
* @param isDeleteMessage Whether to delete the historical messages with the conversation.
* - (Default) `true`: Yes.
* - `false`: No.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async removeConversationFromServer(
convId: string,
convType: ChatConversationType,
isDeleteMessage: boolean = true
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: removeConversationFromServer: ${convId}, ${convType}, ${isDeleteMessage}`
);
let ct = 0;
switch (convType) {
case ChatConversationType.PeerChat:
ct = 0;
break;
case ChatConversationType.GroupChat:
ct = 1;
break;
case ChatConversationType.RoomChat:
ct = 2;
break;
default:
throw new ChatError({
code: 1,
description: `This type is not supported. ` + convType,
});
}
let r = await Native._callMethod(MTdeleteRemoteConversation, {
[MTdeleteRemoteConversation]: {
conversationId: convId,
conversationType: ct,
isDeleteRemoteMessage: isDeleteMessage,
},
});
Native.checkErrorFromResult(r);
}
/**
* Gets the conversation by conversation ID and conversation type.
*
* @param convId The conversation ID.
* @param convType The conversation type. See {@link ChatConversationType}.
* @param createIfNeed Whether to create a conversation if the specified conversation is not found:
* - (Default) `true`: Yes.
* - `false`: No.
* @param isChatThread Whether the conversation is a thread conversation.
* - (Default) `false`: No.
* - `true`: Yes.
*
* @returns The retrieved conversation object. The SDK returns `null` if the conversation is not found.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getConversation(
convId: string,
convType: ChatConversationType,
createIfNeed: boolean = true,
isChatThread: boolean = false
): Promise<ChatConversation | undefined> {
chatlog.log(
`${ChatManager.TAG}: getConversation: ${convId}, ${convType}, ${createIfNeed}, ${isChatThread}`
);
let r: any = await Native._callMethod(MTgetConversation, {
[MTgetConversation]: {
convId: convId,
convType: convType as number,
createIfNeed: createIfNeed,
isChatThread: isChatThread,
},
});
Native.checkErrorFromResult(r);
const rr = r?.[MTgetConversation];
if (rr) {
return new ChatConversation(rr);
}
return undefined;
}
/**
* Gets all conversations from the local database.
*
* Conversations will be first retrieved from the memory. If no conversation is found, the SDK retrieves from the local database.
*
* @returns The retrieved conversations.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getAllConversations(): Promise<Array<ChatConversation>> {
chatlog.log(`${ChatManager.TAG}: getAllConversations:`);
let r: any = await Native._callMethod(MTloadAllConversations);
Native.checkErrorFromResult(r);
let ret = new Array<ChatConversation>(0);
const rr: Array<any> = r?.[MTloadAllConversations];
if (rr) {
rr.forEach((element) => {
ret.push(new ChatConversation(element));
});
}
return ret;
}
/**
* @deprecated 2023-07-24
*
* Gets the conversation list from the server.
*
* **Note**
*
* - To use this function, you need to contact our business manager to activate it.
* - After this function is activated, users can pull 10 conversations within 7 days by default (each conversation contains the latest historical message).
* - If you want to adjust the number of conversations or time limit, contact our business manager.
*
* @returns The conversation list of the current user.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async fetchAllConversations(): Promise<Array<ChatConversation>> {
chatlog.log(`${ChatManager.TAG}: fetchAllConversations:`);
let r: any = await Native._callMethod(MTgetConversationsFromServer);
Native.checkErrorFromResult(r);
let ret = new Array<ChatConversation>(0);
const rr: Array<any> = r?.[MTgetConversationsFromServer];
if (rr) {
rr.forEach((element) => {
ret.push(new ChatConversation(element));
});
}
return ret;
}
/**
* Deletes a conversation and its local messages from the local database.
*
* @param convId The conversation ID.
* @param withMessage Whether to delete the historical messages with the conversation.
* - (Default) `true`: Yes.
* - `false`: No.
* @returns Whether the conversation is successfully deleted.
* - `true`: Yes.
* - `false`: No.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async deleteConversation(
convId: string,
withMessage: boolean = true
): Promise<void> {
chatlog.log(
`${ChatManager.TAG}: deleteConversation: ${convId}, ${withMessage}`
);
let r: any = await Native._callMethod(MTdeleteConversation, {
[MTdeleteConversation]: {
convId: convId,
deleteMessages: withMessage,
},
});
Native.checkErrorFromResult(r);
}
/**
* Gets the latest message from the conversation.
*
* **Note**
*
* The operation does not change the unread message count.
* If the conversation object does not exist, this method will create it.
*
* The SDK gets the latest message from the memory first. If no message is found, the SDK loads the message from the local database and then puts it in the memory.
*
* @param convId The conversation ID.
* @param convType The conversation type. See {@link ChatConversationType}.
* @param isChatThread Whether the conversation is a thread conversation.
*
* @returns The message instance. The SDK returns `undefined` if the message does not exist.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getLatestMessage(
convId: string,
convType: ChatConversationType,
isChatThread: boolean = false
): Promise<ChatMessage | undefined> {
chatlog.log(
`${ChatManager.TAG}: latestMessage: `,
convId,
convType,
isChatThread
);
let r: any = await Native._callMethod(MTgetLatestMessage, {
[MTgetLatestMessage]: {
convId: convId,
convType: convType,
isChatThread: isChatThread,
},
});
ChatManager.checkErrorFromResult(r);
const rr = r?.[MTgetLatestMessage];
if (rr) {
return new ChatMessage(rr);
}
return undefined;
}
/**
* Gets the latest received message from the conversation.
*
* **note** If the conversation object does not exist, this method will create it.
*
* @param convId The conversation ID.
* @param convType The conversation type. See {@link ChatConversationType}.
* @param isChatThread Whether the conversation is a thread conversation.
*
* @returns The message instance. The SDK returns `undefined` if the message does not exist.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getLatestReceivedMessage(
convId: string,
convType: ChatConversationType,
isChatThread: boolean = false
): Promise<ChatMessage | undefined> {
chatlog.log(
`${ChatManager.TAG}: lastReceivedMessage: `,
convId,
convType,
isChatThread
);
let r: any = await Native._callMethod(MTgetLatestMessageFromOthers, {
[MTgetLatestMessageFromOthers]: {
convId: convId,
convType: convType,
isChatThread: isChatThread,
},
});
ChatManager.checkErrorFromResult(r);
const rr = r?.[MTgetLatestMessageFromOthers];
if (rr) {
return new ChatMessage(rr);
}
return undefined;
}
/**
* Gets the unread message count of the conversation.
*
* **note** If the conversation object does not exist, this method will create it.
*
* @param convId The conversation ID.
* @param convType The conversation type. See {@link ChatConversationType}.
* @param isChatThread Whether the conversation is a thread conversation.
*
* @returns The unread message count.
*
* @throws A description of the exception. See {@link ChatError}.
*/
public async getConversationUnreadCount(
convId: string,
convType: ChatConversationType,
isChatThread: boolean = false
): Promise<number> {
chatlog.log(
`${ChatManager.TAG}: getConversationUnreadCount: `,
convId,
convType,
isChatThread
);
let r: any = await Native._callMethod