refactor(message): replace MessageStateManager with zustand store
Some checks failed
Frontend CI / ota-android (push) Successful in 11m15s
Frontend CI / build-and-push-web (push) Successful in 29m13s
Frontend CI / build-android-apk (push) Has been cancelled

- Remove MessageStateManager wrapper layer in favor of direct zustand store
- Move service modules to services/ subdirectory (ConversationOperations, MessageDeduplication, MessageSendService, MessageSyncService, ReadReceiptManager, UserCacheService, WSMessageHandler)
- Add new zustand-based store with subscriptionManager for event handling
- Introduce React hooks for message state (useConversations, useMessages, useUnreadCount, etc.)
- Update exports in index.ts to reflect new module structure
- Deprecate messageManager.ts entry point in favor of message/index.ts
- Maintain backward compatibility with existing MessageManager API
This commit is contained in:
lafay
2026-03-31 18:22:24 +08:00
parent 1bee7ea551
commit 94c11062f0
15 changed files with 1488 additions and 706 deletions

View File

@@ -0,0 +1,119 @@
/**
* 用户信息缓存服务
* 管理用户信息的缓存和获取
*/
import type { MessageResponse, UserDTO } from '../../../types/dto';
import { api } from '../../../services/api';
import { getUserCache, saveUserCache } from '../../../services/database';
import type { IUserCacheService } from '../types';
export class UserCacheService implements IUserCacheService {
// 正在获取用户信息的请求映射(用于去重)
private pendingUserRequests: Map<string, Promise<UserDTO | null>> = new Map();
/**
* 获取用户信息(带缓存和去重)
*/
async getSenderInfo(userId: string): Promise<UserDTO | null> {
// 1. 先检查本地缓存
const cachedUser = await getUserCache(userId);
if (cachedUser) {
return cachedUser;
}
// 2. 检查是否已有正在进行的请求
const pendingRequest = this.pendingUserRequests.get(userId);
if (pendingRequest) {
return pendingRequest;
}
// 3. 发起新请求
const request = this.fetchUserInfo(userId);
this.pendingUserRequests.set(userId, request);
try {
const user = await request;
return user;
} finally {
// 请求完成后清理
this.pendingUserRequests.delete(userId);
}
}
/**
* 从服务器获取用户信息
*/
private async fetchUserInfo(userId: string): Promise<UserDTO | null> {
try {
const response = await api.get<UserDTO>(`/users/${userId}`);
if (response.code === 0 && response.data) {
// 缓存到本地数据库
await saveUserCache(response.data);
return response.data;
}
return null;
} catch (error) {
console.error(`[UserCacheService] 获取用户信息失败: ${userId}`, error);
return null;
}
}
/**
* 批量异步填充消息的 sender 信息
* 填充完成后调用 notifyUpdate 更新内存并通知订阅者
*/
enrichMessagesWithSenderInfo(
conversationId: string,
messages: MessageResponse[],
notifyUpdate: (conversationId: string, messages: MessageResponse[]) => void
): void {
// 收集所有需要查询的唯一 sender_id排除系统用户
const senderIds = [...new Set(
messages
.filter(m => m.sender_id && m.sender_id !== '10000' && !m.sender)
.map(m => m.sender_id)
)];
if (senderIds.length === 0) return;
// 并发获取所有 sender 信息
Promise.all(senderIds.map(id => this.getSenderInfo(id).then(user => ({ id, user }))))
.then(results => {
const senderMap = new Map<string, UserDTO>();
results.forEach(({ id, user }) => {
if (user) senderMap.set(id, user);
});
if (senderMap.size === 0) return;
let changed = false;
const updated = messages.map(m => {
if (!m.sender && m.sender_id && senderMap.has(m.sender_id)) {
changed = true;
return { ...m, sender: senderMap.get(m.sender_id) };
}
return m;
});
if (!changed) return;
// 调用回调通知更新
notifyUpdate(conversationId, updated);
})
.catch(error => {
console.error('[UserCacheService] 批量获取 sender 信息失败:', error);
});
}
/**
* 清除所有待处理的请求
* 用于测试或需要重置的场景
*/
reset(): void {
this.pendingUserRequests.clear();
}
}
// 单例导出
export const userCacheService = new UserCacheService();