120 lines
3.4 KiB
TypeScript
120 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();
|