refactor: refactor ack logic to not fetch all acks but fetch only the ones that are needed

chore/cli-prune-script
moonrailgun 6 months ago
parent 5c338b5bb4
commit 14613cc973

@ -1,10 +1,15 @@
import { ChatConverseInfo, fetchConverseInfo } from '../model/converse';
import {
ChatConverseInfo,
fetchConverseInfo,
getConverseAckInfo,
} from '../model/converse';
import {
findGroupInviteByCode,
getGroupBasicInfo,
GroupBasicInfo,
GroupInvite,
} from '../model/group';
import { getConverseLastMessageInfo } from '../model/message';
import {
fetchLocalStaticRegistryPlugins,
fetchRegistryPlugins,
@ -18,6 +23,7 @@ import { queryClient } from './index';
export enum CacheKey {
user = 'user',
converse = 'converse',
converseAck = 'converseAck',
baseGroupInfo = 'baseGroupInfo',
groupInvite = 'groupInvite',
pluginRegistry = 'pluginRegistry',
@ -84,6 +90,32 @@ export async function getCachedGroupInviteInfo(
return data;
}
/**
*
*/
export async function getCachedAckInfo(converseId: string, refetch = false) {
const data = await queryClient.fetchQuery(
[CacheKey.converseAck, converseId],
() => {
return Promise.all([
getConverseAckInfo([converseId]).then((d) => d[0]),
getConverseLastMessageInfo([converseId]).then((d) => d[0]),
]).then(([ack, lastMessage]) => {
return {
converseId,
ack,
lastMessage,
};
});
},
{
staleTime: 2 * 1000, // 缓存2s, 减少一秒内的重复请求(无意义)
}
);
return data;
}
/**
*
*/

@ -1,4 +1,11 @@
import { request } from '../api/request';
import {
createAutoMergedRequest,
createAutoSplitRequest,
} from '../utils/request';
import _uniq from 'lodash/uniq';
import _flatten from 'lodash/flatten';
import _zipObject from 'lodash/zipObject';
export enum ChatConverseType {
DM = 'DM', // 单人会话
@ -88,3 +95,50 @@ export async function fetchUserAck(): Promise<AckInfo[]> {
return data;
}
/**
*
*/
export async function fetchUserAckList(
converseIds: string[]
): Promise<(AckInfo | null)[]> {
const { data } = await request.post('/api/chat/ack/list', {
converseIds,
});
if (!Array.isArray(data)) {
return [];
}
return data;
}
const _fetchConverseAckInfo = createAutoMergedRequest<
string[],
(AckInfo | null)[]
>(
createAutoSplitRequest(
async (converseIdsList) => {
const uniqList = _uniq(_flatten(converseIdsList));
const infoList = await fetchUserAckList(uniqList);
const map = _zipObject<AckInfo | null>(uniqList, infoList);
// 将请求结果根据传输来源重新分组
return converseIdsList.map((converseIds) =>
converseIds.map((converseId) => map[converseId] ?? null)
);
},
'serial',
100
)
);
/**
*
*/
export async function getConverseAckInfo(
converseIds: string[]
): Promise<(AckInfo | null)[]> {
return _fetchConverseAckInfo(converseIds);
}

@ -1,5 +1,12 @@
import { request } from '../api/request';
import type { ChatMessageReaction, ChatMessage } from 'tailchat-types';
import {
createAutoMergedRequest,
createAutoSplitRequest,
} from '../utils/request';
import _uniq from 'lodash/uniq';
import _flatten from 'lodash/flatten';
import _zipObject from 'lodash/zipObject';
export { ChatMessageReaction, ChatMessage };
@ -103,10 +110,15 @@ export async function searchMessage(
return data;
}
interface LastMessageInfo {
converseId: string;
lastMessageId: string;
}
/**
* idid
*/
export async function fetchConverseLastMessages(
async function fetchConverseLastMessages(
converseIds: string[]
): Promise<{ converseId: string; lastMessageId: string }[]> {
const { data } = await request.post(
@ -119,6 +131,30 @@ export async function fetchConverseLastMessages(
return data;
}
export const _fetchConverseLastMessageInfo = createAutoMergedRequest<
string[],
(LastMessageInfo | null)[]
>(
createAutoSplitRequest(
async (converseIdsList) => {
const uniqList = _uniq(_flatten(converseIdsList));
const infoList = await fetchConverseLastMessages(uniqList);
const map = _zipObject<LastMessageInfo | null>(uniqList, infoList);
// 将请求结果根据传输来源重新分组
return converseIdsList.map((converseIds) =>
converseIds.map((converseId) => map[converseId] ?? null)
);
},
'serial',
100
)
);
export function getConverseLastMessageInfo(converseIds: string[]) {
return _fetchConverseLastMessageInfo(converseIds);
}
/**
* @param converseId ID
* @param messageId ID

@ -0,0 +1,41 @@
import { useAppDispatch, useAppSelector } from './useAppSelector';
import { chatActions } from '../slices';
import { useEvent } from '../../hooks/useEvent';
import { getCachedAckInfo } from '../../cache/cache';
export function useAckInfoChecker() {
const ack = useAppSelector((state) => state.chat.ack);
const lastMessageMap = useAppSelector((state) => state.chat.lastMessageMap);
const dispatch = useAppDispatch();
const ensureAckInfo = useEvent((converseId: string) => {
if (
ack[converseId] === undefined ||
lastMessageMap[converseId] === undefined
) {
getCachedAckInfo(converseId).then((info) => {
if (info.ack?.lastMessageId) {
dispatch(
chatActions.setConverseAck({
converseId,
lastMessageId: info.ack.lastMessageId,
})
);
}
if (info.lastMessage?.lastMessageId) {
dispatch(
chatActions.setLastMessageMap([
{
converseId,
lastMessageId: info.lastMessage.lastMessageId,
},
])
);
}
});
}
});
return { ensureAckInfo };
}

@ -1,4 +1,6 @@
import { useAppSelector } from './useAppSelector';
import { useAckInfoChecker } from './useAckInfo';
import { useEffect } from 'react';
/**
*
@ -6,13 +8,18 @@ import { useAppSelector } from './useAppSelector';
export function useUnread(converseIds: string[]) {
const ack = useAppSelector((state) => state.chat.ack);
const lastMessageMap = useAppSelector((state) => state.chat.lastMessageMap);
const { ensureAckInfo } = useAckInfoChecker();
return converseIds.map((converseId) => {
useEffect(() => {
converseIds.forEach((converseId) => ensureAckInfo(converseId));
}, [converseIds]);
const unreadList = converseIds.map((converseId) => {
if (
ack[converseId] === undefined &&
lastMessageMap[converseId] !== undefined
) {
// 没有已读记录且远程有数据
// 远程没有已读记录且获取到了最后一条消息
return true;
}
@ -20,4 +27,6 @@ export function useUnread(converseIds: string[]) {
// 则返回true(有未读消息)
return lastMessageMap[converseId] > ack[converseId];
});
return unreadList;
}

@ -9,19 +9,11 @@ import {
import type { FriendRequest } from '../model/friend';
import { getCachedConverseInfo } from '../cache/cache';
import type { GroupInfo } from '../model/group';
import {
ChatMessage,
ChatMessageReaction,
fetchConverseLastMessages,
} from '../model/message';
import { ChatMessage, ChatMessageReaction } from '../model/message';
import { socketEventListeners } from '../manager/socket';
import { showToasts } from '../manager/ui';
import { t } from '../i18n';
import {
ChatConverseInfo,
ChatConverseType,
fetchUserAck,
} from '../model/converse';
import { ChatConverseInfo, ChatConverseType } from '../model/converse';
import { appendUserDMConverse } from '../model/user';
import { sharedEvent } from '../event';
import type { InboxItem } from '../model/inbox';
@ -61,7 +53,7 @@ function initial(socket: AppSocket, store: AppStore) {
console.log('初始化Redux上下文...');
// 立即请求加入房间
const conversesP = socket
socket
.request<{
dmConverseIds: string[];
groupIds: string[];
@ -77,30 +69,6 @@ function initial(socket: AppSocket, store: AppStore) {
throw new Error('findAndJoinRoom failed');
});
Promise.all([conversesP, fetchUserAck()]).then(
([{ dmConverseIds, textPanelIds }, acks]) => {
/**
* TODO:
* acklastMessageMap
*/
// 设置已读消息
acks.forEach((ackInfo) => {
store.dispatch(
chatActions.setConverseAck({
converseId: ackInfo.converseId,
lastMessageId: ackInfo.lastMessageId,
})
);
});
const converseIds = [...dmConverseIds, ...textPanelIds];
fetchConverseLastMessages(converseIds).then((list) => {
store.dispatch(chatActions.setLastMessageMap(list));
});
}
);
// 获取好友列表
socket
.request<{ id: string; nickname?: string }[]>('friend.getAllFriends')

@ -23,6 +23,14 @@ class AckService extends TcService {
lastMessageId: 'string',
},
});
this.registerAction('list', this.listAck, {
params: {
converseIds: {
type: 'array',
items: 'string',
},
},
});
this.registerAction('all', this.allAck);
}
@ -54,6 +62,35 @@ class AckService extends TcService {
// TODO: 如果要实现消息已读可以在此处基于会话id进行通知
}
/**
* ack
*/
async listAck(ctx: TcContext<{ converseIds: string[] }>) {
const userId = ctx.meta.userId;
const { converseIds } = ctx.params;
const list = await this.adapter.model.find({
userId,
converseId: {
$in: [...converseIds],
},
});
return converseIds.map((converseId) => {
const lastMessageId =
list
.find((item) => String(item.converseId) === converseId)
?.lastMessageId?.toString() ?? null;
return lastMessageId
? {
converseId,
lastMessageId,
}
: null;
});
}
/**
* ack
*/

@ -479,10 +479,14 @@ class MessageService extends TcService {
})
);
return list.filter(Boolean).map((item) => ({
converseId: String(item.converseId),
lastMessageId: String(item._id),
}));
return list.map((item) =>
item
? {
converseId: String(item.converseId),
lastMessageId: String(item._id),
}
: null
);
}
async addReaction(

Loading…
Cancel
Save