mirror of https://github.com/msgbyte/tailchat
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
6.0 KiB
TypeScript
251 lines
6.0 KiB
TypeScript
import _ from 'lodash';
|
|
import { Types } from 'mongoose';
|
|
import {
|
|
TcDbService,
|
|
TcService,
|
|
TcContext,
|
|
UserStruct,
|
|
call,
|
|
DataNotFoundError,
|
|
} from 'tailchat-server-sdk';
|
|
import type {
|
|
ConverseDocument,
|
|
ConverseModel,
|
|
} from '../../../models/chat/converse';
|
|
|
|
interface ConverseService
|
|
extends TcService,
|
|
TcDbService<ConverseDocument, ConverseModel> {}
|
|
class ConverseService extends TcService {
|
|
get serviceName(): string {
|
|
return 'chat.converse';
|
|
}
|
|
|
|
onInit(): void {
|
|
this.registerLocalDb(require('../../../models/chat/converse').default);
|
|
|
|
this.registerAction('createDMConverse', this.createDMConverse, {
|
|
params: {
|
|
/**
|
|
* 创建私人会话的参与者ID列表
|
|
*/
|
|
memberIds: { type: 'array', items: 'string' },
|
|
},
|
|
});
|
|
this.registerAction(
|
|
'appendDMConverseMembers',
|
|
this.appendDMConverseMembers,
|
|
{
|
|
params: {
|
|
converseId: 'string',
|
|
memberIds: 'array',
|
|
},
|
|
}
|
|
);
|
|
this.registerAction('findConverseInfo', this.findConverseInfo, {
|
|
params: {
|
|
converseId: 'string',
|
|
},
|
|
});
|
|
this.registerAction('findAndJoinRoom', this.findAndJoinRoom);
|
|
}
|
|
|
|
async createDMConverse(ctx: TcContext<{ memberIds: string[] }>) {
|
|
const userId = ctx.meta.userId;
|
|
const memberIds = ctx.params.memberIds;
|
|
|
|
const participantList = _.uniq([userId, ...memberIds]);
|
|
|
|
let converse = await this.adapter.model.findConverseWithMembers(
|
|
participantList
|
|
);
|
|
if (converse === null) {
|
|
// 创建新的会话
|
|
converse = await this.adapter.insert({
|
|
type: 'DM',
|
|
members: participantList.map((id) => new Types.ObjectId(id)),
|
|
});
|
|
}
|
|
|
|
const roomId = String(converse._id);
|
|
await Promise.all(
|
|
participantList.map((memberId) =>
|
|
call(ctx).joinSocketIORoom([roomId], memberId)
|
|
)
|
|
);
|
|
|
|
// 广播更新消息
|
|
await this.roomcastNotify(
|
|
ctx,
|
|
roomId,
|
|
'updateDMConverse',
|
|
converse.toJSON()
|
|
);
|
|
|
|
// 更新dmlist 异步处理
|
|
Promise.all(
|
|
participantList.map(async (memberId) => {
|
|
try {
|
|
await ctx.call(
|
|
'user.dmlist.addConverse',
|
|
{ converseId: roomId },
|
|
{
|
|
meta: {
|
|
userId: memberId,
|
|
},
|
|
}
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(e);
|
|
}
|
|
})
|
|
);
|
|
|
|
if (participantList.length > 2) {
|
|
// 如果创建的是一个多人会话(非双人), 发送系统消息
|
|
await Promise.all(
|
|
_.without(participantList, userId).map<Promise<UserStruct>>(
|
|
(memberId) => ctx.call('user.getUserInfo', { userId: memberId })
|
|
)
|
|
).then((infoList) => {
|
|
return call(ctx).sendSystemMessage(
|
|
`${ctx.meta.user.nickname} 邀请 ${infoList
|
|
.map((info) => info.nickname)
|
|
.join(', ')} 加入会话`,
|
|
roomId
|
|
);
|
|
});
|
|
}
|
|
|
|
return await this.transformDocuments(ctx, {}, converse);
|
|
}
|
|
|
|
/**
|
|
* 在多人会话中添加成员
|
|
*/
|
|
async appendDMConverseMembers(
|
|
ctx: TcContext<{ converseId: string; memberIds: string[] }>
|
|
) {
|
|
const userId = ctx.meta.userId;
|
|
const { converseId, memberIds } = ctx.params;
|
|
|
|
const converse = await this.adapter.model.findById(converseId);
|
|
if (!converse) {
|
|
throw new DataNotFoundError();
|
|
}
|
|
|
|
if (!converse.members.map(String).includes(userId)) {
|
|
throw new Error('不是会话参与者, 无法添加成员');
|
|
}
|
|
|
|
converse.members.push(...memberIds.map((uid) => new Types.ObjectId(uid)));
|
|
await converse.save();
|
|
|
|
await Promise.all(
|
|
memberIds.map((uid) =>
|
|
call(ctx).joinSocketIORoom([String(converseId)], uid)
|
|
)
|
|
);
|
|
|
|
// 广播更新会话列表
|
|
await this.roomcastNotify(
|
|
ctx,
|
|
converseId,
|
|
'updateDMConverse',
|
|
converse.toJSON()
|
|
);
|
|
|
|
// 更新dmlist 异步处理
|
|
Promise.all(
|
|
memberIds.map(async (memberId) => {
|
|
try {
|
|
await ctx.call(
|
|
'user.dmlist.addConverse',
|
|
{ converseId },
|
|
{
|
|
meta: {
|
|
userId: memberId,
|
|
},
|
|
}
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(e);
|
|
}
|
|
})
|
|
);
|
|
|
|
// 发送系统消息, 异步处理
|
|
await Promise.all(
|
|
memberIds.map<Promise<UserStruct>>((memberId) =>
|
|
ctx.call('user.getUserInfo', { userId: memberId })
|
|
)
|
|
).then((infoList) => {
|
|
return call(ctx).sendSystemMessage(
|
|
`${ctx.meta.user.nickname} 邀请 ${infoList
|
|
.map((info) => info.nickname)
|
|
.join(', ')} 加入会话`,
|
|
converseId
|
|
);
|
|
});
|
|
|
|
return converse;
|
|
}
|
|
|
|
/**
|
|
* 查找会话
|
|
*/
|
|
async findConverseInfo(
|
|
ctx: TcContext<{
|
|
converseId: string;
|
|
}>
|
|
) {
|
|
const converseId = ctx.params.converseId;
|
|
const userId = ctx.meta.userId;
|
|
const t = ctx.meta.t;
|
|
|
|
const converse = await this.adapter.findById(converseId);
|
|
|
|
const memebers = converse.members ?? [];
|
|
if (!memebers.map((member) => String(member)).includes(userId)) {
|
|
throw new Error(t('没有获取会话信息权限'));
|
|
}
|
|
|
|
return await this.transformDocuments(ctx, {}, converse);
|
|
}
|
|
|
|
/**
|
|
* 查找用户相关的所有会话并加入房间
|
|
* @returns 返回相关信息
|
|
*/
|
|
async findAndJoinRoom(ctx: TcContext) {
|
|
const userId = ctx.meta.userId;
|
|
const dmConverseIds = await this.adapter.model.findAllJoinedConverseId(
|
|
userId
|
|
);
|
|
|
|
// 获取群组列表
|
|
const { groupIds, textPanelIds, subscribeFeaturePanelIds } =
|
|
await ctx.call<{
|
|
groupIds: string[];
|
|
textPanelIds: string[];
|
|
subscribeFeaturePanelIds: string[];
|
|
}>('group.getJoinedGroupAndPanelIds');
|
|
|
|
await call(ctx).joinSocketIORoom([
|
|
...dmConverseIds,
|
|
...groupIds,
|
|
...textPanelIds,
|
|
...subscribeFeaturePanelIds,
|
|
]);
|
|
|
|
return {
|
|
dmConverseIds,
|
|
groupIds,
|
|
textPanelIds,
|
|
subscribeFeaturePanelIds,
|
|
};
|
|
}
|
|
}
|
|
|
|
export default ConverseService;
|