/** * MessageManager - 重构版 * 作为协调者,整合各个专注的服务模块 */ import { messageStateManager, MessageStateManager } from './MessageStateManager'; import { wsMessageHandler, WSMessageHandler } from './WSMessageHandler'; import { messageSyncService, MessageSyncService } from './MessageSyncService'; import { readReceiptManager, ReadReceiptManager } from './ReadReceiptManager'; import { messageRepository } from '../../data/repositories/MessageRepository'; import { useAuthStore } from '../authStore'; import type { Message, Conversation } from '../../core/entities/Message'; import type { ConversationResponse, MessageResponse } from '../../types/dto'; export type { MessageEventType, MessageEvent, MessageSubscriber, } from './MessageStateManager'; export class MessageManager { private stateManager: MessageStateManager; private wsHandler: WSMessageHandler; private syncService: MessageSyncService; private readManager: ReadReceiptManager; private initialized: boolean = false; private authUnsubscribe: (() => void) | null = null; private wsUnsubscribe: (() => void) | null = null; private currentUserId: string | null = null; constructor() { this.stateManager = messageStateManager; this.wsHandler = wsMessageHandler; this.syncService = messageSyncService; this.readManager = readReceiptManager; this.readManager.setStateManager(this.stateManager); this.setupWSHandlers(); this.initAuthListener(); } private initAuthListener(): void { const authState = useAuthStore.getState(); this.currentUserId = authState.currentUser?.id || null; if (this.currentUserId && !this.initialized) { this.initialize(); } this.authUnsubscribe = useAuthStore.subscribe((state) => { const nextUserId = state.currentUser?.id || null; this.currentUserId = nextUserId; if (nextUserId && !this.initialized) { this.initialize(); } }); } private setupWSHandlers(): void { this.wsUnsubscribe = this.wsHandler.subscribe((event) => { switch (event.type) { case 'chat_message': case 'group_message': this.handleNewMessage(event.payload); break; case 'read_receipt': case 'group_read_receipt': this.handleReadReceipt(event.payload); break; case 'message_recalled': case 'group_message_recalled': this.handleMessageRecall(event.payload); break; case 'typing': this.handleTypingStatus(event.payload); break; case 'group_notice': this.handleGroupNotice(event.payload); break; } }); } async initialize(): Promise { if (this.initialized) return; try { console.log('[MessageManager] Initializing...'); this.wsHandler.connect(); const conversations = await this.syncService.syncConversations(); this.stateManager.setConversations(conversations); this.initialized = true; console.log('[MessageManager] Initialized successfully'); } catch (error) { console.error('[MessageManager] Initialization failed:', error); throw error; } } async activateConversation(conversationId: string): Promise { this.stateManager.setCurrentConversation(conversationId); const existing = this.stateManager.getMessages(conversationId); if (existing.length === 0) { await this.loadMessages(conversationId); } const conversation = this.stateManager.getConversation(conversationId); if (conversation && conversation.unreadCount > 0) { await this.readManager.markAsRead(conversationId, conversation.lastSeq); } } deactivateConversation(): void { this.stateManager.setCurrentConversation(null); } async loadMessages(conversationId: string): Promise { const localMessages = await this.syncService.loadLocalMessages(conversationId); if (localMessages.length > 0) { this.stateManager.setMessages(conversationId, localMessages); } const syncResult = await this.syncService.syncMessages(conversationId); if (syncResult.messages.length > 0) { this.stateManager.appendMessages(conversationId, syncResult.messages); return [...localMessages, ...syncResult.messages]; } return localMessages; } async loadHistory(conversationId: string): Promise { const messages = this.stateManager.getMessages(conversationId); const oldestSeq = messages.length > 0 ? Math.min(...messages.map(m => m.seq)) : 0; const history = await this.syncService.loadHistoryMessages( conversationId, oldestSeq, 20 ); if (history.length > 0) { this.stateManager.prependMessages(conversationId, history); } return history; } async sendMessage( conversationId: string, content: string, type: 'private' | 'group' = 'private' ): Promise { throw new Error('sendMessage not implemented - use existing implementation'); } private async handleNewMessage(message: Message): Promise { await messageRepository.saveMessage(message, true); this.stateManager.addMessage(message.conversationId, message); const currentConvId = this.stateManager.getCurrentConversationId(); if (currentConvId !== message.conversationId) { const conv = this.stateManager.getConversation(message.conversationId); if (conv) { this.stateManager.updateConversation(message.conversationId, { unreadCount: (conv.unreadCount || 0) + 1, lastSeq: message.seq, lastMessageAt: message.createdAt, }); } } } private handleReadReceipt(payload: any): void { const { conversationId, lastReadSeq } = payload; this.stateManager.updateConversation(conversationId, { unreadCount: 0, }); } private async handleMessageRecall(payload: any): Promise { const { messageId, conversationId } = payload; await messageRepository.updateMessageStatus(messageId, 'recalled', true); this.stateManager.updateMessage(conversationId, messageId, { status: 'recalled', }); } private handleTypingStatus(payload: any): void { const { groupId, userIds } = payload; this.stateManager.setTypingUsers(groupId, userIds); } private handleGroupNotice(notice: any): void { console.log('[MessageManager] Group notice:', notice); } subscribe(callback: any): () => void { return this.stateManager.subscribe(callback); } getConversations(): Conversation[] { return this.stateManager.getConversations(); } getMessages(conversationId: string): Message[] { return this.stateManager.getMessages(conversationId); } getUnreadCount(): { total: number; system: number } { return this.stateManager.getUnreadCount(); } isConnected(): boolean { return this.wsHandler.isConnected(); } reset(): void { this.initialized = false; this.stateManager.reset(); this.readManager.reset(); this.wsHandler.disconnect(); } destroy(): void { if (this.authUnsubscribe) { this.authUnsubscribe(); this.authUnsubscribe = null; } if (this.wsUnsubscribe) { this.wsUnsubscribe(); this.wsUnsubscribe = null; } this.reset(); } } export const messageManager = new MessageManager(); export default messageManager;