/** * 消息同步服务 * 负责从服务器同步消息和会话 */ import { messageService } from '../../services/messageService'; import { messageRepository } from '../../data/repositories/MessageRepository'; import type { Message, Conversation } from '../../core/entities/Message'; import type { ConversationResponse, MessageResponse } 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 = await messageService.getConversations(); const conversations = this.mapConversations(response); 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 = await messageService.getMessages(conversationId, { after_seq: lastSeq, limit: 50, }); const messages = this.mapMessages(response.messages || []); if (messages.length > 0) { await messageRepository.saveMessages(messages, true); } return { conversations: [], messages, hasMore: response.has_more || false, }; } 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 = await messageService.getMessages(conversationId, { before_seq: 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(response: ConversationResponse[]): Conversation[] { return response.map(conv => ({ id: conv.id, type: conv.type || 'private', isPinned: conv.isPinned || false, lastSeq: conv.lastSeq || conv.last_seq || 0, lastMessageAt: conv.lastMessageAt || conv.last_message_at || new Date().toISOString(), unreadCount: conv.unreadCount || conv.unread_count || 0, participants: conv.participants || [], group: conv.group, createdAt: conv.createdAt || conv.created_at || new Date().toISOString(), updatedAt: conv.updatedAt || conv.updated_at || new Date().toISOString(), })); } private mapMessages(response: MessageResponse[]): Message[] { return response.map(msg => ({ id: msg.id, conversationId: msg.conversationId || msg.conversation_id || '', senderId: msg.senderId || msg.sender_id || '', seq: msg.seq || 0, segments: msg.segments || [], createdAt: msg.createdAt || msg.created_at || new Date().toISOString(), status: msg.status || 'normal', sender: msg.sender, })); } isSyncingConversations(): boolean { return this.syncingConversations; } isSyncingMessages(conversationId: string): boolean { return this.syncingMessages.get(conversationId) || false; } } export const messageSyncService = new MessageSyncService();