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 {} 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>( (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>((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;