/** * MessageManager - 消息管理核心模块(重构版) * * 作为协调者,整合各个专注的服务模块 * 保持与原始版本完全兼容的 API */ import type { ConversationResponse, MessageResponse, MessageSegment, UserDTO } from '../../types/dto'; import { messageService } from '../../services/messageService'; import { wsService, WSChatMessage, WSGroupChatMessage, WSReadMessage, WSGroupReadMessage, WSRecallMessage, WSGroupRecallMessage, WSGroupTypingMessage, WSGroupNoticeMessage, GroupNoticeType, } from '../../services/wsService'; import { saveMessage, saveMessagesBatch, getMessagesByConversation, getMaxSeq, getMinSeq, getMessagesBeforeSeq, markConversationAsRead, updateConversationCacheUnreadCount, CachedMessage, getUserCache, saveUserCache, updateMessageStatus, deleteConversation as deleteConversationFromDb, saveConversationsWithRelatedCache, } from '../../services/database'; import { api } from '../../services/api'; import { vibrateOnMessage } from '../../services/messageVibrationService'; import { useAuthStore } from '../authStore'; import { type IConversationListPagedSource, SqliteConversationListPagedSource, createRemoteConversationListSource, CONVERSATION_LIST_PAGE_SIZE, } from '../conversationListSources'; // 导入新模块 import { MessageStateManager } from './MessageStateManager'; import { MessageDeduplication } from './MessageDeduplication'; import { UserCacheService } from './UserCacheService'; import { ReadReceiptManager } from './ReadReceiptManager'; import { ConversationOperations } from './ConversationOperations'; import { MessageSendService } from './MessageSendService'; import { MessageSyncService } from './MessageSyncService'; import { WSMessageHandler } from './WSMessageHandler'; // 重新导出类型,保持兼容性 export type { MessageEventType, MessageEvent, MessageSubscriber, MessageManagerState, ReadStateRecord, MessageManagerConversationListDeps, } from './types'; // ==================== MessageManager 类 ==================== class MessageManager { // 子模块 private stateManager: MessageStateManager; private deduplication: MessageDeduplication; private userCacheService: UserCacheService; private readReceiptManager: ReadReceiptManager; private conversationOps: ConversationOperations; private sendService: MessageSendService; private syncService: MessageSyncService; private wsHandler: WSMessageHandler; // 本地状态 private currentUserId: string | null = null; private authUnsubscribe: (() => void) | null = null; private initializePromise: Promise | null = null; private activatingConversationTasks: Map> = new Map(); constructor(deps?: import('./types').MessageManagerConversationListDeps) { // 初始化子模块 this.stateManager = new MessageStateManager(); this.deduplication = new MessageDeduplication(); this.userCacheService = new UserCacheService(); this.readReceiptManager = new ReadReceiptManager(this.stateManager); this.conversationOps = new ConversationOperations(this.stateManager); this.sendService = new MessageSendService(this.stateManager, () => this.getCurrentUserId()); this.syncService = new MessageSyncService( this.stateManager, () => this.getCurrentUserId(), deps ); this.wsHandler = new WSMessageHandler( this.stateManager, this.deduplication, this.userCacheService, () => this.getCurrentUserId(), { markAsRead: (id, seq) => this.markAsRead(id, seq), fetchConversations: (force, source) => this.fetchConversations(force, source), fetchUnreadCount: () => this.fetchUnreadCount(), fetchMessages: (id) => this.fetchMessages(id), } ); // 监听认证状态变化 this.initAuthListener(); } // ==================== 私有工具方法 ==================== private initAuthListener() { const authState = useAuthStore.getState(); this.currentUserId = authState.currentUser?.id || null; if (this.currentUserId && !this.stateManager.getState().isInitialized) { this.initialize(); } if (!this.authUnsubscribe) { this.authUnsubscribe = useAuthStore.subscribe((state) => { const nextUserId = state.currentUser?.id || null; const prevUserId = this.currentUserId; this.currentUserId = nextUserId; if (nextUserId && !this.stateManager.getState().isInitialized) { this.initialize(); } if (nextUserId && this.stateManager.getActiveConversation()) { this.activateConversation(this.stateManager.getActiveConversation()!, { forceSync: true }).catch(error => { console.error('[MessageManager] 登录态就绪后重激活会话失败:', error); }); } if (!nextUserId && prevUserId && this.stateManager.getState().isInitialized) { this.destroy(); } }); } } private getCurrentUserId(): string | null { if (!this.currentUserId) { this.currentUserId = useAuthStore.getState().currentUser?.id || null; } return this.currentUserId; } private normalizeConversationId(conversationId: string | number | null | undefined): string { return conversationId == null ? '' : String(conversationId); } // ==================== 初始化与销毁 ==================== async initialize(): Promise { if (this.stateManager.getState().isInitialized) { return; } if (this.initializePromise) { await this.initializePromise; return; } this.initializePromise = (async () => { try { this.currentUserId = this.getCurrentUserId(); if (!this.currentUserId) { console.warn('[MessageManager] 用户未登录,延迟初始化'); return; } this.wsHandler.setBootstrapping(true); // 初始化SSE监听 this.wsHandler.connect(); // 加载会话列表 await this.fetchConversations(false, 'initialize'); // 加载未读数 await this.fetchUnreadCount(); this.stateManager.setInitialized(true); // 处理缓冲的 SSE 事件 await this.wsHandler.flushBufferedSSEEvents(); this.wsHandler.setBootstrapping(false); this.stateManager.notifySubscribers({ type: 'conversations_updated', payload: { conversations: this.stateManager.getConversations() }, timestamp: Date.now(), }); if (this.stateManager.getActiveConversation()) { await this.fetchMessages(this.stateManager.getActiveConversation()!); } } catch (error) { console.error('[MessageManager] 初始化失败:', error); this.wsHandler.setBootstrapping(false); this.stateManager.notifySubscribers({ type: 'error', payload: { error, context: 'initialize' }, timestamp: Date.now(), }); } })(); try { await this.initializePromise; } finally { this.initializePromise = null; } } destroy(): void { this.wsHandler.disconnect(); this.stateManager.reset(); this.syncService.restartSources(); this.readReceiptManager.reset(); this.deduplication.reset(); this.userCacheService.reset(); this.activatingConversationTasks.clear(); this.initializePromise = null; } // ==================== 数据获取方法(代理到 syncService)==================== async fetchConversations(forceRefresh = false, source: string = 'unknown'): Promise { return this.syncService.fetchConversations(forceRefresh, source); } async loadMoreConversations(): Promise { return this.syncService.loadMoreConversations(); } async fetchConversationDetail(conversationId: string): Promise { return this.syncService.fetchConversationDetail(conversationId); } async fetchMessages(conversationId: string, afterSeq?: number): Promise { return this.syncService.fetchMessages(conversationId, afterSeq); } async loadMoreMessages(conversationId: string, beforeSeq: number, limit = 20): Promise { return this.syncService.loadMoreMessages(conversationId, beforeSeq, limit); } async fetchUnreadCount(): Promise { return this.syncService.fetchUnreadCount(); } // ==================== 数据操作方法(代理到各服务)==================== async sendMessage( conversationId: string, segments: MessageSegment[], options?: { replyToId?: string } ): Promise { return this.sendService.sendMessage(conversationId, segments, options); } async markAsRead(conversationId: string, seq: number): Promise { return this.readReceiptManager.markAsRead(conversationId, seq); } async markAllAsRead(): Promise { return this.readReceiptManager.markAllAsRead(); } async createConversation(userId: string): Promise { return this.conversationOps.createConversation(userId); } updateConversation(conversationId: string, updates: Partial): void { return this.conversationOps.updateConversation(conversationId, updates); } removeConversation(conversationId: string): void { return this.conversationOps.removeConversation(conversationId); } clearConversations(): void { return this.conversationOps.clearConversations(); } updateUnreadCount(conversationId: string, count: number): void { return this.conversationOps.updateUnreadCount(conversationId, count); } setSystemUnreadCount(count: number): void { return this.conversationOps.setSystemUnreadCount(count); } incrementSystemUnreadCount(): void { return this.conversationOps.incrementSystemUnreadCount(); } decrementSystemUnreadCount(count?: number): void { return this.conversationOps.decrementSystemUnreadCount(count); } // ==================== 状态查询方法(代理到 stateManager)==================== getConversations(): ConversationResponse[] { return this.stateManager.getConversations(); } getConversation(conversationId: string): ConversationResponse | null { return this.stateManager.getConversation(conversationId); } getMessages(conversationId: string): MessageResponse[] { return this.stateManager.getMessages(conversationId); } getUnreadCount(): { total: number; system: number } { return this.stateManager.getUnreadCount(); } isConnected(): boolean { return this.stateManager.isConnected(); } isLoading(): boolean { return this.stateManager.isLoading(); } isLoadingMessages(conversationId: string): boolean { return this.stateManager.isLoadingMessages(conversationId); } getTypingUsers(groupId: string): string[] { return this.stateManager.getTypingUsers(groupId); } isMuted(groupId: string): boolean { return this.stateManager.isMuted(groupId); } setMutedStatus(groupId: string, isMuted: boolean): void { return this.stateManager.setMutedStatus(groupId, isMuted); } // ==================== 活动会话管理 ==================== setActiveConversation(conversationId: string | null): void { const normalizedId = conversationId ? this.normalizeConversationId(conversationId) : null; this.stateManager.setCurrentConversation(normalizedId); } getActiveConversation(): string | null { return this.stateManager.getActiveConversation(); } async activateConversation(conversationId: string, options?: { forceSync?: boolean }): Promise { const normalizedId = this.normalizeConversationId(conversationId); if (!normalizedId) return; await this.initialize(); this.setActiveConversation(normalizedId); // 先下发当前内存快照 const snapshot = this.getMessages(normalizedId); this.stateManager.notifySubscribers({ type: 'messages_updated', payload: { conversationId: normalizedId, messages: [...snapshot], source: 'activation_snapshot', }, timestamp: Date.now(), }); const existingTask = this.activatingConversationTasks.get(normalizedId); if (existingTask && !options?.forceSync) { await existingTask; return; } const task = (async () => { await this.fetchMessages(normalizedId); })(); this.activatingConversationTasks.set(normalizedId, task); try { await task; } finally { if (this.activatingConversationTasks.get(normalizedId) === task) { this.activatingConversationTasks.delete(normalizedId); } } } // ==================== 订阅机制 ==================== subscribe(subscriber: import('./types').MessageSubscriber): () => void { const unsubscribe = this.stateManager.subscribe(subscriber); // 立即发送当前状态给新订阅者(与原始版本保持一致) subscriber({ type: 'conversations_updated', payload: { conversations: this.stateManager.getConversations() }, timestamp: Date.now(), }); const unreadCount = this.stateManager.getUnreadCount(); subscriber({ type: 'unread_count_updated', payload: { totalUnreadCount: unreadCount.total, systemUnreadCount: unreadCount.system, }, timestamp: Date.now(), }); subscriber({ type: 'connection_changed', payload: { connected: this.stateManager.isConnected() }, timestamp: Date.now(), }); // 如果当前有活动会话,立即发送该会话的消息给新订阅者 const activeConversationId = this.stateManager.getActiveConversation(); if (activeConversationId) { const currentMessages = this.stateManager.getMessages(activeConversationId); if (currentMessages.length > 0) { subscriber({ type: 'messages_updated', payload: { conversationId: activeConversationId, messages: [...currentMessages], source: 'initial_sync', }, timestamp: Date.now(), }); } } return unsubscribe; } subscribeToMessages(conversationId: string, callback: (messages: MessageResponse[]) => void): () => void { return this.stateManager.subscribe((event) => { if (event.type === 'messages_updated' && event.payload.conversationId === conversationId) { callback(event.payload.messages); } }); } // ==================== 其他方法 ==================== canLoadMoreConversations(): boolean { return this.syncService.canLoadMoreConversations(); } invalidateCache(_type?: 'all' | 'list' | 'unread'): void { // 兼容性方法,新架构不需要外部缓存 } async requestConversationListRefresh( source: string, options?: { force?: boolean; allowDefer?: boolean } ): Promise { const forceRefresh = options?.force ?? true; const allowDefer = options?.allowDefer ?? true; if (allowDefer && this.shouldDeferConversationRefresh(source, forceRefresh)) { // 延迟刷新逻辑在 syncService 中处理 return; } await this.fetchConversations(forceRefresh, source); } private shouldDeferConversationRefresh(source: string, forceRefresh: boolean): boolean { if (!this.stateManager.getActiveConversation()) return false; if (!forceRefresh) return false; return source === 'sse-reconnect' || source === 'prefetch' || source === 'hooks-initial-refresh'; } } // ==================== 单例导出 ==================== export const messageManager = new MessageManager(); // 导出类以支持类型检查和测试 export { MessageManager }; export default messageManager;