diff --git a/game-server/app/servers/chat/handler/chatHandler.ts b/game-server/app/servers/chat/handler/chatHandler.ts index 928ab6520..4f4e2f279 100644 --- a/game-server/app/servers/chat/handler/chatHandler.ts +++ b/game-server/app/servers/chat/handler/chatHandler.ts @@ -1,7 +1,7 @@ import {Application, BackendSession} from 'pinus'; import { resResult } from '../../../pubUtils/util'; import { DEFAULT_MSG_PER_PAGE, STATUS } from '../../../consts'; -import { createPrivateMsg, getPrivateMessages, pushMsgToRole } from '../../../services/chatService'; +import { createGroupMsg, createPrivateMsg, getPrivateMessages, groupRoomId, pushGroupMsgToRoom, pushMsgToRole } from '../../../services/chatService'; export default function(app: Application) { @@ -79,6 +79,12 @@ export class ChatHandler { */ async sendGroupMessage(msg: { channel: string, channelId: string, type: number, content: string, targetRoleId: string, targetMsgCode: string }, session: BackendSession) { const { channel, channelId, type, content, targetRoleId, targetMsgCode } = msg; + const roleId = session.get('roleId'); + const roleName = session.get('roleName'); + const msgData = await createGroupMsg(roleId, roleName, channel, channelId, type, content, targetRoleId, targetMsgCode); + await pushGroupMsgToRoom(groupRoomId(channel, channelId), msgData); + if (!msgData) return resResult(STATUS.WRONG_PARMS); + return resResult(STATUS.SUCCESS); } /** diff --git a/game-server/app/servers/chat/remote/chatRemote.ts b/game-server/app/servers/chat/remote/chatRemote.ts index 967010938..970056a19 100644 --- a/game-server/app/servers/chat/remote/chatRemote.ts +++ b/game-server/app/servers/chat/remote/chatRemote.ts @@ -1,8 +1,10 @@ import { GroupMessageType } from './../../../db/GroupMessage'; -import { Application, ChannelService, FrontendSession, RemoterClass, pinus } from 'pinus'; +import { Application, ChannelService } from 'pinus'; import { resResult } from '../../../pubUtils/util'; -import { STATUS } from '../../../consts'; +import { ON_ADD_CHANNEL_ROUTE, ON_GROUP_MSG_ROUTE, STATUS } from '../../../consts'; import { PrivateMessageType } from '../../../db/PrivateMessage'; +import { addUserToChannel } from '../../../services/roleService'; +import { ChannelUser } from '../../../domain/ChannelUser'; export default function (app: Application) { return new ChatRemote(app); @@ -40,15 +42,13 @@ export class ChatRemote { public async addWorldChannel(roleId: string, serverId: number, sid: string, flag: boolean = true) { const name = `world${serverId}`; let channel = this.channelService.getChannel(name, flag); + if (!channel) return; + channel.add(roleId, sid); let param = { roleId }; channel.pushMessage('onWorldAdd', resResult(STATUS.SUCCESS, param)); - if (!!channel) { - channel.add(roleId, sid); - } - return this.getWorldChannel(name); } @@ -86,10 +86,8 @@ export class ChatRemote { let channel = this.channelService.getChannel(name, false); // leave channel - if (!!channel) { - channel.leave(roleId, sid); - } - + if (!channel) return; + channel.leave(roleId, sid); let param = { roleId }; @@ -120,7 +118,10 @@ export class ChatRemote { * @memberof ChatRemote */ public async addChannel(channelName: string, roleId: string, sid: string) { - + let channel = this.channelService.getChannel(channelName, true); + if (!channel) return; + addUserToChannel(channel, new ChannelUser(roleId, sid)); + channel.pushMessage(ON_ADD_CHANNEL_ROUTE, resResult(STATUS.SUCCESS, { roleId, channelName })); } /** @@ -131,7 +132,15 @@ export class ChatRemote { * @memberof ChatRemote */ public async leaveChannel(channelName: string, roleId: string, sid: string) { - + let channel = this.channelService.getChannel(channelName, false); + // leave channel + if (!channel) return; + channel.leave(roleId, sid); + let param = { + roleId, + channelName + }; + channel.pushMessage('onLeave', resResult(STATUS.SUCCESS, param)); } /** @@ -139,8 +148,10 @@ export class ChatRemote { * @param {Partial} msg * @memberof ChatRemote */ - public async sendGroupMsg(msg: Partial) { - + public async sendGroupMsg(roomId: string, msg: Partial) { + let channel = this.channelService.getChannel(roomId, false); + if (!channel) return; + channel.pushMessage(ON_GROUP_MSG_ROUTE, resResult(STATUS.SUCCESS, msg)); } /** @@ -151,5 +162,4 @@ export class ChatRemote { public async sendPrivateMsg(msg: Partial) { } - -} \ No newline at end of file +} diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index 44798915f..3c32e6091 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -19,6 +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'; export default function (app: Application) { return new EntryHandler(app); } @@ -88,7 +89,8 @@ export class EntryHandler { // put user into channel // console.log(JSON.stringify(self.app.rpc.battle)) // await self.app.rpc.battle.battleRemote.add.route(session)(role.roleId, self.app.get('serverId'), role.serverId, true); - + addRoleToSysChannel(role.roleId, self.app.get('serverId'), role.serverId); + addRoleToWorldChannel(role.roleId, self.app.get('serverId'), role.serverId); await self.app.rpc.chat.chatRemote.addWorldChannel.route(session)(role.roleId, serverId, self.app.get('serverId')); await self.app.rpc.chat.guildRemote.enterMyChannel.route(session)(role.roleId, self.app.get('serverId')); let heros = await HeroModel.findByRole(role.roleId, [], HERO_SELECT.ENTRY, true); @@ -110,6 +112,7 @@ export class EntryHandler { if(userGuild) { let guild = await GuildModel.findGuild(userGuild.guildCode, role.serverId, GUILD_SELECT.ENTRY); if(guild) { + addRoleToGuildChannel(role.roleId, self.app.get('serverId'), guild.code); role['guildAuth'] = userGuild.auth; let {lv: guildLv, memberCnt} = guild; let dicGuild = gameData.centerBase.get(guildLv); @@ -132,7 +135,7 @@ export class EntryHandler { * @param {Object} session current session object * */ - onUserLeave(session: FrontendSession, reason: string) { + async onUserLeave(session: FrontendSession, reason: string) { if (!session || !session.uid) { return; } @@ -148,6 +151,9 @@ export class EntryHandler { // this.app.rpc.battle.battleRemote.kick.route(session)(roleId, this.app.get('serverId'), serverId); this.app.rpc.chat.chatRemote.kickWorldChannel.route(session, true)(roleId, sid, serverId); this.app.rpc.chat.guildRemote.leaveMyChannel.route(session)(roleId, sid); + await leaveSysChannel(roleId, sid, serverId); + await leaveWorldChannel(roleId, sid, serverId); + await leaveGuildChannel(roleId, sid); RoleModel.updateRoleInfo(roleId, { quitTime: nowSeconds() }); } diff --git a/game-server/app/services/chatService.ts b/game-server/app/services/chatService.ts index 8d91ee014..8f80d6bcf 100644 --- a/game-server/app/services/chatService.ts +++ b/game-server/app/services/chatService.ts @@ -1,3 +1,5 @@ +import { RoleModel } from './../db/Role'; +import { GroupMessageModel } from './../db/GroupMessage'; import { CounterModel } from './../db/Counter'; import { STATUS } from './../consts/statusCode'; import { PrivateMessageModel, PrivateMessageParam, PrivateMessageType } from './../db/PrivateMessage'; @@ -5,7 +7,8 @@ import { GroupMessageParam, GroupMessageType } from '../db/GroupMessage'; import { genCode, resResult } from '../pubUtils/util'; import { pinus } from 'pinus'; import { MSG_CODE_LEN, MSG_STATUS, ON_MSG_ROUTE } from '../consts'; -import { getRoleOnlineInfo } from './redisService'; +import { addRedisChannel, getRoleOnlineInfo, redisChannelServer } from './redisService'; +import { crc32 } from 'crc'; /** * @description 生成私聊房间号 @@ -63,6 +66,13 @@ async function createPrivateMsgData(roleId: string, roleName: string, type: numb return result; } +async function createGroupMsgData(roleId: string, roleName: string, channel: string, channelId: string, type: number, content: string, targetRoleId: string, targetMsgCode: string) { + const result: GroupMessageParam = {roleId, roleName, channel, channelId, type, content, targetRoleId, targetMsgCode}; + result.roomId = groupRoomId(channel, channelId); + await setupBaseMsgParm(result); + return result; +} + /** * @description 数据库中创建私聊数据 * @export @@ -105,4 +115,72 @@ export async function pushMsgToRole(targetRoleId: string, msg: PrivateMessageTyp export async function getPrivateMessages(roleId: string, targetRoleId: string, fromSeqId: number, count: number) { const result = await PrivateMessageModel.getMsgs(privateRoomId(roleId, targetRoleId), fromSeqId, count); return result; +} + +export async function createGroupMsg(roleId: string, roleName: string, channel: string, channelId: string, type: number, content: string, targetRoleId: string, targetMsgCode: string) { + const msgData: GroupMessageParam = await createGroupMsgData(roleId, roleName, channel, channelId, type, content, targetRoleId, targetMsgCode); + const result: GroupMessageType = await GroupMessageModel.createMsg(msgData); + return result; +} + +export async function pushGroupMsgToRoom(roomId: string, msg: GroupMessageType) { + const channelSid = await channelServer(roomId); + await pinus.app.rpc.chat.chatRemote.sendGroupMsg.toServer(channelSid, roomId, msg); +} + +export async function channelServer(roomId: string) { + const existSid = await redisChannelServer(roomId); + if (existSid) { + return existSid; + } + const servers = pinus.app.getServersByType('chat'); + if (!servers || !servers.length) return null; + + let index = Math.abs(crc32(roomId)) % servers.length; + const newSid = servers[index].id; + const addResult = await addRedisChannel(roomId, newSid); + if (!addResult) return null; + return newSid; +} + +async function addRoleToChannel(roomId: string, roleId: string, sid: string) { + const channelSid = await channelServer(roomId); + await pinus.app.rpc.chat.chatRemote.addChannel.toServer(channelSid, roomId, roleId, sid); +} + +export async function addRoleToSysChannel(roleId: string, sid: string, serverId: number) { + const roomId = groupRoomId('sys', `${serverId}`); + await addRoleToChannel(roomId, roleId, sid); +} + +export async function addRoleToWorldChannel(roleId: string, sid: string, serverId: number) { + const roomId = groupRoomId('new_world', `${serverId}`); + await addRoleToChannel(roomId, roleId, sid); +} + +export async function addRoleToGuildChannel(roleId: string, sid: string, guildCode: string) { + const roomId = groupRoomId('new_guild', guildCode); + await addRoleToChannel(roomId, roleId, sid); +} + +async function leaveChannel(roomId: string, roleId: string, sid: string) { + const channelSid = await channelServer(roomId); + await pinus.app.rpc.chat.chatRemote.leaveChannel.toServer(channelSid, roomId, roleId, sid); +} + +export async function leaveSysChannel(roleId: string, sid: string, serverId: number) { + const roomId = groupRoomId('sys', `${serverId}`); + await leaveChannel(roomId, roleId, sid); +} + +export async function leaveWorldChannel(roleId: string, sid: string, serverId: number) { + const roomId = groupRoomId('new_world', `${serverId}`); + await leaveChannel(roomId, roleId, sid); +} + +export async function leaveGuildChannel(roleId: string, sid: string) { + const { guildCode } = await RoleModel.findByRoleId(roleId, 'guildCode'); + if (!guildCode) return; + const roomId = groupRoomId('new_guild', guildCode); + await leaveChannel(roomId, roleId, sid); } \ No newline at end of file diff --git a/game-server/app/services/redisService.ts b/game-server/app/services/redisService.ts index b356cfccf..36b0f0c0d 100644 --- a/game-server/app/services/redisService.ts +++ b/game-server/app/services/redisService.ts @@ -346,12 +346,12 @@ export function redisSidKey(roleId: string) { } export async function redisChannelServer(roomId: string) { - const sid = await redisClient().hgetAsync(REDIS_KEY.ONLINE_USERS, roomId); + const sid = await redisClient().hgetAsync(REDIS_KEY.CHANNEL_SERVERS, roomId); return sid; } export async function addRedisChannel(roomId: string, sid: string) { - const result = await redisClient().hsetAsync(REDIS_KEY.ONLINE_USERS, roomId, sid); + const result = await redisClient().hsetAsync(REDIS_KEY.CHANNEL_SERVERS, roomId, sid); return result; } diff --git a/game-server/test/Client.ts b/game-server/test/Client.ts index 24162b86f..82f8aa512 100644 --- a/game-server/test/Client.ts +++ b/game-server/test/Client.ts @@ -1,6 +1,7 @@ import { PinusWSClient } from 'pinus-robot-plugin'; import { expect } from 'chai'; import { checkSuccessResponse } from './CheckPatten'; +import { ON_ADD_CHANNEL_ROUTE } from '../app/consts'; export class Client { private _client; @@ -19,6 +20,11 @@ export class Client { this._client.request('connector.entryHandler.debugQueryToken', {tel, magicWord: 'zyz666server518'}, (res) => { checkSuccessResponse(res); expect(res.data.token).to.be.an('string'); + this._client.on(ON_ADD_CHANNEL_ROUTE, (msg) => { + checkSuccessResponse(msg); + expect(msg.data.roleId).to.be.a('string'); + expect(msg.data.channelName).to.be.a('string'); + }); this._client.request('connector.entryHandler.enter', {serverId: 1, ...res.data}, (enterRes) => { // 消息回调 // console.log('connector返回'); diff --git a/game-server/test/chat.test.ts b/game-server/test/chat.test.ts index ef758f946..cfd0f7c90 100644 --- a/game-server/test/chat.test.ts +++ b/game-server/test/chat.test.ts @@ -1,4 +1,4 @@ -import { DEFAULT_MSG_PER_PAGE, MSG_TYPE, ON_MSG_ROUTE } from './../app/consts'; +import { DEFAULT_MSG_PER_PAGE, MSG_TYPE, ON_MSG_ROUTE, ON_GROUP_MSG_ROUTE, CHANNEL_PREFIX } from './../app/consts'; import { Client } from './Client'; import 'mocha'; import { PinusWSClient } from 'pinus-robot-plugin'; @@ -13,6 +13,40 @@ function sendPrivateMessageParm(targetRoleInfo, msg) { return result; } +function sendGroupMessageParm(channel, channelId, msg) { + const result = {channel, channelId, ...msg}; + return result; +} + +function checkGroupMsg(msg, roleId, roomId, content) { + expect(msg.content).to.equal(TEXT_MSG.content); + expect(msg.roleId).to.equal(roleId); + expect(msg.content).to.equal(content); + expect(msg.roomId).to.equal(roomId); +} + +function testGroupMsg(pinusClient: PinusWSClient, roleInfo: any, pinusClientT: PinusWSClient, channel: string, channelId: string, done: Mocha.Done) { + let msgReceiveCnt = 0; + const roomId = `${channel}_${channelId}`; + pinusClientT.on(ON_GROUP_MSG_ROUTE, (res) => { + checkSuccessResponse(res); + checkGroupMsg(res.data, roleInfo.roleId, roomId, TEXT_MSG.content); + msgReceiveCnt += 1; + }); + pinusClient.on(ON_GROUP_MSG_ROUTE, (res) => { + checkSuccessResponse(res); + checkGroupMsg(res.data, roleInfo.roleId, roomId, TEXT_MSG.content); + msgReceiveCnt += 1; + }); + pinusClient.request('chat.chatHandler.sendGroupMessage', sendGroupMessageParm(channel, channelId, TEXT_MSG), (res) => { + checkSuccessResponse(res, false); + setTimeout(() => { + expect(msgReceiveCnt).to.be.equal(2); + done(); + }, 1000); + }); +} + describe('聊天测试', function() { let pinusClient: PinusWSClient; let pinusClientT: PinusWSClient; // 用做测试队友 @@ -72,4 +106,12 @@ describe('聊天测试', function() { }) }, 1000); }); + + it('测试系统频道消息', function(done) { + testGroupMsg(pinusClient, roleInfo, pinusClientT, CHANNEL_PREFIX.SYS, roleInfo.serverId, done); + }); + + it('测试世界频道消息', function(done) { + testGroupMsg(pinusClient, roleInfo, pinusClientT, CHANNEL_PREFIX.WORLD, roleInfo.serverId, done); + }); }); diff --git a/shared/consts/constModules/chatConst.ts b/shared/consts/constModules/chatConst.ts index a74b4ee11..c4fd8b9ec 100644 --- a/shared/consts/constModules/chatConst.ts +++ b/shared/consts/constModules/chatConst.ts @@ -11,6 +11,14 @@ export const MSG_TYPE = { IMG: 2 } +export const CHANNEL_PREFIX = { + SYS: 'sys', + WORLD: 'new_world', + GUILD: 'new_guild', +} + export const ON_MSG_ROUTE = 'onMessage'; +export const ON_GROUP_MSG_ROUTE = 'onGroupMessage'; +export const ON_ADD_CHANNEL_ROUTE = 'onAddChannel'; export const DEFAULT_MSG_PER_PAGE = 10; \ No newline at end of file diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index b2548ba6f..b4efd7966 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -225,6 +225,7 @@ export const REDIS_KEY = { GUILD_ACTIVE_RANK: "guildActiveRank", // 公会周活跃排行榜 DB_GAME: 'db_game', // 服务器列表 ONLINE_USERS: 'onlineUsers', // 在线用户情况 + CHANNEL_SERVERS: 'chat:channelServers', // 渠道对应的 chat 服务器 Id } // 各排行榜对应hash的key diff --git a/shared/db/GroupMessage.ts b/shared/db/GroupMessage.ts index a26ad15c9..0173ef8de 100644 --- a/shared/db/GroupMessage.ts +++ b/shared/db/GroupMessage.ts @@ -39,6 +39,21 @@ export default class GroupMessage extends BaseModel { @prop({ required: true, default: '' }) content: string; // 消息内容 + + public static async createMsg(data: GroupMessageParam) { + const result = await GroupMessageModel.findOneAndUpdate({ msgCode: data.msgCode }, {...data}, {upsert: true, new: true}).lean(); + return result; + } + + public static async findOneMsg(query: GroupMessageParam) { + const result = await GroupMessageModel.findOne(query).lean(); + return result; + } + + public static async getMsgs(roomId: string, fromSeqId: number, count: number) { + const result = await GroupMessageModel.find({ roomId, seqId: { $lt: fromSeqId } }).sort({ seqId: -1 }).limit(count).lean(); + return result; + } }