92 lines
2.5 KiB
TypeScript
92 lines
2.5 KiB
TypeScript
|
|
/**
|
||
|
|
* 已读回执管理器
|
||
|
|
* 负责处理消息已读状态的同步
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { messageService } from '../../services/messageService';
|
||
|
|
import { messageRepository } from '../../data/repositories/MessageRepository';
|
||
|
|
import type { MessageStateManager } from './MessageStateManager';
|
||
|
|
|
||
|
|
export interface ReadReceiptResult {
|
||
|
|
conversationId: string;
|
||
|
|
lastReadSeq: number;
|
||
|
|
success: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
export class ReadReceiptManager {
|
||
|
|
private pendingOperations: Map<string, Promise<void>> = new Map();
|
||
|
|
private stateManager: MessageStateManager | null = null;
|
||
|
|
|
||
|
|
setStateManager(manager: MessageStateManager): void {
|
||
|
|
this.stateManager = manager;
|
||
|
|
}
|
||
|
|
|
||
|
|
async markAsRead(
|
||
|
|
conversationId: string,
|
||
|
|
lastSeq: number
|
||
|
|
): Promise<ReadReceiptResult> {
|
||
|
|
const existing = this.pendingOperations.get(conversationId);
|
||
|
|
if (existing) {
|
||
|
|
await existing;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!this.stateManager) {
|
||
|
|
throw new Error('StateManager not set');
|
||
|
|
}
|
||
|
|
|
||
|
|
const version = this.stateManager.beginReadOperation(conversationId);
|
||
|
|
|
||
|
|
const promise = this.executeMarkAsRead(conversationId, lastSeq, version);
|
||
|
|
this.pendingOperations.set(conversationId, promise);
|
||
|
|
|
||
|
|
try {
|
||
|
|
await promise;
|
||
|
|
return { conversationId, lastReadSeq: lastSeq, success: true };
|
||
|
|
} catch (error) {
|
||
|
|
console.error('[ReadReceiptManager] Failed to mark as read:', error);
|
||
|
|
return { conversationId, lastReadSeq: lastSeq, success: false };
|
||
|
|
} finally {
|
||
|
|
this.pendingOperations.delete(conversationId);
|
||
|
|
this.stateManager.endReadOperation(conversationId);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private async executeMarkAsRead(
|
||
|
|
conversationId: string,
|
||
|
|
lastSeq: number,
|
||
|
|
version: number
|
||
|
|
): Promise<void> {
|
||
|
|
await messageService.markAsRead(conversationId, lastSeq);
|
||
|
|
|
||
|
|
await messageRepository.markConversationAsRead(conversationId);
|
||
|
|
|
||
|
|
if (this.stateManager) {
|
||
|
|
this.stateManager.updateConversation(conversationId, {
|
||
|
|
unreadCount: 0,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async markAllAsRead(): Promise<void> {
|
||
|
|
if (!this.stateManager) return;
|
||
|
|
|
||
|
|
const conversations = this.stateManager.getConversations();
|
||
|
|
const unreadConversations = conversations.filter(c => c.unreadCount > 0);
|
||
|
|
|
||
|
|
await Promise.all(
|
||
|
|
unreadConversations.map(conv =>
|
||
|
|
this.markAsRead(conv.id, conv.lastSeq)
|
||
|
|
)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
isPending(conversationId: string): boolean {
|
||
|
|
return this.pendingOperations.has(conversationId);
|
||
|
|
}
|
||
|
|
|
||
|
|
reset(): void {
|
||
|
|
this.pendingOperations.clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const readReceiptManager = new ReadReceiptManager();
|