UNPKG

@rongcloud/imkit-store

Version:

RongCloud IM UIKit Store

870 lines (856 loc) 23.9 kB
import * as mobx from 'mobx'; import { ObservableMap } from 'mobx'; import * as _rongcloud_engine from '@rongcloud/engine'; import { FileType, IAsyncRes, ILogger, PluginContext, IConversationOption as IConversationOption$1, ConversationType as ConversationType$1, RCConnectionStatus } from '@rongcloud/engine'; import { LogL, ConversationType, IAReceivedMessage, NotificationLevel, ReadReceiptInfoV5, BaseMessage, ISendMessageOptions, IConversationOption, IAsyncRes as IAsyncRes$1, GetHistoryMessageResult, ITypingUser, ErrorCode, LogDBProxy } from '@rongcloud/imlib-next'; /** * 上传信息 * @category Interface */ interface IKitUploadInfo { file?: File; path?: string; buffer?: ArrayBuffer; fileName?: string; fileSize: number; fileType: FileType; duration?: number; onProgress?: (progress: number) => void; onComplete?: (res: IAsyncRes<IKitUploadCompleteData>) => void; } /** * 上传请求数据接口 * 用于外部调用者发起请求 * @category Interface */ interface IKitUploadRequestData { url: string; headers: Record<string, string>; body: Record<string, string> | ArrayBuffer | any; contentType?: string; method: 'PUT' | 'POST'; filePath?: string; } /** * @hidden */ interface IKitUploadResult { name: string; downloadUrl: string; uniqueName: string; size: number; type: string; /** * 音频时长,单位秒 */ duration?: number; length?: number; /** * 图片缩略图 */ thumbnail?: string; /** * 图片宽度 */ width?: number; /** * 图片高度 */ height?: number; } /** * 图片信息 * @category Interface */ interface IKitImageInfo { /** * 图片缩略图的 base64 数据 */ thumbnail?: string; /** * 图片宽度 */ width?: number; /** * 图片高度 */ height?: number; } /** * 缩略图配置 * @category Interface */ interface IKitThumbnailConfig { /** * 最大高度 */ maxHeight?: number; /** * 最大宽度 */ maxWidth?: number; /** * 图片质量 */ quality?: number; /** * 缩放比例 */ scale?: number; } /** * 上传完成返回数据信息 * @category Interface */ interface IKitUploadCompleteData { downloadUrl: string; msg?: string; } /** * 上传请求协议接口 * 由外部实现,用于执行上传请求 * @category class */ declare abstract class AKitUploadRequest { uploadInfo: IKitUploadInfo; protected _abortStatus: boolean; /** * @hidden */ constructor(info: IKitUploadInfo); /** * 执行上传请求 * @returns 上传结果 */ abstract execute(data: IKitUploadRequestData): Promise<IAsyncRes<IKitUploadResult>>; /** * 取消上传请求 */ abort(): void; isAbort(): boolean; } /** * store 初始化参数 * @category Interface */ interface IRCStoreInitOpts { /** * 日志输出等级,默认值 `LogL.WARN(2)` */ logLevel?: LogL.DEBUG | LogL.INFO | LogL.WARN | LogL.ERROR; /** * 业务数据模块钩子,用于向 SDK 注入用户信息、群组信息等。 */ hooks?: IKitServiceHooks; } /** * 会话信息 * @category Interface */ interface IKitConversation { /** * 根据 targetId、conversationType、channelId 生成的唯一标识 */ key: string; targetId: string; conversationType: ConversationType; channelId: string; name: string; nickName: string; portraitUri: string; draft: string; latestMessage: IAReceivedMessage | null; isTop: boolean; notificationLevel: NotificationLevel; unreadCount: number; updateTime: number; memberCount: number; readReceiptInfo?: ReadReceiptInfoV5; } /** * @hidden */ type CacheType<T> = ObservableMap<string, { data: T; expires: number; pending: boolean; }>; /** * Profile 基础信息 * @category Interface * @hidden */ interface IBaseProfile { /** * 唯一标识 */ id: string; /** * 名称 */ name: string; /** * 头像 */ portraitUri?: string; } /** * 用户信息 * @category Interface */ interface IUserProfile extends IBaseProfile { /** * 用户备注 */ remark?: string; } /** * 群组信息 * @category Interface */ interface IGroupProfile extends IBaseProfile { /** * 群组成员数量 */ memberCount: number; /** * 群组备注 */ remark?: string; } /** * 系统信息 * @category Interface */ interface ISystemProfile extends IBaseProfile { } /** * 群组成员信息 * @category Interface */ interface IGroupMemberProfile { /** * 群成员昵称 */ groupNickname: string; /** * 用户信息 */ user: { /** * 用户 ID */ id: string; /** * 用户昵称 */ nickname: string; /** * 用户头像 */ portraitUri?: string; }; } /** * 数据源接口约束 * @hidden */ interface IDataSource { getUserProfile(userIds: string[]): Promise<IUserProfile[]>; getGroupProfile(groupIds: string[]): Promise<IGroupProfile[]>; getSystemProfile(systemIds: string[]): Promise<ISystemProfile[]>; getGroupMembers(groupId: string): Promise<IGroupMemberProfile[]>; } /** * 用户信息回调钩子 * @category Interface */ interface IKitServiceHooks { /** * 根据 userId 批量获取用户信息 * @param userIds - 用户 ID 列表 */ reqUserProfiles?(userIds: string[]): Promise<IUserProfile[]>; /** * 根据 groupId 批量获取群组信息 * @param groupIds - 群组 ID 列表 */ reqGroupProfiles?(groupIds: string[]): Promise<IGroupProfile[]>; /** * 批量获取系统会话信息,当会话列表中存在 ConversationType.SYSTEM 类型时,会调用此方法获取系统会话信息 * @param targetIds - 系统会话 ID 列表 */ reqSystemProfiles?(targetIds: string[]): Promise<ISystemProfile[]>; /** * 根据 groupId 获取群组成员列表信息 * @param groupId - 群组 ID */ reqGroupMembers?(groupId: string): Promise<IGroupMemberProfile[]>; } /** * 消息信息 * @category Interface */ interface IKitMessage extends IKitMessageCache { user: { nickname: string; portraitUri: string; groupNickname?: string; }; } /** * @category Interface */ interface IKitMessageCache extends IAReceivedMessage { /** * 媒体消息本地临时路径 */ localTmpPath?: string; /** * V5 已读信息(UI 绑定使用) */ readReceiptInfo?: ReadReceiptInfoV5; } /** * 内存态会话更新信息 * @category Interface */ interface IConversationUpdate { /** * 置顶变更 */ isTop?: boolean; /** * 免打扰状态变更 */ notificationLevel?: NotificationLevel; /** * 未读数变更 */ unreadCount?: number; /** * 会话最后一条消息变更 */ latestMessage?: IAReceivedMessage | null; /** * 会话草稿变更 */ draft?: string; /** * 会话最新消息的 V5 已读信息变更 */ readReceiptInfo?: ReadReceiptInfoV5; } /** * 媒体消息参数 * @category Interface */ interface IKitMediaMessageOptions { /** * 会话 key */ conversationKey: string; /** * 消息 */ message: BaseMessage; /** * 发送消息选项 */ sendOptions?: ISendMessageOptions; /** * 上传信息 */ info: IKitUploadInfo; /** * 上传请求器 */ request: AKitUploadRequest; } /** * 消息列表状态管理 * @category class */ declare class RCKitMessageStore { #private; private readonly _logger; private rootStore; private _context; /** * @hidden */ constructor(_logger: ILogger, rootStore: RCKitStore, _context: PluginContext); getMessages(conversationKey: string): IKitMessage[]; /** * 根据会话信息 + messageUId 获取内存中的消息对象(若存在) */ getMessageByUid(conversation: IConversationOption, messageUId: string): IKitMessage | undefined; /** * 获取历史消息 * @param conversationKey 会话ID * @param endTime 结束时间戳, 精确到 ms * @param lastMsgUId 上次查询的最后一条消息的 messageUId, 第一次不填 * @param limit 查询的数量, 默认 20 * @returns */ getHistoryMsgList(conversationKey: string, endTime: number, lastMsgUId?: string, limit?: number): Promise<IAsyncRes$1<GetHistoryMessageResult>>; /** * 从消息队列尾部插入一条消息,如果缓存中不存在消息所在会话,则不做任何操作 * @param message 消息对象 * @param isTrim 是否需要移除超出队列缓存上限部分,默认为 true */ insertMessage(message: IKitMessageCache, isTrim?: boolean, isLog?: boolean): IKitMessageCache; /** * 更新缓存中的消息,如果缓存中不存在则不做任何操作 * @param message 消息对象 * @returns */ updateCatchedMessage(message: IKitMessageCache): void; /** * 移除一条缓存中的消息 * @param message 消息对象 */ removeCatchedMessage(message: Pick<IAReceivedMessage, 'conversationType' | 'targetId' | 'channelId' | 'messageUId' | 'messageId'>): void; /** * 撤回消息 * @param message 消息对象 */ recallMessage(message: IAReceivedMessage): Promise<_rongcloud_engine.RCResult<IAReceivedMessage>>; /** * 发送消息 * @param message 消息实例 */ sendMessage(conversationKey: string, message: BaseMessage, options: ISendMessageOptions): Promise<IAsyncRes$1<IAReceivedMessage>>; /** * 发送媒体消息 */ sendMediaMessage(mediaOptions: IKitMediaMessageOptions): Promise<IAsyncRes$1<IAReceivedMessage>>; /** * 发送 V5 回执(对当前会话内指定消息) * messageUIds 需要根据内存态消息存储做校验去重、过滤缓存中非接收向、已有回执或不存在的消息 */ sendV5Receipts(conversation: IConversationOption, messageUIds: string[]): Promise<void>; /** * 拉取并绑定 V5 已读信息,刷新 UI */ fetchReadReceiptV5(conversation: IConversationOption, messageUIds: string[]): Promise<void>; /** * 获取指定消息的已读/未读用户(V5)- 分页接口 * * @param conversation 会话 * @param messageUId 消息 UId * @param options.type 可选,0=已读,1=未读;不传则同时查询两个列表 * @param options.pageTokenRead 已读列表翻页 token(当 type 为 0 或未传时生效) * @param options.pageTokenUnread 未读列表翻页 token(当 type 为 1 或未传时生效) * @param options.pageCount 每页数量,默认 100 * @param options.order 排序,默认 0(按阅读时间降序) */ getReadReceiptUsersV5(conversation: IConversationOption, messageUId: string, options?: { type?: 0 | 1; pageTokenRead?: string; pageTokenUnread?: string; pageCount?: number; order?: 0 | 1; }): Promise<{ read: { list: { id: string; name: string; portraitUri?: string | undefined; timestamp?: number | undefined; }[]; total: number; pageToken: string | undefined; }; unread: { list: { id: string; name: string; portraitUri?: string | undefined; timestamp?: number | undefined; }[]; total: number; pageToken: string | undefined; }; }>; /** * 转发消息 * @param conversationKey 会话ID * @param message 消息列表 */ forwardMessage(conversationKey: string, message: IAReceivedMessage): Promise<{ code: number; data?: IAReceivedMessage | undefined; }>; /** * 取消指定消息的上传请求 * @param messageId 消息ID */ cancelSendMediaMessage(messageId: number): void; /** * 获取选中的消息 */ getSelectedMessages(): IKitMessage[]; /** * 设置选中的消息 * @param messages 消息列表 */ setSelectedMessages(messages: IKitMessage[]): void; /** * 清理超出缓存上限的消息 * @param conversationKey 会话ID * @hidden */ clearExcessMessage(conversationKey: string): void; destroy(): void; /** * 清理内存数据 */ clearMemoryData(): void; } /** * Typing 状态管理器 * - 发送端:同一会话 6s 内只发一次 typing * - 接收端:维护会话下的 typing 用户列表,超时自动消失(基于 SDK 事件,SDK 自身会 6s 过期刷新) */ declare class RCKitTypingStore { #private; /** 6 秒防抖间隔 */ static readonly DISAPPEAR_INTERVAL = 6000; /** 支持 typing 的会话类型仅单聊 */ static readonly typingSupportTypes: ConversationType[]; /** key: `${conversationType};;;${targetId};;;${channelId||''}` → value: Map<userId, ITypingUser> */ typingMap: mobx.ObservableMap<string, Map<string, ITypingUser>>; constructor(); dispose(): void; /** 发送 typing 状态(限 ConversationType.PRIVATE) */ sendTyping(conversation: IConversationOption, typingContentType: string): Promise<void>; /** * 是否显示“正在输入中...”,并返回 typing 的用户列表 * 返回值说明: * - active: 是否有正在输入/说话的用户 * - list: typing 用户详细信息列表(ITypingUser) */ isTyping(conversation: IConversationOption): { active: boolean; list: ITypingUser[]; }; /** 发送端:发送了真实消息后,解除该会话 6s typing 发送限制 */ releaseTypingThrottle(conversation: IConversationOption): void; getTypingMapKey(conversation: IConversationOption): string; } /** * 会话管理模块 * @category class */ declare class RCKitConversationStore { #private; private _kitStore; /** * 当前打开的会话信息 */ openedConversation: IKitConversation | null; /** * 内存太缓存会话列表 */ conversations: IKitConversation[]; /** * @hidden */ constructor(_kitStore: RCKitStore, _logger: ILogger); /** * 获取更多会话(分页) * * 根据会话对象获取更多会话,若传入 null 则获取首页 * @param conversation 类型为 IKitConversation 的会话对象 * @param count 获取数量 * @returns 会话列表 */ getConversations(conversation?: IKitConversation | null, count?: number): { hasMore: boolean; code: _rongcloud_engine.ErrorCode; list: IKitConversation[]; isFirstScreen: boolean; } | undefined; /** * 打开会话 * * 传递 null 为清空当前选中会话 * @param conversation 会话对象 */ openConversation(conversation: IKitConversation | null): void; /** * 创建会话缓存数据对象,若已存在则直接返回 * @param conversation 会话对象 */ createCachedConversation(conversation: IConversationOption$1): IKitConversation; /** * 删除会话 * 可通过 trans2ConversationKey 生成会话 key * @param conversationKey 会话 key */ removeConversation(conversationKey: string): void; /** * 更新会话缓存数据 * @param conversationKey 会话 key * @param data 会话更新数据 */ updateCacheConversation(conversationKey: string, data: IConversationUpdate): void; /** * 获取所有会话的未读消息总数 */ getTotalUnreadCount(): number; /** * 清除会话未读消息 * 可通过 trans2ConversationKey 生成会话 key * @param conversationKey 会话 key */ clearUnreadCount(conversationKey: string): Promise<void>; /** * 清理内存数据 */ clearMemoryData(): void; /** * 销毁 */ destroy(): void; } /** * 语音转文字内存态管理器 * - 仅缓存成功结果,按 messageUId 作为 key * - LRU 上限 200 条 */ declare class SpeechToTextStore { #private; private readonly _logger; /** 仅存储成功转换的文本结果(可观察 Map,确保 UI 响应式) */ cache: mobx.ObservableMap<string, string>; /** 正在转换中的 messageUId 集合 */ converting: mobx.ObservableSet<string>; /** 转换失败的 messageUId 集合(用于 UI 标记,可重试) */ error: mobx.ObservableSet<string>; /** 缓存最大条数(LRU) */ static readonly MAX_CACHE_SIZE = 200; /** 请求超时时间(毫秒) */ static readonly REQUEST_TIMEOUT = 30000; constructor(_logger: ILogger); /** 获取转换文本(命中缓存时返回) */ getSTTText(messageUId: string): string | undefined; /** 是否处于转换中 */ isConverting(messageUId: string): boolean; /** 是否处于失败态 */ hasError(messageUId: string): boolean; /** * 发起语音转文字请求:若缓存命中或正在转换则直接返回 SUCCESS */ requestForMessage(message: Pick<IAReceivedMessage, 'messageUId' | 'messageType' | 'content'>): Promise<ErrorCode>; /** 清理内存态数据 */ clearMemoryData(): void; /** 销毁 */ destroy(): void; } /** * 群组成员缓存 * @category class */ declare class GroupMembersCache { #private; private logger; private dataSource; /** * @hidden */ constructor(logger: ILogger, dataSource: IDataSource); /** * 初始化群组成员信息 * @param groupId 群组 ID * @hidden */ initGroupMembers(groupId: string): Promise<void>; /** * 获取群组成员信息 * @param groupId 群组 ID */ getGroupMembers(groupId: string): IGroupMemberProfile[]; /** * 获取群组成员信息 * @param groupId 群组 ID * @param userId 用户 ID */ getGroupMember(groupId: string, userId: string): IGroupMemberProfile | undefined; /** * 获取群组成员信息 map * @param groupId 群组 ID * @hidden */ getGroupMemberMap(groupId: string): Map<string, IGroupMemberProfile>; /** * 清理内存数据 */ clearMemoryData(): void; } /** * 用户数据模块 * @category class */ declare class AppDataModule { #private; private logger; groupMembersCache: GroupMembersCache; /** * @hidden */ constructor(logger: ILogger, hooks?: IKitServiceHooks); /** * 获取用户信息 * @param userId - 用户 ID * @returns 用户信息 */ getUserProfile(userId: string): IUserProfile | undefined; /** * 获取群组信息 * @param groupId - 群组 ID * @returns 群组信息 */ getGroupProfile(groupId: string): IGroupProfile | undefined; /** * 获取系统信息 * @param systemId - 系统 ID * @returns 系统信息 */ getSystemProfile(systemId: string): ISystemProfile | undefined; /** * 获取本地用户信息 * @param userId - 用户 ID * @returns 用户信息 */ getUserInfo(userId: string): IUserProfile | undefined; /** * @hidden */ getUsersCache(): CacheType<IUserProfile>; /** * @hidden */ getGroupsCache(): CacheType<IGroupProfile>; /** * @hidden */ getSystemsCache(): CacheType<ISystemProfile>; /** * 更新用户信息 * 如果 profile 不为空,查询缓存中是否存在,如果存在,更新缓存,如果不存在,则添加到缓存中 * 如果 profile 为空,请求远端数据补充到缓存中 * @param userId - 用户 ID * @param profile - 用户信息 */ updateUserProfile(userId: string, profile?: IUserProfile): void; /** * 更新群组信息 * @param groupId - 群组 ID * @param profile - 群组信息 * 如果 profile 不为空,查询缓存中是否存在,如果存在,更新缓存,如果不存在,则添加到缓存中 * 如果 profile 为空,请求远端数据补充到缓存中 */ updateGroupProfile(groupId: string, profile?: IGroupProfile): void; /** * 更新系统信息 * @param systemId - 系统 ID * @param profile - 系统信息 * 如果 profile 不为空,查询缓存中是否存在,如果存在,更新缓存,如果不存在,则添加到缓存中 * 如果 profile 为空,请求远端数据补充到缓存中 */ updateSystemProfile(systemId: string, profile?: ISystemProfile): void; /** * 获取会话信息 * @param id - 会话 ID * @param type - 类型 * @returns 会话信息 */ getProfileSync(id: string, type: ConversationType$1): Promise<IUserProfile | IGroupProfile | ISystemProfile | undefined>; /** * 清理内存数据 */ clearMemoryData(): void; } /** * @category class */ declare class RCKitStore { #private; private _context; private readonly _logger; private _option; /** * 消息状态管理器 */ messageStore: RCKitMessageStore; /** * 会话状态管理器 */ conversationStore: RCKitConversationStore; /** * 输入状态管理器 */ typingStore: RCKitTypingStore; /** * 语音转文字状态管理器 */ speechToTextStore: SpeechToTextStore; /** * 用户数据模块 */ appData: AppDataModule; /** * 当前用户 Id */ currentUserId: string; /** * 当前连接状态 */ connectStatus: mobx.IObservableValue<RCConnectionStatus>; get enableReadV5(): boolean; /** * @hidden */ constructor(_context: PluginContext, _logger: ILogger, _option: IRCStoreInitOpts); /** * 设置已读 V5 开关(结合服务端 getAppSettings 结果) */ setEnableReadV5(enable: boolean): void; private _onConnected; private _onDisconnected; private _onSuspend; private _onConnecting; /** * 销毁 */ destroy(): void; /** * 清理内存数据 */ clearMemoryData(): void; } /** * kit store 初始化 * @param option 初始化参数 * @category function */ declare const RCKitStoreInstaller: (option: IRCStoreInitOpts) => RCKitStore | null; /** * 根据会话 targetId、conversationType、channelId 生成的唯一标识 * @category function */ declare const trans2ConversationKey: (conversation: IConversationOption$1) => string; /** * 创建日志代理 * 1. 日志代理需要运行在 uni-app 环境 * 2. 日志代理仅支持 CustomLogPlatform 中的平台 * @returns 日志代理 */ declare function createIMLogProxy(): Promise<LogDBProxy | null>; /** * 销毁日志代理 */ declare function destroyIMLogProxy(): void; export { AKitUploadRequest, AppDataModule, CacheType, GroupMembersCache, IBaseProfile, IConversationUpdate, IDataSource, IGroupMemberProfile, IGroupProfile, IKitConversation, IKitImageInfo, IKitMediaMessageOptions, IKitMessage, IKitMessageCache, IKitServiceHooks, IKitThumbnailConfig, IKitUploadCompleteData, IKitUploadInfo, IKitUploadRequestData, IKitUploadResult, IRCStoreInitOpts, ISystemProfile, IUserProfile, RCKitConversationStore, RCKitMessageStore, RCKitStore, RCKitStoreInstaller, RCKitTypingStore, createIMLogProxy, destroyIMLogProxy, trans2ConversationKey };