Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions client/shared/cache/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ export async function getCachedUserInfo(
* 获取缓存的会话信息
*/
export async function getCachedConverseInfo(
converseId: string
converseId: string,
refetch = false
): Promise<ChatConverseInfo> {
const data = await queryClient.fetchQuery(
[CacheKey.converse, converseId],
() => fetchConverseInfo(converseId)
() => fetchConverseInfo(converseId),
{ staleTime: refetch ? 0 : 10 * 1000 }
);

return data;
Expand Down
93 changes: 82 additions & 11 deletions client/shared/helper/converse-helper.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,73 @@
import { getReduxStore, isValidStr } from '..';
import { getCachedConverseInfo, getCachedUserInfo } from '../cache/cache';
import { getReduxStore, AppStore } from '../redux/store';
import { isValidStr } from '../utils/string-helper';
import { CacheKey, getCachedUserInfo } from '../cache/cache';
import { queryClient } from '../cache';
import { t } from '../i18n';
import type { ChatConverseInfo } from '../model/converse';
import { ChatConverseInfo, fetchConverseInfo } from '../model/converse';
import { appendUserDMConverse } from '../model/user';
import type { FriendInfo } from '../redux/slices/user';
import { chatActions } from '../redux/slices/chat';
import type { RequestError } from '../api/request';

const converseRefreshes = new Map<
string,
Promise<ChatConverseInfo | undefined>
>();

export function removeDMConverseLocally(
converseId: string,
store: AppStore = getReduxStore()
) {
store.dispatch(chatActions.removeDMConverse({ converseId }));
converseRefreshes.delete(converseId);
queryClient.removeQueries([CacheKey.converse, converseId], { exact: true });
queryClient.removeQueries([CacheKey.converseAck, converseId], {
exact: true,
});
}

/**
* 只有服务端确认的成员关系才能恢复已退出的会话。
*/
export function refreshDMConverse(
converseId: string,
currentUserId: string,
store: AppStore = getReduxStore()
): Promise<ChatConverseInfo | undefined> {
const version =
store.getState().chat.converseMembership[converseId]?.version ?? 0;
const run = async (): Promise<ChatConverseInfo | undefined> => {
// 成员验证不复用缓存;同时开始的调用等待最新请求,不互相取消。
const result = await fetchConverseInfo(converseId).then(
(converse) => ({ converse, error: undefined }),
(error: RequestError) => ({ converse: undefined, error })
);
if (
(store.getState().chat.converseMembership[converseId]?.version ?? 0) !==
version
) {
return;
}
const latestRefresh = converseRefreshes.get(converseId);
if (latestRefresh && latestRefresh !== refresh) {
return latestRefresh;
}
if (result.error && result.error.code !== 403) {
throw result.error;
}
if (!result.converse?.members.includes(currentUserId)) {
removeDMConverseLocally(converseId, store);
return;
}
store.dispatch(
chatActions.restoreDMConverse({ converse: result.converse, version })
);
return result.converse;
};
const refresh = run();
converseRefreshes.set(converseId, refresh);
return refresh;
}

/**
* 确保私信会话存在
Expand All @@ -12,18 +76,23 @@ export async function ensureDMConverse(
converseId: string,
currentUserId: string
): Promise<ChatConverseInfo> {
const converse = await getCachedConverseInfo(converseId);
if (converse === null) {
// TODO
throw new Error(t('找不到私信会话'));
}

if (!converse.members.includes(currentUserId)) {
const store = getReduxStore();
const version =
store.getState().chat.converseMembership[converseId]?.version ?? 0;
const converse = await refreshDMConverse(converseId, currentUserId, store);
if (!converse) {
throw new Error(t('会话没有权限'));
}

await appendUserDMConverse(converseId); // 添加到私人会话列表

if (
(store.getState().chat.converseMembership[converseId]?.version ?? 0) !==
version
) {
throw new Error(t('会话没有权限'));
}

return converse;
}

Expand Down Expand Up @@ -72,7 +141,9 @@ export async function getDMConverseName(
});
const len = memberNicknames.length;

if (len === 1) {
if (len === 0) {
return t('多人会话');
} else if (len === 1) {
return memberNicknames[0] ?? '';
} else if (len === 2) {
return `${memberNicknames[0]}, ${memberNicknames[1]}`;
Expand Down
16 changes: 11 additions & 5 deletions client/shared/hooks/model/useUserSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,21 @@ export function useUserSettings() {

const [{ loading: saveLoading }, setSettings] = useAsyncRequest(
async (_settings: UserSettings) => {
const previousSettings =
client.getQueryData<UserSettings>([CacheKey.userSettings]) ?? {};
client.setQueryData([CacheKey.userSettings], () => ({
...settings,
...previousSettings,
..._settings,
})); // 让配置能够立即生效, 防止依赖配置的行为出现跳变(如GroupNav)

const newSettings = await setUserSettings(_settings);

client.setQueryData([CacheKey.userSettings], () => newSettings);
sharedEvent.emit('userSettingsUpdate', newSettings);
try {
const newSettings = await setUserSettings(_settings);
client.setQueryData([CacheKey.userSettings], () => newSettings);
sharedEvent.emit('userSettingsUpdate', newSettings);
} catch (error) {
client.setQueryData([CacheKey.userSettings], previousSettings);
throw error;
}
},
[client]
);
Expand Down
7 changes: 6 additions & 1 deletion client/shared/i18n/langs/en-US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"k11cef91e": "There are some problems with the page",
"k123852c": "Group privacy control to prevent malicious harassment of users through groups.",
"k1252f904": "Gateway",
"k12e81a9d": "Multi-person conversation",
"k131598d0": "A new version is detected, whether to refresh immediately to upgrade to the latest content",
"k13ae6a93": "Copy",
"k13bea6d2": "User not found",
Expand All @@ -19,6 +20,7 @@
"k18580d81": "Create a link and send it to external friends",
"k186fec4": "Plugin failed to load",
"k1885734a": "Effective after refreshing the page",
"k1898e887": "Leave conversation",
"k18c716ce": "Password cannot be less than 6 digits",
"k19885be1": "Panel name is too long",
"k19a1647f": "1 minute",
Expand Down Expand Up @@ -79,6 +81,7 @@
"k375be8c3": "Jump to panel",
"k378f66fc": "Unmute",
"k393892b6": "Upload original image",
"k3a1a59b7": "Leave this multi-person conversation? You will no longer receive its messages.",
"k3a31dae3": "Verification email sent",
"k3ac17670": "An exception occurred, store create failed",
"k3b4b656d": "About",
Expand Down Expand Up @@ -308,6 +311,7 @@
"kb123dbb9": "Your personal unique identifier",
"kb12cc88f": "Unmute",
"kb2217aa7": "Currently using a temporary account, <2>claim now</2>",
"kb292488d": "When enabled, only friends can invite you to create or join multi-person conversations",
"kb3390ae7": "Are you sure you want to leave the group?",
"kb47a9aa4": "Password can not be empty",
"kb488372f": "All",
Expand Down Expand Up @@ -356,6 +360,7 @@
"kcac0467c": "Allow members to create invitation links",
"kcb20f8ce": "The following are plugin permissions",
"kcb8e662f": "Converse Service",
"kccdd14b1": "Close conversation (new messages will show it again)",
"kceea83fc": "Join Group",
"kcefdbe2d": "Modify avatar success",
"kd0690a45": "Allow management of identity groups",
Expand Down Expand Up @@ -414,6 +419,7 @@
"ke6da074f": "The message was withdrawn successfully",
"ke9748e88": "Custom Meta is not supported",
"keb053701": "Copy message text successfully",
"kec0ca6b4": "Only allow friends to invite me to conversations",
"kec46a57f": "Add members",
"kecb51e2c": "Old password",
"kecbb0e45": "System",
Expand Down Expand Up @@ -459,7 +465,6 @@
"kf8de33b7": "Plugin provider not found",
"kf9235c11": "Something went wrong",
"kf94465ba": "Invite Code",
"kfa01c850": "No private message found",
"kfa493f3f": "Reply",
"kfa610536": "Alpha mode switch",
"kfaddd61d": "Chat Service",
Expand Down
7 changes: 6 additions & 1 deletion client/shared/i18n/langs/zh-CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"k11cef91e": "页面出现了一些问题",
"k123852c": "群组隐私控制,防止通过群组恶意骚扰用户。",
"k1252f904": "服务网关",
"k12e81a9d": "多人会话",
"k131598d0": "检测到有新版本, 是否立即刷新以升级到最新内容",
"k13ae6a93": "复制",
"k13bea6d2": "没有找到用户",
Expand All @@ -19,6 +20,7 @@
"k18580d81": "创建链接并发送给外部好友",
"k186fec4": "插件加载失败",
"k1885734a": "刷新页面后生效",
"k1898e887": "退出会话",
"k18c716ce": "密码不能低于6位",
"k19885be1": "面板名过长",
"k19a1647f": "1分钟",
Expand Down Expand Up @@ -79,6 +81,7 @@
"k375be8c3": "跳转到面板",
"k378f66fc": "解除禁言",
"k393892b6": "上传原图",
"k3a1a59b7": "确定要退出此多人会话么?退出后将不再接收此会话的消息",
"k3a31dae3": "已发送认证邮件",
"k3ac17670": "出现异常, Store 创建失败",
"k3b4b656d": "关于",
Expand Down Expand Up @@ -308,6 +311,7 @@
"kb123dbb9": "您的个人唯一标识",
"kb12cc88f": "取消免打扰",
"kb2217aa7": "当前使用的是一个临时账号, <2>立即认领</2>",
"kb292488d": "开启后,只有好友可以邀请你创建或加入多人会话",
"kb3390ae7": "确定要退出群组么?",
"kb47a9aa4": "密码不能为空",
"kb488372f": "所有人",
Expand Down Expand Up @@ -356,6 +360,7 @@
"kcac0467c": "允许成员创建邀请链接",
"kcb20f8ce": "以下为插件权限",
"kcb8e662f": "会话服务",
"kccdd14b1": "关闭会话(新消息到达时会重新显示)",
"kceea83fc": "加入群组",
"kcefdbe2d": "修改头像成功",
"kd0690a45": "允许管理身份组",
Expand Down Expand Up @@ -414,6 +419,7 @@
"ke6da074f": "消息撤回成功",
"ke9748e88": "不支持自定义Meta",
"keb053701": "复制消息文本成功",
"kec0ca6b4": "仅允许好友邀请创建会话",
"kec46a57f": "添加成员",
"kecb51e2c": "旧密码",
"kecbb0e45": "系统",
Expand Down Expand Up @@ -459,7 +465,6 @@
"kf8de33b7": "未找到插件的提供者",
"kf9235c11": "出现了一些问题",
"kf94465ba": "邀请码",
"kfa01c850": "找不到私信会话",
"kfa493f3f": "回复",
"kfa610536": "Alpha测试开关",
"kfaddd61d": "聊天服务",
Expand Down
7 changes: 7 additions & 0 deletions client/shared/model/converse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export async function appendDMConverseMembers(
return data;
}

/**
* 退出多人会话
*/
export async function leaveDMConverse(converseId: string): Promise<void> {
await request.post('/api/chat/converse/leaveDMConverse', { converseId });
}

/**
* 获取会话信息
* @param converseId 会话ID
Expand Down
5 changes: 5 additions & 0 deletions client/shared/model/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export interface UserLoginInfo extends UserBaseInfo {
}

export interface UserSettings {
/**
* 仅允许好友邀请创建或加入多人会话,默认关闭
*/
onlyAllowFriendInvite?: boolean;

/**
* 消息列表虚拟化
*/
Expand Down
3 changes: 1 addition & 2 deletions client/shared/redux/hooks/useConverseMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ export function useConverseMessage(context: ConverseContext) {
if (!isGroup) {
// 如果是私信会话
// Step 1. 创建会话 并确保私信列表中存在该会话
const converse = await ensureDMConverse(converseId, currentUserId);
dispatch(chatActions.setConverseInfo(converse));
await ensureDMConverse(converseId, currentUserId);
} else {
// 如果是群组会话(文本频道)
// Step 1. 确保群组会话存在
Expand Down
Loading
Loading