From 41025cacf9b93d0e186f9db786b5da761a1861c4 Mon Sep 17 00:00:00 2001 From: liangtongchuan Date: Wed, 10 Mar 2021 12:49:12 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=8A=E5=A4=A9=EF=BC=9A=E6=9C=80=E8=BF=91?= =?UTF-8?q?=E7=A7=81=E8=81=8A=E5=8E=86=E5=8F=B2=E7=9B=B8=E5=85=B3=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servers/connector/handler/entryHandler.ts | 7 +++- game-server/app/services/chatService.ts | 37 ++++++++++++++++++- shared/consts/constModules/chatConst.ts | 2 + shared/db/ChatInfo.ts | 27 +++++++++++--- shared/db/PrivateMessage.ts | 10 +++++ 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index c5e508528..9bbeb7e0e 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -19,7 +19,7 @@ import { GuildModel } from '../../../db/Guild'; import { gameData } from '../../../pubUtils/data'; import { getMails } from '../../../services/mailService'; -import { addRoleToGuildChannel, addRoleToSysChannel, addRoleToWorldChannel, leaveGuildChannel, leaveSysChannel, leaveWorldChannel } from '../../../services/chatService'; +import { addRoleToGuildChannel, addRoleToSysChannel, addRoleToWorldChannel, leaveGuildChannel, leaveSysChannel, leaveWorldChannel, recentPrivateChatInfos } from '../../../services/chatService'; import { reportOneOnline } from '../../../services/timeTaskService'; export default function (app: Application) { return new EntryHandler(app); @@ -109,6 +109,11 @@ export class EntryHandler { role['apJson'] = apJson; role['mails'] = mails; + const recentPrivateChats = await recentPrivateChatInfos(role.roleId, role.roleName); + if (recentPrivateChats) { + role['recentPrivateChats'] = recentPrivateChats; + } + if(role.hasGuild) { let userGuild = await UserGuildModel.getMyGuild(role.roleId, USER_GUILD_SELECT.ENTRY ); if(userGuild) { diff --git a/game-server/app/services/chatService.ts b/game-server/app/services/chatService.ts index 61f5c0a74..873e43658 100644 --- a/game-server/app/services/chatService.ts +++ b/game-server/app/services/chatService.ts @@ -9,12 +9,13 @@ import { PrivateMessageModel, PrivateMessageParam, PrivateMessageType } from './ import { GroupMessageParam, GroupMessageType } from '../db/GroupMessage'; import { genCode, resResult } from '../pubUtils/util'; import { pinus } from 'pinus'; -import { CHANNEL_PREFIX, MSG_CODE_LEN, MSG_SOURCE, MSG_STATUS, MSG_TYPE, ON_GROUP_MSG_ROUTE, ON_MSG_ROUTE, RICH_TEXT_TABLE } from '../consts'; +import { CHANNEL_PREFIX, MSG_CODE_LEN, MSG_SOURCE, MSG_STATUS, MSG_TYPE, ON_GROUP_MSG_ROUTE, ON_MSG_ROUTE, RICH_TEXT_TABLE, RECENT_PRIVATE_CHATS_CNT, MAX_PRIVATE_MSGS } from '../consts'; import { addRedisChannel, getRoleOnlineInfo, redisChannelServer } from './redisService'; import { crc32 } from 'crc'; import { HeroType } from '../db/Hero'; import { GuildType } from '../db/Guild'; import { GuildTrainType } from '../db/GuildTrain'; +import { ChatInfoModel } from '../db/ChatInfo'; /** * @description 生成私聊房间号 @@ -272,3 +273,37 @@ export async function pushGuildBossSucMsg(roleId: string, roleName: string, guil await pushGroupMsgToRoom(groupRoomId(CHANNEL_PREFIX.GUILD, guildCode), msgData); return msgData; } + +export async function roleChatInfos(roleId: string, roleName: string) { + let result = await ChatInfoModel.findInfo(roleId); + if (!result) { + result = await ChatInfoModel.createInfo({ roleId, roleName }); + } + return result; +} + +export async function recentPrivateChatInfos(roleId: string, roleName: string) { + const { recentPrivateChats } = await roleChatInfos(roleId, roleName); + const sortedChats = recentPrivateChats + .sort((a, b) => a.lastChatTime.getTime() - b.lastChatTime.getTime()) + .splice(RECENT_PRIVATE_CHATS_CNT); + if (!sortedChats || !sortedChats.length) return null; + + const unreadChats = sortedChats.filter(chat => { return chat.lastChatTime > chat.lastReadTime }); + let unreadMsgs = {}; + for (let { targetRoleId, lastReadTime } of unreadChats) { + const msgs = await PrivateMessageModel.getMsgsByTime(privateRoomId(roleId, targetRoleId), lastReadTime, MAX_PRIVATE_MSGS); + unreadMsgs[targetRoleId] = msgs; + } + + const roleInfos = await RoleModel.findRoleByField('roleId', sortedChats.map(chat => { return chat.targetRoleId })); + const chatInfos = sortedChats.map( chat => { + for (let { roleId: targetRoleId, quitTime, roleName: targetRoleName, title, guildName, headHid, sHid, lv } of roleInfos) { + if (targetRoleId === chat.targetRoleId) { + const unreadCnt = unreadMsgs[targetRoleId] ? unreadMsgs[targetRoleId].length : 0; + return { ...chat, quitTime, targetRoleName, title, guildName, headHid, sHid, lv, unreadCnt }; + } + } + }); + return chatInfos; +} diff --git a/shared/consts/constModules/chatConst.ts b/shared/consts/constModules/chatConst.ts index 8895df713..1fb8897a9 100644 --- a/shared/consts/constModules/chatConst.ts +++ b/shared/consts/constModules/chatConst.ts @@ -1,4 +1,6 @@ export const MSG_CODE_LEN = 8; +export const RECENT_PRIVATE_CHATS_CNT = 20; +export const MAX_PRIVATE_MSGS = 99; export const MSG_STATUS = { NORMAL: 0, diff --git a/shared/db/ChatInfo.ts b/shared/db/ChatInfo.ts index 368090971..1760c7c1f 100644 --- a/shared/db/ChatInfo.ts +++ b/shared/db/ChatInfo.ts @@ -1,6 +1,12 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; +class PrivateChatRec { + targetRoleId: string; // 聊天玩家 roleId + lastReadTime: Date; // 最后查看时间,用来检查未读消息数 + lastChatTime: Date; // 最后聊天时间 +} + /** * 记录聊天信息,包含配置、最近聊天等 **/ @@ -20,15 +26,24 @@ export default class ChatInfo extends BaseModel { BSSources: [string]; // 弹幕打开的消息来源 @prop({ required: true, default: '' }) bubbleId: string; // 气泡编号 - @prop({ required: true, type: String, default: [] }) - recentPrivateChats: [{ // 最近聊天列表 - targetRoleId: string; // 聊天玩家 roleId - roomId: string; // 聊天 Id - lastReadTime: Date; // 最后查看时间 - }]; + @prop({ required: true, type: PrivateChatRec, default: [] }) + recentPrivateChats: [PrivateChatRec]; // 最近聊天列表 + + public static async createInfo(data: ChatInfoParam) { + const roleId = data.roleId!; + const docData = new ChatInfoModel(); + const result = await ChatInfoModel.findOneAndUpdate({ roleId }, { ...docData.toJSON(), ...data }, { upsert: true, new: true }).select('-_id').lean(); + return result; + } + + public static async findInfo(roleId: string) { + let result = await ChatInfoModel.findOne({ roleId }).select('-_id').lean(); + return result; + } } export const ChatInfoModel = getModelForClass(ChatInfo); export interface ChatInfoType extends Pick, keyof ChatInfo> {}; +export type ChatInfoParam = Partial; diff --git a/shared/db/PrivateMessage.ts b/shared/db/PrivateMessage.ts index 11b32ede8..91f7cd9aa 100644 --- a/shared/db/PrivateMessage.ts +++ b/shared/db/PrivateMessage.ts @@ -51,6 +51,16 @@ export default class PrivateMessage extends BaseModel { const result = await PrivateMessageModel.find({ roomId, seqId: { $lt: fromSeqId } }).sort({ seqId: -1 }).limit(count).lean(); return result; } + + public static async getMsgsByTime(roomId: string, time: Date, count: number) { + const result = await PrivateMessageModel.find({ roomId, createdAt: { $gt: time } }).sort({ seqId: -1 }).limit(count).lean(); + return result; + } + + public static async getMsgByRooms(roomIds: string[], count: number) { + const result = await PrivateMessageModel.find({ roomId: { $in: roomIds } }).sort({ seqId: -1 }).limit(count).lean(); + return result; + } }