refactor(message): replace SubscriptionManager with Zustand selectors
Remove custom SubscriptionManager class and adopt Zustand's built-in selector mechanism for reactive state updates. This simplifies the architecture by eliminating manual subscription management and relying on Zustand's automatic dependency tracking for component re-renders. Key changes: - Remove SubscriptionManager class from store.ts - Replace all notifySubscribers calls with direct store updates - Update hooks to use Zustand selectors with useShallow for complex data - Remove subscribe/unsubscribe patterns from MessageManager - Simplify EmbeddedChat to use selector instead of local state - Rename requestConversationListRefresh to refreshConversations
This commit is contained in:
@@ -2,14 +2,16 @@
|
||||
* 会话操作服务
|
||||
* 处理会话的 CRUD 操作
|
||||
*
|
||||
* 重构说明:直接使用 zustand store 替代 IMessageStateManager
|
||||
* 重构说明:
|
||||
* - 直接使用 zustand store 替代 IMessageStateManager
|
||||
* - 移除了 SubscriptionManager 调用,Zustand 的 set() 会自动触发组件重渲染
|
||||
*/
|
||||
|
||||
import type { ConversationResponse } from '../../../types/dto';
|
||||
import { messageService } from '../../../services/messageService';
|
||||
import { deleteConversation } from '../../../services/database';
|
||||
import type { IConversationOperations } from '../types';
|
||||
import { useMessageStore, subscriptionManager, normalizeConversationId } from '../store';
|
||||
import { useMessageStore, normalizeConversationId } from '../store';
|
||||
|
||||
export class ConversationOperations implements IConversationOperations {
|
||||
/**
|
||||
@@ -24,21 +26,9 @@ export class ConversationOperations implements IConversationOperations {
|
||||
// 添加到会话列表
|
||||
store.updateConversation(conversation);
|
||||
|
||||
// 通知更新
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
return conversation;
|
||||
} catch (error) {
|
||||
console.error('[ConversationOperations] 创建会话失败:', error);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'error',
|
||||
payload: { error, context: 'createConversation' },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -60,13 +50,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
};
|
||||
|
||||
store.updateConversation(updatedConv);
|
||||
|
||||
// 通知更新
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,23 +59,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
const store = useMessageStore.getState();
|
||||
store.removeConversation(conversationId);
|
||||
|
||||
// 通知更新
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
const unreadCount = store.getUnreadCount();
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: unreadCount.total,
|
||||
systemUnreadCount: unreadCount.system,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 删除本地数据库中的会话
|
||||
deleteConversation(conversationId).catch(error => {
|
||||
console.error('[ConversationOperations] 删除本地会话失败:', error);
|
||||
@@ -105,21 +71,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
clearConversations(): void {
|
||||
const store = useMessageStore.getState();
|
||||
store.reset();
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: [] },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: 0,
|
||||
systemUnreadCount: 0,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,22 +100,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
Math.max(0, currentUnread.total + diff),
|
||||
currentUnread.system
|
||||
);
|
||||
|
||||
// 通知更新
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: store.getUnreadCount().total,
|
||||
systemUnreadCount: store.getUnreadCount().system,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,22 +126,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
currentUnread.total + 1,
|
||||
currentUnread.system
|
||||
);
|
||||
|
||||
// 通知更新
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: store.getUnreadCount().total,
|
||||
systemUnreadCount: store.getUnreadCount().system,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,15 +135,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
const store = useMessageStore.getState();
|
||||
const currentUnread = store.getUnreadCount();
|
||||
store.setUnreadCount(currentUnread.total, count);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: currentUnread.total,
|
||||
systemUnreadCount: count,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,15 +144,6 @@ export class ConversationOperations implements IConversationOperations {
|
||||
const store = useMessageStore.getState();
|
||||
const currentUnread = store.getUnreadCount();
|
||||
store.setUnreadCount(currentUnread.total, currentUnread.system + 1);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: currentUnread.total,
|
||||
systemUnreadCount: currentUnread.system + 1,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,14 +154,5 @@ export class ConversationOperations implements IConversationOperations {
|
||||
const currentUnread = store.getUnreadCount();
|
||||
const newSystemCount = Math.max(0, currentUnread.system - count);
|
||||
store.setUnreadCount(currentUnread.total, newSystemCount);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: currentUnread.total,
|
||||
systemUnreadCount: newSystemCount,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,16 @@
|
||||
* 消息发送服务
|
||||
* 处理消息发送相关逻辑
|
||||
*
|
||||
* 重构说明:直接使用 zustand store 替代 IMessageStateManager
|
||||
* 重构说明:
|
||||
* - 直接使用 zustand store 替代 IMessageStateManager
|
||||
* - 移除了 SubscriptionManager 调用,Zustand 的 set() 会自动触发组件重渲染
|
||||
*/
|
||||
|
||||
import type { MessageResponse, MessageSegment, ConversationResponse } from '../../../types/dto';
|
||||
import { messageService } from '../../../services/messageService';
|
||||
import { saveMessage } from '../../../services/database';
|
||||
import type { IMessageSendService } from '../types';
|
||||
import { useMessageStore, subscriptionManager, mergeMessagesById } from '../store';
|
||||
import { useMessageStore, mergeMessagesById } from '../store';
|
||||
|
||||
export class MessageSendService implements IMessageSendService {
|
||||
private getCurrentUserId: () => string | null;
|
||||
@@ -53,28 +55,9 @@ export class MessageSendService implements IMessageSendService {
|
||||
const updatedMessages = mergeMessagesById(existingMessages, [newMessage]);
|
||||
store.setMessages(conversationId, updatedMessages);
|
||||
|
||||
// 关键:立即广播消息列表更新
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: updatedMessages,
|
||||
newMessage,
|
||||
source: 'send',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 更新会话最后消息
|
||||
this.updateConversationWithNewMessage(conversationId, newMessage);
|
||||
|
||||
// 通知消息已发送
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'message_sent',
|
||||
payload: { conversationId, message: newMessage },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 保存到本地数据库
|
||||
const textContent = segments
|
||||
?.filter((s: any) => s.type === 'text')
|
||||
@@ -100,11 +83,6 @@ export class MessageSendService implements IMessageSendService {
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('[MessageSendService] 发送消息失败:', error);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'error',
|
||||
payload: { error, context: 'sendMessage' },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
* 消息同步服务
|
||||
* 处理消息和会话的服务器同步逻辑
|
||||
*
|
||||
* 重构说明:直接使用 zustand store 替代 IMessageStateManager
|
||||
* 重构说明:
|
||||
* - 直接使用 zustand store 替代 IMessageStateManager
|
||||
* - 移除了 SubscriptionManager 调用,Zustand 的 set() 会自动触发组件重渲染
|
||||
*/
|
||||
|
||||
import type { ConversationResponse, MessageResponse } from '../../../types/dto';
|
||||
@@ -21,7 +23,7 @@ import {
|
||||
CONVERSATION_LIST_PAGE_SIZE,
|
||||
} from '../../conversationListSources';
|
||||
import type { IMessageSyncService, MessageManagerConversationListDeps, IUserCacheService } from '../types';
|
||||
import { useMessageStore, subscriptionManager, normalizeConversationId, mergeMessagesById } from '../store';
|
||||
import { useMessageStore, normalizeConversationId, mergeMessagesById } from '../store';
|
||||
import { ReadReceiptManager } from './ReadReceiptManager';
|
||||
|
||||
export class MessageSyncService implements IMessageSyncService {
|
||||
@@ -94,19 +96,11 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
if (!forceRefresh && currentState.conversations.size === 0) {
|
||||
const warmed = await this.hydrateConversationsFromLocalSource();
|
||||
if (warmed) {
|
||||
this.emitConversationListAndUnreadUpdates();
|
||||
this.persistConversationListCache();
|
||||
}
|
||||
}
|
||||
|
||||
store.setLoading(true);
|
||||
const emitLoadingToUi = store.getConversations().length === 0;
|
||||
if (emitLoadingToUi) {
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_loading',
|
||||
payload: { loading: true },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
this.remoteConversationListSource.restart();
|
||||
@@ -129,29 +123,17 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
);
|
||||
store.setUnreadCount(totalUnread, store.getUnreadCount().system);
|
||||
|
||||
this.emitConversationListAndUnreadUpdates();
|
||||
this.persistConversationListCache();
|
||||
} catch (error) {
|
||||
console.error('[MessageSyncService] 获取会话列表失败:', error);
|
||||
if (store.getConversations().length === 0) {
|
||||
const recovered = await this.hydrateConversationsFromLocalSource();
|
||||
if (recovered) {
|
||||
this.emitConversationListAndUnreadUpdates();
|
||||
this.persistConversationListCache();
|
||||
}
|
||||
}
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'error',
|
||||
payload: { error, context: 'fetchConversations' },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
} finally {
|
||||
store.setLoading(false);
|
||||
if (emitLoadingToUi) {
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_loading',
|
||||
payload: { loading: false },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,14 +160,9 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
});
|
||||
|
||||
this.recomputeConversationTotalUnread();
|
||||
this.emitConversationListAndUnreadUpdates();
|
||||
this.persistConversationListCache();
|
||||
} catch (error) {
|
||||
console.error('[MessageSyncService] 加载更多会话失败:', error);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'error',
|
||||
payload: { error, context: 'loadMoreConversations' },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
} finally {
|
||||
this.loadingMoreConversations = false;
|
||||
}
|
||||
@@ -252,27 +229,9 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
}));
|
||||
|
||||
store.setMessages(conversationId, formattedMessages);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: formattedMessages,
|
||||
source: 'local',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
} else {
|
||||
// 冷启动兜底:先下发空列表事件
|
||||
// 冷启动兜底:先设置空列表
|
||||
store.setMessages(conversationId, []);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: [],
|
||||
source: 'local_empty',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[MessageSyncService] 读取本地消息失败:', error);
|
||||
@@ -288,17 +247,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
const existingMessages = store.getMessages(conversationId);
|
||||
const mergedSnapshot = mergeMessagesById(existingMessages, snapshotMessages);
|
||||
store.setMessages(conversationId, mergedSnapshot);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: mergedSnapshot,
|
||||
newMessages: snapshotMessages,
|
||||
source: 'server_snapshot',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 持久化到本地
|
||||
saveMessagesBatch(snapshotMessages.map((m: any) => ({
|
||||
@@ -327,17 +275,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
const existingMessages = store.getMessages(conversationId);
|
||||
const mergedMessages = mergeMessagesById(existingMessages, newMessages);
|
||||
store.setMessages(conversationId, mergedMessages);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: mergedMessages,
|
||||
newMessages,
|
||||
source: 'server_incremental',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
saveMessagesBatch(newMessages.map((m: any) => ({
|
||||
id: m.id,
|
||||
@@ -368,16 +305,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
const mergedMessages = mergeMessagesById(existingMessages, newMessages);
|
||||
|
||||
store.setMessages(conversationId, mergedMessages);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: mergedMessages,
|
||||
newMessages,
|
||||
source: 'server',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
saveMessagesBatch(newMessages.map((m: any) => ({
|
||||
id: m.id,
|
||||
@@ -397,11 +324,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[MessageSyncService] 获取消息失败:', error);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'error',
|
||||
payload: { error, context: 'fetchMessages', conversationId },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
} finally {
|
||||
// 异步填充用户信息(不阻塞消息显示)
|
||||
const currentMessages = store.getMessages(conversationId);
|
||||
@@ -411,15 +333,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
currentMessages,
|
||||
(convId, enrichedMessages) => {
|
||||
store.setMessages(convId, enrichedMessages);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId: convId,
|
||||
messages: enrichedMessages,
|
||||
source: 'sender_enriched',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -452,12 +365,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
const mergedMessages = this.mergeOlderMessages(existingMessages, formattedMessages);
|
||||
store.setMessages(conversationId, mergedMessages);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: { conversationId, messages: mergedMessages, source: 'local_history' },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
return formattedMessages;
|
||||
}
|
||||
|
||||
@@ -484,12 +391,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
const mergedMessages = this.mergeOlderMessages(existingMessages, serverMessages);
|
||||
store.setMessages(conversationId, mergedMessages);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: { conversationId, messages: mergedMessages, source: 'server_history' },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
return serverMessages;
|
||||
}
|
||||
|
||||
@@ -532,22 +433,8 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
// 使用 zustand set 函数正确更新状态
|
||||
store.setConversations(newConversations);
|
||||
this.persistConversationListCache();
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: totalUnread,
|
||||
systemUnreadCount: systemUnread,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[MessageSyncService] 获取未读数失败:', error);
|
||||
}
|
||||
@@ -598,26 +485,6 @@ export class MessageSyncService implements IMessageSyncService {
|
||||
store.setUnreadCount(totalUnread, store.getUnreadCount().system);
|
||||
}
|
||||
|
||||
private emitConversationListAndUnreadUpdates(): void {
|
||||
const store = useMessageStore.getState();
|
||||
this.persistConversationListCache();
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
const unreadCount = store.getUnreadCount();
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: unreadCount.total,
|
||||
systemUnreadCount: unreadCount.system,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
private persistConversationListCache(): void {
|
||||
const store = useMessageStore.getState();
|
||||
const currentState = store.getState();
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
* 已读回执管理器
|
||||
* 管理消息已读状态的同步和保护
|
||||
*
|
||||
* 重构说明:直接使用 zustand store 替代 IMessageStateManager
|
||||
* 重构说明:
|
||||
* - 直接使用 zustand store 替代 IMessageStateManager
|
||||
* - 移除了 SubscriptionManager 调用,Zustand 的 set() 会自动触发组件重渲染
|
||||
*/
|
||||
|
||||
import type { ConversationResponse } from '../../../types/dto';
|
||||
@@ -10,7 +12,7 @@ import { messageService } from '../../../services/messageService';
|
||||
import { markConversationAsRead, updateConversationCacheUnreadCount } from '../../../services/database';
|
||||
import type { ReadStateRecord, IReadReceiptManager } from '../types';
|
||||
import { READ_STATE_PROTECTION_DELAY } from '../constants';
|
||||
import { useMessageStore, subscriptionManager, normalizeConversationId } from '../store';
|
||||
import { useMessageStore, normalizeConversationId } from '../store';
|
||||
|
||||
export class ReadReceiptManager implements IReadReceiptManager {
|
||||
/**
|
||||
@@ -78,27 +80,7 @@ export class ReadReceiptManager implements IReadReceiptManager {
|
||||
// 3. 更新本地数据库
|
||||
markConversationAsRead(normalizedId).catch(console.error);
|
||||
|
||||
// 4. 立即通知所有订阅者
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'message_read',
|
||||
payload: {
|
||||
conversationId: normalizedId,
|
||||
unreadCount: 0,
|
||||
totalUnreadCount: newTotalUnread,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: newTotalUnread,
|
||||
systemUnreadCount: currentUnread.system,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 5. 调用 API,完成后设置延迟清除保护
|
||||
// 4. 调用 API,完成后设置延迟清除保护
|
||||
try {
|
||||
await messageService.markAsRead(normalizedId, seq);
|
||||
} catch (error) {
|
||||
@@ -107,16 +89,6 @@ export class ReadReceiptManager implements IReadReceiptManager {
|
||||
// 失败时回滚状态
|
||||
store.updateConversation(conversation);
|
||||
store.setUnreadCount(currentUnread.total, currentUnread.system);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'message_read',
|
||||
payload: {
|
||||
conversationId: normalizedId,
|
||||
unreadCount: prevUnreadCount,
|
||||
totalUnreadCount: currentUnread.total,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// API 失败时立即清除保护
|
||||
this.pendingReadMap.delete(normalizedId);
|
||||
@@ -156,15 +128,6 @@ export class ReadReceiptManager implements IReadReceiptManager {
|
||||
|
||||
store.setUnreadCount(0, currentSystem);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: 0,
|
||||
systemUnreadCount: currentSystem,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
try {
|
||||
// 标记系统消息已读
|
||||
await messageService.markAllSystemMessagesRead();
|
||||
@@ -182,15 +145,6 @@ export class ReadReceiptManager implements IReadReceiptManager {
|
||||
console.error('[ReadReceiptManager] 标记所有已读失败:', error);
|
||||
// 回滚
|
||||
store.setUnreadCount(prevTotalUnread, currentSystem);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: prevTotalUnread,
|
||||
systemUnreadCount: currentSystem,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
* WebSocket 消息处理器
|
||||
* 处理所有来自 WebSocket 的消息事件
|
||||
*
|
||||
* 重构说明:直接使用 zustand store 替代 IMessageStateManager
|
||||
* 重构说明:
|
||||
* - 直接使用 zustand store 替代 IMessageStateManager
|
||||
* - 移除了 SubscriptionManager 调用,Zustand 的 set() 会自动触发组件重渲染
|
||||
*/
|
||||
|
||||
import type {
|
||||
@@ -26,7 +28,7 @@ import type {
|
||||
HandleNewMessageOptions,
|
||||
} from '../types';
|
||||
import { MAX_FLUSH_ITERATIONS } from '../constants';
|
||||
import { useMessageStore, subscriptionManager, normalizeConversationId, mergeMessagesById } from '../store';
|
||||
import { useMessageStore, normalizeConversationId, mergeMessagesById } from '../store';
|
||||
|
||||
export class WSMessageHandler implements IWSMessageHandler {
|
||||
private deduplication: IMessageDeduplication;
|
||||
@@ -134,11 +136,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
// 监听连接状态
|
||||
wsService.onConnect(() => {
|
||||
store.setSSEConnected(true);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'connection_changed',
|
||||
payload: { connected: true },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
// 冷启动/重连兜底
|
||||
const now = Date.now();
|
||||
@@ -166,11 +163,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
|
||||
wsService.onDisconnect(() => {
|
||||
store.setSSEConnected(false);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'connection_changed',
|
||||
payload: { connected: false },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -268,14 +260,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
m.id === id ? { ...m, sender: user } : m
|
||||
);
|
||||
store.setMessages(normalizedConversationId, updatedMessages);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId: normalizedConversationId,
|
||||
messages: [...updatedMessages],
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
@@ -301,16 +285,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
if (!messageExists) {
|
||||
const updatedMessages = mergeMessagesById(existingMessages, [newMessage]);
|
||||
store.setMessages(normalizedConversationId, updatedMessages);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId: normalizedConversationId,
|
||||
messages: updatedMessages,
|
||||
newMessage,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
// 更新会话信息
|
||||
@@ -358,17 +332,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
}).catch(error => {
|
||||
console.error('[WSMessageHandler] 保存消息到本地失败:', error);
|
||||
});
|
||||
|
||||
// 通知收到新消息
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'message_received',
|
||||
payload: {
|
||||
conversationId: conversation_id,
|
||||
message: newMessage,
|
||||
isCurrentUser: isCurrentUserMessage,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,12 +358,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
this.markMessageAsRecalled(normalizedConversationId, message_id);
|
||||
this.syncConversationLastMessageOnRecall(normalizedConversationId, message_id);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'message_recalled',
|
||||
payload: { conversationId: normalizedConversationId, messageId: message_id },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
updateMessageStatus(message_id, 'recalled', true).catch(error => {
|
||||
console.error('[WSMessageHandler] 更新本地消息撤回状态失败:', error);
|
||||
});
|
||||
@@ -416,12 +373,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
this.markMessageAsRecalled(normalizedConversationId, message_id);
|
||||
this.syncConversationLastMessageOnRecall(normalizedConversationId, message_id);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'message_recalled',
|
||||
payload: { conversationId: normalizedConversationId, messageId: message_id, isGroup: true },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
updateMessageStatus(message_id, 'recalled', true).catch(error => {
|
||||
console.error('[WSMessageHandler] 更新本地消息撤回状态失败:', error);
|
||||
});
|
||||
@@ -450,11 +401,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
|
||||
if (updatedTypingUsers.length !== currentTypingUsers.length) {
|
||||
store.setTypingUsers(groupIdStr, updatedTypingUsers);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'typing_status',
|
||||
payload: { groupId: groupIdStr, typingUsers: updatedTypingUsers },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,34 +446,9 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
|
||||
const updatedMessages = [...existingMessages, systemNoticeMessage].sort((a, b) => a.seq - b.seq);
|
||||
store.setMessages(conversationId, updatedMessages);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: {
|
||||
conversationId,
|
||||
messages: updatedMessages,
|
||||
newMessage: systemNoticeMessage,
|
||||
source: 'group_notice',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通知订阅者群通知
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'group_notice',
|
||||
payload: {
|
||||
groupId: groupIdStr,
|
||||
noticeType: notice_type,
|
||||
data,
|
||||
timestamp,
|
||||
messageId: message_id,
|
||||
seq,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 私有工具方法 ====================
|
||||
@@ -550,12 +471,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
};
|
||||
store.updateConversation(updatedConv);
|
||||
}
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
private incrementUnreadCount(conversationId: string): void {
|
||||
@@ -571,21 +486,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
|
||||
const currentUnread = store.getUnreadCount();
|
||||
store.setUnreadCount(currentUnread.total + 1, currentUnread.system);
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
payload: {
|
||||
totalUnreadCount: store.getUnreadCount().total,
|
||||
systemUnreadCount: store.getUnreadCount().system,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: store.getConversations() },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,11 +510,6 @@ export class WSMessageHandler implements IWSMessageHandler {
|
||||
if (!changed) return;
|
||||
|
||||
store.setMessages(conversationId, updatedMessages);
|
||||
subscriptionManager.notifySubscribers({
|
||||
type: 'messages_updated',
|
||||
payload: { conversationId, messages: updatedMessages },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
private syncConversationLastMessageOnRecall(conversationId: string, messageId: string): void {
|
||||
|
||||
Reference in New Issue
Block a user