- 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
119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
/**
|
||
* 用户信息缓存服务
|
||
* 管理用户信息的缓存和获取
|
||
*/
|
||
|
||
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(); |