/** * 消息同步服务 * 负责从服务器同步消息和会话 */ import { messageService } from '../../services/messageService'; import { messageRepository } from '../../data/repositories/MessageRepository'; import type { Message, Conversation } from '../../core/entities/Message'; import type { ConversationListResponse, MessageListResponse } from '../../types/dto'; export interface SyncOptions { force?: boolean; lastSeq?: number; } export interface SyncResult { conversations: Conversation[]; messages: Message[]; hasMore: boolean; } export class MessageSyncService { private syncingConversations: boolean = false; private syncingMessages: Map = new Map(); async syncConversations(): Promise { if (this.syncingConversations) { console.log('[MessageSyncService] Already syncing conversations'); return []; } this.syncingConversations = true; try { const response: ConversationListResponse = await messageService.getConversations(); const conversations = this.mapConversations(response.list || []); return conversations; } catch (error) { console.error('[MessageSyncService] Failed to sync conversations:', error); throw error; } finally { this.syncingConversations = false; } } async syncMessages( conversationId: string, options: SyncOptions = {} ): Promise { const key = conversationId; if (this.syncingMessages.get(key)) { console.log('[MessageSyncService] Already syncing messages for:', conversationId); return { conversations: [], messages: [], hasMore: false }; } this.syncingMessages.set(key, true); try { const lastSeq = options.lastSeq ?? await messageRepository.getMaxSeq(conversationId); const response: MessageListResponse = await messageService.getMessages( conversationId, lastSeq, undefined, 50 ); const messages = this.mapMessages(response.messages || []); if (messages.length > 0) { await messageRepository.saveMessages(messages, true); } return { conversations: [], messages, hasMore: messages.length >= 50, }; } catch (error) { console.error('[MessageSyncService] Failed to sync messages:', error); throw error; } finally { this.syncingMessages.delete(key); } } async loadHistoryMessages( conversationId: string, beforeSeq: number, limit: number = 20 ): Promise { try { const response: MessageListResponse = await messageService.getMessages( conversationId, undefined, beforeSeq, limit ); const messages = this.mapMessages(response.messages || []); if (messages.length > 0) { await messageRepository.saveMessages(messages, true); } return messages; } catch (error) { console.error('[MessageSyncService] Failed to load history:', error); throw error; } } async loadLocalMessages( conversationId: string, limit: number = 50 ): Promise { return messageRepository.getMessagesByConversation(conversationId, limit); } async loadHistoryFromLocal( conversationId: string, beforeSeq: number, limit: number = 20 ): Promise { return messageRepository.getMessagesBeforeSeq(conversationId, beforeSeq, limit); } private mapConversations(list: ConversationListResponse['list']): Conversation[] { return list.map(conv => ({ id: conv.id, type: conv.type || 'private', isPinned: conv.is_pinned || false, lastSeq: conv.last_seq || 0, lastMessageAt: conv.last_message_at || new Date().toISOString(), unreadCount: conv.unread_count || 0, participants: (conv.participants || []).map(p => ({ id: p.id, username: p.username, avatar: p.avatar || undefined, nickname: p.nickname, })), group: conv.group ? { id: String(conv.group.id), name: conv.group.name, avatar: conv.group.avatar, } : undefined, createdAt: conv.created_at || new Date().toISOString(), updatedAt: conv.updated_at || new Date().toISOString(), })); } private mapMessages(messages: MessageListResponse['messages']): Message[] { return messages.map(msg => ({ id: msg.id, conversationId: msg.conversation_id, senderId: msg.sender_id, seq: msg.seq, segments: msg.segments || [], createdAt: msg.created_at, status: msg.status || 'normal', sender: msg.sender ? { id: msg.sender.id, username: msg.sender.username, avatar: msg.sender.avatar || undefined, nickname: msg.sender.nickname, } : undefined, })); } isSyncingConversations(): boolean { return this.syncingConversations; } isSyncingMessages(conversationId: string): boolean { return this.syncingMessages.get(conversationId) || false; } } export const messageSyncService = new MessageSyncService();