From 0bb4caf291e8070fa1b78188428db638633bdd1d Mon Sep 17 00:00:00 2001 From: liangtongchuan Date: Thu, 4 Mar 2021 18:27:39 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=8A=E5=A4=A9=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=A7=81=E8=81=8A=E9=83=A8=E5=88=86=E9=80=BB=E8=BE=91=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=EF=BC=8C=E5=87=8F=E5=B0=91socket=E6=96=AD?= =?UTF-8?q?=E5=BC=80=E7=9A=84=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/servers/chat/handler/chatHandler.ts | 11 ++- game-server/app/services/chatService.ts | 84 +++++++++++++++++++ game-server/runtest.sh | 3 + game-server/test/PinusWSClient.js | 2 +- game-server/test/chat.test.ts | 61 ++++++++++++++ shared/consts/constModules/chatConst.ts | 14 ++++ shared/consts/index.ts | 1 + shared/db/GroupMessage.ts | 5 +- shared/db/Message.ts | 43 ++++++++++ shared/db/PrivateMessage.ts | 15 +++- 10 files changed, 232 insertions(+), 7 deletions(-) create mode 100644 game-server/app/services/chatService.ts create mode 100755 game-server/runtest.sh create mode 100644 game-server/test/chat.test.ts create mode 100644 shared/consts/constModules/chatConst.ts create mode 100644 shared/db/Message.ts diff --git a/game-server/app/servers/chat/handler/chatHandler.ts b/game-server/app/servers/chat/handler/chatHandler.ts index 4015f6225..ecf846351 100644 --- a/game-server/app/servers/chat/handler/chatHandler.ts +++ b/game-server/app/servers/chat/handler/chatHandler.ts @@ -1,6 +1,7 @@ import {Application, BackendSession} from 'pinus'; import { resResult } from '../../../pubUtils/util'; import { STATUS } from '../../../consts'; +import { createPrivateMsg, pushMsgToRole } from '../../../services/chatService'; export default function(app: Application) { @@ -76,8 +77,8 @@ export class ChatHandler { * @param {BackendSession} session * @memberof ChatHandler */ - async sendGroupMessage(msg: { channel: string, type: number, content: string, targetRoleId: string, targetMsgCode: string }, session: BackendSession) { - const { channel, type, content, targetRoleId, targetMsgCode } = msg; + 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; } /** @@ -88,6 +89,12 @@ export class ChatHandler { */ async sendPrivateMessage(msg: { type: number, content: string, targetRoleId: string, targetMsgCode: string }, session: BackendSession) { const { type, content, targetRoleId, targetMsgCode } = msg; + const roleId = session.get('roleId'); + const roleName = session.get('roleName'); + const msgData = await createPrivateMsg(roleId, roleName, type, content, targetRoleId, targetMsgCode); + await pushMsgToRole(targetRoleId, msgData); + if (!msgData) return resResult(STATUS.WRONG_PARMS); + return resResult(STATUS.SUCCESS); } /** diff --git a/game-server/app/services/chatService.ts b/game-server/app/services/chatService.ts new file mode 100644 index 000000000..394c261a2 --- /dev/null +++ b/game-server/app/services/chatService.ts @@ -0,0 +1,84 @@ +import { STATUS } from './../consts/statusCode'; +import { PrivateMessageModel, PrivateMessageParam, PrivateMessageType } from './../db/PrivateMessage'; +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'; + +/** + * @description 生成私聊房间号 + * @export + * @param {string[]} roleIds + * @returns + */ +export function privateRoomId(roleId: string, targetRoleId: string) { + return [roleId, targetRoleId].sort().join('_'); +} + +/** + * @description 生成群聊房间号 + * @export + * @param {string} channel + * @param {string} channelId + * @returns + */ +export function groupRoomId(channel: string, channelId: string) { + return `${channel}_${channelId}`; +} + +/** + * @description 设置群消息和私聊消息的公共字段 + * @param {(PrivateMessageParam | GroupMessageParam)} msg + */ +function setupBaseMsgParm(msg: PrivateMessageParam | GroupMessageParam ) { + msg.msgCode = genCode(MSG_CODE_LEN); + msg.status = MSG_STATUS.NORMAL; +} + +/** + * @description 生成私聊消息数据 + * @param {string} roleId + * @param {string} roleName + * @param {number} type + * @param {string} content + * @param {string} targetRoleId + * @param {string} targetMsgCode + * @returns + */ +function createPrivateMsgData(roleId: string, roleName: string, type: number, content: string, targetRoleId: string, targetMsgCode: string) { + const result: PrivateMessageParam = {roleId, roleName, type, content, targetRoleId, targetMsgCode}; + setupBaseMsgParm(result); + result.roomId = privateRoomId(roleId, targetRoleId); + return result; +} + +/** + * @description 数据库中创建私聊数据 + * @export + * @param {string} roleId + * @param {string} roleName + * @param {number} type + * @param {string} content + * @param {string} targetRoleId + * @param {string} targetMsgCode + * @returns + */ +export async function createPrivateMsg(roleId: string, roleName: string, type: number, content: string, targetRoleId: string, targetMsgCode: string) { + const msgData: PrivateMessageParam = createPrivateMsgData(roleId, roleName, type, content, targetRoleId, targetMsgCode); + const result: PrivateMessageType = await PrivateMessageModel.createMsg(msgData); + return result; +} + +/** + * @description 给某个玩家发送消息 + * @export + * @param {string} targetRoleId + * @param {(PrivateMessageType | GroupMessageType)} msg + */ +export async function pushMsgToRole(targetRoleId: string, msg: PrivateMessageType | GroupMessageType) { + const { sid } = await getRoleOnlineInfo(targetRoleId); + if (sid) { + pinus.app.get('channelService').pushMessageByUids(ON_MSG_ROUTE, resResult(STATUS.SUCCESS, msg), [{uid: targetRoleId, sid}]); + } +} \ No newline at end of file diff --git a/game-server/runtest.sh b/game-server/runtest.sh new file mode 100755 index 000000000..3a65509af --- /dev/null +++ b/game-server/runtest.sh @@ -0,0 +1,3 @@ +cp ./test/PinusWSClient.ts ./node_modules/pinus-robot-plugin/src/PinusWSClient.ts +cp ./test/PinusWSClient.js ./node_modules/pinus-robot-plugin/dist/PinusWSClient.js +./node_modules/mocha/bin/mocha -t 5000 -r ts-node/register ./test/**test.ts diff --git a/game-server/test/PinusWSClient.js b/game-server/test/PinusWSClient.js index 9350ecc10..3f3e13f79 100644 --- a/game-server/test/PinusWSClient.js +++ b/game-server/test/PinusWSClient.js @@ -139,7 +139,7 @@ class PinusWSClient { this.send(this._package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(this.handshakeBuffer)))); } onClose(e) { - console.error('[Pinus] connect close:', e); + console.error('[Pinus] connect close'); // this.emit(Pinus.EVENT_CLOSE,e); } onIOError(e) { diff --git a/game-server/test/chat.test.ts b/game-server/test/chat.test.ts new file mode 100644 index 000000000..3334f9d14 --- /dev/null +++ b/game-server/test/chat.test.ts @@ -0,0 +1,61 @@ +import { MSG_TYPE, ON_MSG_ROUTE } from './../app/consts'; +import { indexOf } from 'underscore'; +import { COM_TEAM_STATUS, DEFAULT_HEROES } from './../../shared/consts/consts'; +import { Client } from './Client'; +import { COM_BTL_QUALITY } from './../app/consts/constModules/itemConst'; +import 'mocha'; +import { PinusWSClient } from 'pinus-robot-plugin'; +import { expect } from 'chai'; +import { checkDisplayItems, checkSuccessResponse } from './CheckPatten'; + +const TEXT_MSG = {type: MSG_TYPE.TEXT, content: 'hello world'} + +function sendPrivateMessageParm(targetRoleInfo, msg) { + const { roleId: targetRoleId, roleName: targetRoleName } = targetRoleInfo; + const result = {targetRoleId, targetRoleName, ...msg}; + return result; +} + +describe('私聊消息发送和接收', function() { + let pinusClient: PinusWSClient; + let pinusClientT: PinusWSClient; // 用做测试队友 + let roleInfo; + let roleInfoT; + + beforeEach(function(done) { + const c = new Client(); + const cT = new Client('13121622738'); + const timer = setInterval(() => { + if (c.client && cT.client) { + pinusClient = c.client; + roleInfo = c.roleInfo; + pinusClientT = cT.client; + roleInfoT = cT.roleInfo; + clearInterval(timer); + done(); + } + }, 500); + }); + + afterEach(function(done) { + pinusClient.disconnect(); + pinusClientT.disconnect(); + done(); + }); + + it('两个玩家互相发送', function(done) { + pinusClientT.on(ON_MSG_ROUTE, (msg) => { + console.log(ON_MSG_ROUTE , msg); + checkSuccessResponse(msg); + expect(msg.data.content).to.equal(TEXT_MSG.content); + }); + + pinusClient.request('chat.chatHandler.sendPrivateMessage', sendPrivateMessageParm(roleInfoT, TEXT_MSG), (res) => { + checkSuccessResponse(res, false); + setTimeout(() => { + done(); + }, 200); + }); + }); + +}); diff --git a/shared/consts/constModules/chatConst.ts b/shared/consts/constModules/chatConst.ts new file mode 100644 index 000000000..29afefa2e --- /dev/null +++ b/shared/consts/constModules/chatConst.ts @@ -0,0 +1,14 @@ +export const MSG_CODE_LEN = 8; + +export const MSG_STATUS = { + NORMAL: 0, + BLOCKED: 1 +} + +export const MSG_TYPE = { + TEXT: 0, + RICH_TEXT: 1, + IMG: 2 +} + +export const ON_MSG_ROUTE = 'onMessage'; \ No newline at end of file diff --git a/shared/consts/index.ts b/shared/consts/index.ts index 255d959f5..b707247af 100644 --- a/shared/consts/index.ts +++ b/shared/consts/index.ts @@ -6,5 +6,6 @@ export * from './constModules/itemConst'; export * from './constModules/sysConst'; export * from './constModules/guildConst'; export * from './constModules/selectConst'; +export * from './constModules/chatConst'; export * from './statusCode'; export * from './dataName'; \ No newline at end of file diff --git a/shared/db/GroupMessage.ts b/shared/db/GroupMessage.ts index 0538e81d3..a26ad15c9 100644 --- a/shared/db/GroupMessage.ts +++ b/shared/db/GroupMessage.ts @@ -28,11 +28,11 @@ export default class GroupMessage extends BaseModel { targetRoleName: string; // 被回复者名称 @prop({ required: true, default: '' }) - msgId: string; // 消息唯一 Id + msgCode: string; // 消息唯一 Id @prop({ required: true, default: 0 }) seqId: number; // 消息在本聊天室的递增 Id @prop({ required: true, default: '' }) - targetMsgId: string; // 回复消息的唯一 Id + targetMsgCode: string; // 回复消息的唯一 Id @prop({ required: true, default: 0 }) status: number; // 消息状态:0,正常;1,屏蔽 @@ -45,3 +45,4 @@ export default class GroupMessage extends BaseModel { export const GroupMessageModel = getModelForClass(GroupMessage); export interface GroupMessageType extends Pick, keyof GroupMessage> {}; +export type GroupMessageParam = Partial; diff --git a/shared/db/Message.ts b/shared/db/Message.ts new file mode 100644 index 000000000..200324b38 --- /dev/null +++ b/shared/db/Message.ts @@ -0,0 +1,43 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; + +/** + * 信息基类 +**/ +@modelOptions({ schemaOptions: { id: false } }) +@index({ roomId: 1, seqId: 1 }) +@index({ msgId: 1 }) +export default class Message extends BaseModel { + @prop({ required: true, default: '' }) + roomId: string; // 频道唯一 Id,由 roleId 和 targetRoleId 排序后拼接 + @prop({ required: true, default: 0 }) + type: number; // 消息类型:0,纯文本;1,富文本;2,表情 + + @prop({ required: true, default: '' }) + roleId: string; // 消息发送者 roleId + @prop({ required: true, default: '' }) + roleName: string; // 消息发送者名称 + @prop({ required: false, default: '' }) + targetRoleId: string; // 接收者 roleId + @prop({ required: false, default: '' }) + targetRoleName: string; // 接收者名称 + + @prop({ required: true, default: '' }) + msgId: string; // 消息唯一 Id + @prop({ required: true, default: 0 }) + seqId: number; // 消息在本聊天室的递增 Id + @prop({ required: false, default: '' }) + targetMsgId: string; // 回复消息的唯一 Id + + @prop({ required: true, default: 0 }) + status: number; // 消息状态:0,正常;1,屏蔽 + + @prop({ required: true, default: '' }) + content: string; // 消息内容 +} + + +export const MessageModel = getModelForClass(Message); + +export interface MessageType extends Pick, keyof Message> {}; +export type MessageParam = Partial; diff --git a/shared/db/PrivateMessage.ts b/shared/db/PrivateMessage.ts index 4685c942b..dcf0c3195 100644 --- a/shared/db/PrivateMessage.ts +++ b/shared/db/PrivateMessage.ts @@ -23,20 +23,31 @@ export default class PrivateMessage extends BaseModel { targetRoleName: string; // 接收者名称 @prop({ required: true, default: '' }) - msgId: string; // 消息唯一 Id + msgCode: string; // 消息唯一 Id @prop({ required: true, default: 0 }) seqId: number; // 消息在本聊天室的递增 Id @prop({ required: true, default: '' }) - targetMsgId: string; // 回复消息的唯一 Id + targetMsgCode: string; // 回复消息的唯一 Id @prop({ required: true, default: 0 }) status: number; // 消息状态:0,正常;1,屏蔽 @prop({ required: true, default: '' }) content: string; // 消息内容 + + public static async createMsg(data: PrivateMessageParam) { + const result = await PrivateMessageModel.findOneAndUpdate({}, {...data}, {upsert: true, new: true}).lean(); + return result; + } + + public static async findOneMsg(query: PrivateMessageParam) { + const result = await PrivateMessageModel.findOne(query).lean(); + return result; + } } export const PrivateMessageModel = getModelForClass(PrivateMessage); export interface PrivateMessageType extends Pick, keyof PrivateMessage> {}; +export type PrivateMessageParam = Partial;