From 8ce0dc040f38d3e1db2ec9f2a20d28d474d703ee Mon Sep 17 00:00:00 2001 From: liangtongchuan Date: Sat, 15 Aug 2020 20:34:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=20chat=20=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=20game-server=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=83=A8=E7=BD=B2=E3=80=81=E5=9F=9F?= =?UTF-8?q?=E5=90=8D=E8=AE=BF=E9=97=AE=E3=80=81=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=92=8C=E5=9F=BA=E7=A1=80=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +- game-server/Dockerfile | 9 + game-server/app.ts | 172 ++ game-server/app/db/BaseModel.ts | 24 + game-server/app/db/User.ts | 45 + .../app/servers/chat/handler/chatHandler.ts | 76 + .../app/servers/chat/remote/chatRemote.ts | 92 + .../servers/connector/handler/entryHandler.ts | 63 + .../app/servers/gate/handler/gateHandler.ts | 42 + game-server/app/servers/user.rpc.define.ts | 14 + game-server/app/util/dispatcher.ts | 7 + game-server/app/util/routeUtil.ts | 15 + game-server/config/adminServer.ts | 11 + game-server/config/adminUser.ts | 17 + game-server/config/clientProtos.ts | 14 + game-server/config/dictionary.ts | 1 + game-server/config/log4js.ts | 134 ++ game-server/config/log4js.without.logfile.ts | 30 + game-server/config/master.ts | 13 + game-server/config/serverProtos.ts | 7 + game-server/config/servers.ts | 45 + game-server/config/servers_multi_ser.ts | 45 + game-server/docker-compose.yaml | 20 + game-server/generatePm2Config.js | 119 ++ game-server/package-lock.json | 1726 +++++++++++++++++ game-server/package.json | 37 + game-server/pomeloPm2Start.json | 149 ++ game-server/preload.ts | 40 + game-server/pushdocker.sh | 2 + game-server/pushdocker_zyz_test.sh | 2 + game-server/robot/robot.ts | 97 + game-server/startGameServer.sh | 5 + game-server/tsconfig.json | 35 + game-server/tsrun.js | 34 + npm-install.bat | 4 + npm-install.sh | 5 + 36 files changed, 3165 insertions(+), 2 deletions(-) create mode 100644 game-server/Dockerfile create mode 100644 game-server/app.ts create mode 100644 game-server/app/db/BaseModel.ts create mode 100644 game-server/app/db/User.ts create mode 100644 game-server/app/servers/chat/handler/chatHandler.ts create mode 100644 game-server/app/servers/chat/remote/chatRemote.ts create mode 100644 game-server/app/servers/connector/handler/entryHandler.ts create mode 100644 game-server/app/servers/gate/handler/gateHandler.ts create mode 100644 game-server/app/servers/user.rpc.define.ts create mode 100644 game-server/app/util/dispatcher.ts create mode 100644 game-server/app/util/routeUtil.ts create mode 100644 game-server/config/adminServer.ts create mode 100644 game-server/config/adminUser.ts create mode 100644 game-server/config/clientProtos.ts create mode 100644 game-server/config/dictionary.ts create mode 100644 game-server/config/log4js.ts create mode 100644 game-server/config/log4js.without.logfile.ts create mode 100644 game-server/config/master.ts create mode 100644 game-server/config/serverProtos.ts create mode 100644 game-server/config/servers.ts create mode 100644 game-server/config/servers_multi_ser.ts create mode 100644 game-server/docker-compose.yaml create mode 100644 game-server/generatePm2Config.js create mode 100644 game-server/package-lock.json create mode 100644 game-server/package.json create mode 100644 game-server/pomeloPm2Start.json create mode 100644 game-server/preload.ts create mode 100755 game-server/pushdocker.sh create mode 100755 game-server/pushdocker_zyz_test.sh create mode 100644 game-server/robot/robot.ts create mode 100644 game-server/startGameServer.sh create mode 100644 game-server/tsconfig.json create mode 100644 game-server/tsrun.js create mode 100644 npm-install.bat create mode 100644 npm-install.sh diff --git a/README.md b/README.md index 2d3b624e6..4daef29ee 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,15 @@ -# zyz_server +# 环境搭建 +- 安装 ts 环境 +`npm install -g tsc ts-node typescript` +- 安装 pinus +`npm install -g pinus` -赵云传服务器 \ No newline at end of file +# 运行 +## 简介 +服务器主要分为游戏服和账号服,游戏服以长连接为主,处理主要的游戏逻辑。账号服以短连接为主,处理账号等功能。 + +## 运行游戏服 +`cd game-server && node tsrun.js` + +## 运行 web-server +`cd web-server && node app` \ No newline at end of file diff --git a/game-server/Dockerfile b/game-server/Dockerfile new file mode 100644 index 000000000..2f6e4c020 --- /dev/null +++ b/game-server/Dockerfile @@ -0,0 +1,9 @@ +FROM node:12 +RUN mkdir /game-server +WORKDIR /game-server +RUN npm install -g cnpm --registry=https://registry.npm.taobao.org +RUN cnpm install -g ts-node +RUN cnpm install -g typescript +RUN cnpm install -g pm2 +RUN cnpm install -g pinus +CMD pinus start diff --git a/game-server/app.ts b/game-server/app.ts new file mode 100644 index 000000000..202fd54aa --- /dev/null +++ b/game-server/app.ts @@ -0,0 +1,172 @@ +import { + createTcpAcceptor, + createTcpMailBox, + FrontendOrBackendSession, + HandlerCallback, + pinus, + RESERVED, + RouteRecord +} from 'pinus'; +import * as mongoose from 'mongoose'; +import * as redis from 'redis'; +import './app/servers/user.rpc.define' +import * as routeUtil from './app/util/routeUtil'; +import { preload } from './preload'; + +// TODO 需要整理。 +import _pinus = require('pinus'); + +const filePath = (_pinus as any).FILEPATH; +filePath.MASTER = '/config/master'; +filePath.SERVER = '/config/servers'; +filePath.CRON = '/config/crons'; +filePath.LOG = '/config/log4js'; +filePath.SERVER_PROTOS = '/config/serverProtos'; +filePath.CLIENT_PROTOS = '/config/clientProtos'; +filePath.MASTER_HA = '/config/masterha'; +filePath.LIFECYCLE = '/lifecycle'; +filePath.SERVER_DIR = '/app/servers/'; +filePath.CONFIG_DIR = '/config'; + +const adminfilePath = _pinus.DEFAULT_ADMIN_PATH; +adminfilePath.ADMIN_FILENAME = 'adminUser'; +adminfilePath.ADMIN_USER = 'config/adminUser'; +/** + * 替换全局Promise + * 自动解析sourcemap + * 捕获全局错误 + */ +preload(); + +// 创建 mongodb 连接 +mongoose.connect('mongodb://root:zyz_2020@dds-8vbdb47c6fb58a541.mongodb.zhangbei.rds.aliyuncs.com:3717,dds-8vbdb47c6fb58a542.mongodb.zhangbei.rds.aliyuncs.com:3717/admin?replicaSet=mgset-500808098', (err) => { + if (err) { + console.log('mongodb connect err', err); + } else { + console.log('mongodb connect suc'); + } +}); + +// 创建 redis 连接 +const client = redis.createClient(6379, 'r-8vb4i2kgl91886fkxd.redis.zhangbei.rds.aliyuncs.com', {detect_buffers: true}); +client.auth('zyz_2020', (err, reply) => { + if (err) { + console.log('redis err', err); + } else { + console.log('redis suc'); + } +}) +client.set('hello', 'redis', redis.print); + +/** + * Init app for client. + */ +let app = pinus.createApp(); +app.set('name', 'chatofpomelo-websocket'); + +// app configuration +app.configure('production|development', 'connector', function () { + app.set('connectorConfig', + { + connector: pinus.connectors.hybridconnector, + heartbeat: 60, + useDict: true, + useProtobuf: true + }); + + /** + // 缓存大小不够 日志示例 + [2020-03-27T10:44:48.752] [ERROR] pinus - [chat-server-1 channelService.js] [pushMessage] fail to dispatch msg to serverId: connector-server-1, err:RangeError [ERR_OUT_OF_RANGE]: The value of "offset" is out of range. It must be >= 0 and <= 0. Received 1 + at boundsError (internal/buffer.js:53:9) + at writeU_Int8 (internal/buffer.js:562:5) + at Buffer.writeUInt8 (internal/buffer.js:569:10) + at Encoder.writeBytes (F:\develop\gong4-server\logicServer\pinus\packages\pinus-protobuf\lib\encoder.ts:195:20) + */ + app.set('protobufConfig', { + // protobuf Encoder 使用 5m 的缓存 需要保证每个消息不会超过指定的缓存大小,超过了就会抛出异常 + encoderCacheSize: 5 * 1024 * 1024, + // decode 对客户端请求消息做校验 + decodeCheckMsg: true, + }); +}); + +app.configure('production|development', 'gate', function () { + app.set('connectorConfig', + { + connector: pinus.connectors.hybridconnector, + useProtobuf: true + }); +}); + + +function errorHandler(err: Error, msg: any, resp: any, + session: FrontendOrBackendSession, cb: HandlerCallback) { + console.error(`${ pinus.app.serverId } error handler msg[${ JSON.stringify(msg) }] ,resp[${ JSON.stringify(resp) }] , + to resolve unknown exception: sessionId:${ JSON.stringify(session.export()) } , + error stack: ${ err.stack }`); + if (!resp) { + resp = { code: 1003 }; + } + cb(err, resp); +} + +export function globalErrorHandler(err: Error, msg: any, resp: any, + session: FrontendOrBackendSession, cb: HandlerCallback) { + console.error(`${ pinus.app.serverId } globalErrorHandler msg[${ JSON.stringify(msg) }] ,resp[${ JSON.stringify(resp) }] , + to resolve unknown exception: sessionId:${ JSON.stringify(session.export()) } , + error stack: ${ err.stack }`); + + + if (cb) { + cb(err, resp ? resp : { code: 503 }); + } +} + +// app configure +app.configure('production|development', function () { + app.set(RESERVED.ERROR_HANDLER, errorHandler); + app.set(RESERVED.GLOBAL_ERROR_HANDLER, globalErrorHandler); + app.globalAfter((err: Error, routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, resp: any, cb: HandlerCallback) => { + console.log('global after ', err, routeRecord, msg) + }) + + app.globalBefore((routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, cb: HandlerCallback) => { + if (msg.body === null) { + cb(new Error(`msg body ===null maybe protobuf check error uid:${ session.uid } ${ JSON.stringify(msg) }`), { code: 499 }); + return; + } + cb(null); + }) + + // route configures + app.route('chat', routeUtil.chat); + + // filter configures + app.filter(new pinus.filters.timeout()); + + // RPC 启用TCP协议 + app.set('proxyConfig', { + mailboxFactory: createTcpMailBox, + // bufferMsg:true + // rpc 超时时间 + // timeout: 20 * 1000, + // dynamicUserProxy: true, + }); + app.set('remoteConfig', { + acceptorFactory: createTcpAcceptor, + // bufferMsg:true, + // interval:50, + }); +}); + +app.configure('development', function () { + // enable the system monitor modules + app.enable('systemMonitor'); +}); + +if (app.isMaster()) { + // app.use(createRobotPlugin({scriptFile: __dirname + '/robot/robot.js'})); +} + +// start app +app.start(); \ No newline at end of file diff --git a/game-server/app/db/BaseModel.ts b/game-server/app/db/BaseModel.ts new file mode 100644 index 000000000..1e3db4a46 --- /dev/null +++ b/game-server/app/db/BaseModel.ts @@ -0,0 +1,24 @@ +import { prop, pre } from '@typegoose/typegoose'; + +/** + * BaseModel +*/ +@pre('save', function (next) { + if (!this.createdAt || this.isNew) { + this.createdAt = this.updatedAt = new Date() + } else { + this.updatedAt = new Date() + } + next() +}) + +export default class BaseModel { + + _id?: string + + @prop() + createdAt: Date + + @prop() + updatedAt: Date +} \ No newline at end of file diff --git a/game-server/app/db/User.ts b/game-server/app/db/User.ts new file mode 100644 index 000000000..399e3ddcc --- /dev/null +++ b/game-server/app/db/User.ts @@ -0,0 +1,45 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop } from '@typegoose/typegoose'; + + +/** + * 用户字段接口 +*/ +@index({ userNo: 1 }) +export default class User extends BaseModel { + + @prop({ required: true}) + userNo: number; + + @prop({ required: true}) + userName: string; + + @prop({ required: true}) + token: string; + + @prop({ required: true}) + telHash: string; + + //#region(实例方法 和 实例方法) + public async userInstanceTestMethods() { + + const user: User = new User(); + user.userName = '我是实例化方法测试'; + user.userNo = 9527; + + return user; + } + + public static async userStaticTestMethods() { + + const user: User = new User(); + user.userName = '我是静态方法测试'; + user.userNo = 9527; + + return user; + } + + //#endregion +} + +export const UserModel = getModelForClass(User); \ No newline at end of file diff --git a/game-server/app/servers/chat/handler/chatHandler.ts b/game-server/app/servers/chat/handler/chatHandler.ts new file mode 100644 index 000000000..da0a50644 --- /dev/null +++ b/game-server/app/servers/chat/handler/chatHandler.ts @@ -0,0 +1,76 @@ +import { UserModel } from './../../../db/User'; +import { ChatRemote } from '../remote/chatRemote'; +import {Application, BackendSession} from 'pinus'; +import { FrontendSession } from 'pinus'; + +export default function(app: Application) { + return new ChatHandler(app); +} + +export class ChatHandler { + constructor(private app: Application) { + } + + /** + * Send messages to users + * + * @param {Object} msg message from client + * @param {Object} session + * + */ + async send(msg: {content: string , target: string}, session: BackendSession) { + let rid = session.get('rid'); + let username = session.uid.split('*')[0]; + let channelService = this.app.get('channelService'); + let param = { + msg: msg.content, + from: username, + target: msg.target + }; + let channel = channelService.getChannel(rid, false); + + // the target is all users + if (msg.target === '*') { + channel.pushMessage('onChat', param); + } + // the target is specific user + else { + let tuid = msg.target + '*' + rid; + let tsid = channel.getMember(tuid)['sid']; + channelService.pushMessageByUids('onChat', param, [{ + uid: tuid, + sid: tsid + }]); + } + } + + async send2(msg: {content: string , target: string}, session: BackendSession) { + let rid = session.get('rid'); + let username = session.uid.split('*')[0]; + let channelService = this.app.get('channelService'); + let param = { + msg: msg.content, + from: username, + target: msg.target + }; + let channel = channelService.getChannel(rid, false); + + console.log(`got user in send2 :`,); + const user = await UserModel.findOneAndUpdate({userName: username}, {userName: username, userNo: 666}, {upsert: true, new: true}).lean(); + console.log(`got user in send2 :`, user); + + // the target is all users + if (msg.target === '*') { + channel.pushMessage('onChat', param); + } + // the target is specific user + else { + let tuid = msg.target + '*' + rid; + let tsid = channel.getMember(tuid)['sid']; + channelService.pushMessageByUids('onChat', param, [{ + uid: tuid, + sid: tsid + }]); + } + } +} \ No newline at end of file diff --git a/game-server/app/servers/chat/remote/chatRemote.ts b/game-server/app/servers/chat/remote/chatRemote.ts new file mode 100644 index 000000000..ab4f48203 --- /dev/null +++ b/game-server/app/servers/chat/remote/chatRemote.ts @@ -0,0 +1,92 @@ +import { Application, ChannelService, FrontendSession, RemoterClass } from 'pinus'; + +export default function (app: Application) { + return new ChatRemote(app); +} + +// rpc 定义挪到单独的定义文件(user.rpc.define.ts)。解决ts-node 有可能找不到定义的问题。 +// 你也可以用其它方法解决,或者没有遇到过这个问题的话,定义还是可以放在这里。 + +// UserRpc的命名空间自动合并 +// declare global { +// interface UserRpc { +// chat: { +// chatRemote: RemoterClass; +// }; +// } +// } +export class ChatRemote { + + constructor(private app: Application) { + this.app = app; + this.channelService = app.get('channelService'); + } + + private channelService: ChannelService; + + /** + * Add user into chat channel. + * + * @param {String} uid unique id for user + * @param {String} sid server id + * @param {String} name channel name + * @param {boolean} flag channel parameter + * + */ + public async add(uid: string, sid: string, name: string, flag: boolean) { + let channel = this.channelService.getChannel(name, flag); + let username = uid.split('*')[0]; + let param = { + user: username + }; + channel.pushMessage('onAdd', param); + + if (!!channel) { + channel.add(uid, sid); + } + + return this.get(name, flag); + } + + /** + * Get user from chat channel. + * + * @param {Object} opts parameters for request + * @param {String} name channel name + * @param {boolean} flag channel parameter + * @return {Array} users uids in channel + * + */ + private get(name: string, flag: boolean) { + let users: string[] = []; + let channel = this.channelService.getChannel(name, flag); + if (!!channel) { + users = channel.getMembers(); + } + for (let i = 0; i < users.length; i++) { + users[i] = users[i].split('*')[0]; + } + return users; + } + + /** + * Kick user out chat channel. + * + * @param {String} uid unique id for user + * @param {String} sid server id + * @param {String} name channel name + * + */ + public async kick(uid: string, sid: string, name: string) { + let channel = this.channelService.getChannel(name, false); + // leave channel + if (!!channel) { + channel.leave(uid, sid); + } + let username = uid.split('*')[0]; + let param = { + user: username + }; + channel.pushMessage('onLeave', param); + } +} \ 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 new file mode 100644 index 000000000..adf4f9c5d --- /dev/null +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -0,0 +1,63 @@ +import {Application} from 'pinus'; +import {FrontendSession} from 'pinus'; + +export default function (app: Application) { + return new EntryHandler(app); +} + +export class EntryHandler { + constructor(private app: Application) { + } + + + /** + * New client entry chat server. + * + * @param {Object} msg request message + * @param {Object} session current session object + */ + async enter(msg: { rid: string, username: string }, session: FrontendSession) { + let self = this; + let rid = msg.rid; + let uid = msg.username + '*' + rid; + let sessionService = self.app.get('sessionService'); + + // duplicate log in + if (!!sessionService.getByUid(uid)) { + return { + code: 500, + error: true + }; + } + + await session.abind(uid); + session.set('rid', rid); + session.push('rid', function (err) { + if (err) { + console.error('set rid for session service failed! error is : %j', err.stack); + } + }); + session.on('closed', this.onUserLeave.bind(this)); + + // put user into channel + let users = await self.app.rpc.chat.chatRemote.add.route(session)(uid, self.app.get('serverId'), rid, true); + + return { + users: users + }; + } + + /** + * User log out handler + * + * @param {Object} app current application + * @param {Object} session current session object + * + */ + onUserLeave(session: FrontendSession) { + if (!session || !session.uid) { + return; + } + this.app.rpc.chat.chatRemote.kick.route(session, true)(session.uid, this.app.get('serverId'), session.get('rid')); + } +} \ No newline at end of file diff --git a/game-server/app/servers/gate/handler/gateHandler.ts b/game-server/app/servers/gate/handler/gateHandler.ts new file mode 100644 index 000000000..2f10e73a8 --- /dev/null +++ b/game-server/app/servers/gate/handler/gateHandler.ts @@ -0,0 +1,42 @@ +import { dispatch } from '../../../util/dispatcher'; +import { Application , BackendSession} from 'pinus'; + +export default function (app: Application) { + return new GateHandler(app); +} + +export class GateHandler { + constructor(private app: Application) { + } + + /** + * Gate handler that dispatch user to connectors. + * + * @param {Object} msg message from client + * @param {Object} session + * + */ + async queryEntry(msg: {uid: string}, session: BackendSession) { + let uid = msg.uid; + if (!uid) { + return { + code: 500 + }; + } + // get all connectors + let connectors = this.app.getServersByType('connector'); + console.log('ltc connectors', connectors); + if (!connectors || connectors.length === 0) { + return { + code: 500 + }; + } + // select connector + let res = dispatch(uid, connectors); + return { + code: 200, + host: res.host, + port: res.clientPort + }; + } +} \ No newline at end of file diff --git a/game-server/app/servers/user.rpc.define.ts b/game-server/app/servers/user.rpc.define.ts new file mode 100644 index 000000000..c2f5ddf03 --- /dev/null +++ b/game-server/app/servers/user.rpc.define.ts @@ -0,0 +1,14 @@ + +// 这种 + +// UserRpc的命名空间自动合并 +import { FrontendSession, RemoterClass } from 'pinus'; +import { ChatRemote } from './chat/remote/chatRemote'; + +declare global { + interface UserRpc { + chat: { + chatRemote: RemoterClass; + }; + } +} \ No newline at end of file diff --git a/game-server/app/util/dispatcher.ts b/game-server/app/util/dispatcher.ts new file mode 100644 index 000000000..f3ae88545 --- /dev/null +++ b/game-server/app/util/dispatcher.ts @@ -0,0 +1,7 @@ +import * as crc from 'crc'; +import { ServerInfo } from 'pinus'; + +export function dispatch(uid: string , connectors: ServerInfo[]) { + let index = Math.abs(crc.crc32(uid)) % connectors.length; + return connectors[index]; +} \ No newline at end of file diff --git a/game-server/app/util/routeUtil.ts b/game-server/app/util/routeUtil.ts new file mode 100644 index 000000000..2171f2f22 --- /dev/null +++ b/game-server/app/util/routeUtil.ts @@ -0,0 +1,15 @@ + +import { dispatch} from './dispatcher'; +import { Session, Application } from 'pinus'; + +export function chat(session: Session, msg: any, app: Application, cb: (err: Error , serverId ?: string) => void) { + let chatServers = app.getServersByType('chat'); + + if(!chatServers || chatServers.length === 0) { + cb(new Error('can not find chat servers.')); + return; + } + + let res = dispatch(session.get('rid'), chatServers); + cb(null, res.id); +} \ No newline at end of file diff --git a/game-server/config/adminServer.ts b/game-server/config/adminServer.ts new file mode 100644 index 000000000..6f5511d93 --- /dev/null +++ b/game-server/config/adminServer.ts @@ -0,0 +1,11 @@ +module.exports = [{ + 'type': 'connector', + 'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn' +}, { + 'type': 'chat', + 'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn' +}, { + 'type': 'gate', + 'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn' +} +]; \ No newline at end of file diff --git a/game-server/config/adminUser.ts b/game-server/config/adminUser.ts new file mode 100644 index 000000000..aa06959ae --- /dev/null +++ b/game-server/config/adminUser.ts @@ -0,0 +1,17 @@ +module.exports = [{ + 'id': 'user-1', + 'username': 'admin', + 'password': 'admin', + 'level': 1 +}, { + 'id': 'user-2', + 'username': 'monitor', + 'password': 'monitor', + 'level': 2 +}, { + 'id': 'user-3', + 'username': 'test', + 'password': 'test', + 'level': 2 +} +]; \ No newline at end of file diff --git a/game-server/config/clientProtos.ts b/game-server/config/clientProtos.ts new file mode 100644 index 000000000..262a6d916 --- /dev/null +++ b/game-server/config/clientProtos.ts @@ -0,0 +1,14 @@ +module.exports = { + "chat.chatHandler.send": { + "required string content": 1, + "required string target": 2, + "required string rid": 3, + "required string from": 4, + }, + "chat.chatHandler.send2": { + "required string rid": 1, + "required string content": 2, + "required string from": 3, + "required string target": 4 + }, +}; \ No newline at end of file diff --git a/game-server/config/dictionary.ts b/game-server/config/dictionary.ts new file mode 100644 index 000000000..744c39bc9 --- /dev/null +++ b/game-server/config/dictionary.ts @@ -0,0 +1 @@ +module.exports = []; \ No newline at end of file diff --git a/game-server/config/log4js.ts b/game-server/config/log4js.ts new file mode 100644 index 000000000..88878c40d --- /dev/null +++ b/game-server/config/log4js.ts @@ -0,0 +1,134 @@ +module.exports = { + 'appenders': { + 'console': { + 'type': 'console' + }, + 'con-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/con-log-${opts:serverId}.log', + 'pattern': 'connector', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'rpc-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/rpc-log-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'forward-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/forward-log-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'rpc-debug': { + 'type': 'file', + 'filename': '${opts:base}/logs/rpc-debug-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'crash-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/crash.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'admin-log': { + 'type': 'file', + 'filename': '${opts:base}/logs/admin.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus-admin': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-admin.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + }, + 'pinus-rpc': { + 'type': 'file', + 'filename': '${opts:base}/logs/pinus-rpc-${opts:serverId}.log', + 'maxLogSize': 1048576, + 'layout': { + 'type': 'basic' + }, + 'backups': 5 + } + }, + + 'categories': { + 'default': { + 'appenders': ['console', 'pinus'], + 'level': 'debug' + }, + 'con-log': { + 'appenders': ['con-log'], + 'level': 'debug' + }, + 'rpc-log': { + 'appenders': ['rpc-log'], + 'level': 'debug' + }, + 'forward-log': { + 'appenders': ['forward-log'], + 'level': 'debug' + }, + 'rpc-debug': { + 'appenders': ['rpc-debug'], + 'level': 'debug' + }, + 'crash-log': { + 'appenders': ['crash-log'], + 'level': 'debug' + }, + 'admin-log': { + 'appenders': ['admin-log'], + 'level': 'debug' + }, + 'pinus-admin': { + 'appenders': ['pinus-admin'], + 'level': 'debug' + }, + 'pinus-rpc': { + 'appenders': ['pinus-rpc'], + 'level': 'debug' + }, + + }, + + 'prefix': '${opts:serverId} ', + 'replaceConsole': true, + 'lineDebug': false, + 'errorStack': true +}; diff --git a/game-server/config/log4js.without.logfile.ts b/game-server/config/log4js.without.logfile.ts new file mode 100644 index 000000000..a83c5b3a3 --- /dev/null +++ b/game-server/config/log4js.without.logfile.ts @@ -0,0 +1,30 @@ +// 不写日志文件 示例配置文件。 + +module.exports = { + 'appenders': { + 'displayConsole': { + 'type': 'console' + }, + // "other": { + // "type": "file", + // "filename": "${opts:base}/logs/${opts:serverId}.log", + // "maxLogSize": 1048576, + // "layout": { + // "type": "basic" + // }, + // "backups": 5 + // } + }, + 'categories': { + 'default': { + 'appenders': [ + /*"other",*/'displayConsole' + ], + 'level': 'debug' + } + }, + 'replaceConsole': true, + 'prefix': '${opts:serverId} ', + 'lineDebug': false, + 'errorStack': true +}; diff --git a/game-server/config/master.ts b/game-server/config/master.ts new file mode 100644 index 000000000..54161e9a3 --- /dev/null +++ b/game-server/config/master.ts @@ -0,0 +1,13 @@ +module.exports = { + 'development': { + 'id': 'master-server-1', + 'host': '127.0.0.1', + 'port': 3005 + }, + + 'production': { + 'id': 'master-server-1', + 'host': '127.0.0.1', + 'port': 3005 + } +}; \ No newline at end of file diff --git a/game-server/config/serverProtos.ts b/game-server/config/serverProtos.ts new file mode 100644 index 000000000..c7f88ee88 --- /dev/null +++ b/game-server/config/serverProtos.ts @@ -0,0 +1,7 @@ +module.exports = { + 'onChat': { + 'required string msg': 1, + 'required string from': 2, + 'required string target': 3 + }, +}; diff --git a/game-server/config/servers.ts b/game-server/config/servers.ts new file mode 100644 index 000000000..2b77b189c --- /dev/null +++ b/game-server/config/servers.ts @@ -0,0 +1,45 @@ +module.exports = { + 'development': { + 'connector': [ + { + 'id': 'connector-server-1', + 'host': '127.0.0.1', + 'port': 4050, + 'clientHost': 'pinus_test.trgame.cn', + 'clientPort': 3050, + 'frontend': true, + 'args': '--inspect=10001' + } + ], + 'chat': [ + {'id': 'chat-server-1', 'host': '127.0.0.1', 'port': 6050, 'args': '--inspect=10002'}, + {'id': 'chat-server-2', 'host': '127.0.0.1', 'port': 6051, 'args': '--inspect=10004'}, + {'id': 'chat-server-3', 'host': '127.0.0.1', 'port': 6052, 'args': '--inspect=10005'} + ], + 'gate': [ + { + 'id': 'gate-server-1', + 'host': '127.0.0.1', + 'clientHost': 'pinus_test.trgame.cn', + 'clientPort': 3014, + 'frontend': true, + 'args': '--inspect=10003' + } + ] + }, + 'production': { + 'connector': [ + {'id': 'connector-server-1', 'port': 4050, 'host': 'pinus_test.trgame.cn', 'clientPort': 3050, 'frontend': true}, + {'id': 'connector-server-2', 'port': 4051, 'host': 'pinus_test.trgame.cn', 'clientPort': 3051, 'frontend': true}, + {'id': 'connector-server-3', 'port': 4052, 'host': 'pinus_test.trgame.cn', 'clientPort': 3052, 'frontend': true} + ], + 'chat': [ + {'id': 'chat-server-1', 'host': '127.0.0.1', 'port': 6050}, + {'id': 'chat-server-2', 'host': '127.0.0.1', 'port': 6051}, + {'id': 'chat-server-3', 'host': '127.0.0.1', 'port': 6052} + ], + 'gate': [ + {'id': 'gate-server-1', 'host': '127.0.0.1', 'clientHost': 'pinus_test.trgame.cn', 'clientPort': 3014, 'frontend': true} + ] + } +}; diff --git a/game-server/config/servers_multi_ser.ts b/game-server/config/servers_multi_ser.ts new file mode 100644 index 000000000..c4efa7bd2 --- /dev/null +++ b/game-server/config/servers_multi_ser.ts @@ -0,0 +1,45 @@ +module.exports = { + 'development': { + 'connector': [ + { + 'id': 'connector-server-1', + // 'host': '127.0.0.1', + 'host': '39.101.222.20', + 'port': 4050, + 'clientHost': '39.101.222.20', + 'clientPort': 3050, + 'frontend': true, + 'args': '--inspect=10001' + } + ], + 'chat': [ + {'id': 'chat-server-1', 'host': '39.101.222.20', 'port': 6050, 'args': '--inspect=10002'}, + {'id': 'chat-server-2', 'host': '39.100.68.60', 'port': 6051, 'args': '--inspect=10004'}, + {'id': 'chat-server-3', 'host': '39.100.68.60', 'port': 6052, 'args': '--inspect=10005'} + ], + 'gate': [ + { + 'id': 'gate-server-1', + 'host': '39.101.222.20', + 'clientPort': 3014, + 'frontend': true, + 'args': '--inspect=10003' + } + ] + }, + 'production': { + 'connector': [ + {'id': 'connector-server-1', 'host': '127.0.0.1', 'port': 4050, 'clientPort': 3050, 'frontend': true}, + {'id': 'connector-server-2', 'host': '127.0.0.1', 'port': 4051, 'clientPort': 3051, 'frontend': true}, + {'id': 'connector-server-3', 'host': '127.0.0.1', 'port': 4052, 'clientPort': 3052, 'frontend': true} + ], + 'chat': [ + {'id': 'chat-server-1', 'host': '127.0.0.1', 'port': 6050}, + {'id': 'chat-server-2', 'host': '127.0.0.1', 'port': 6051}, + {'id': 'chat-server-3', 'host': '39.100.68.60', 'port': 6052} + ], + 'gate': [ + {'id': 'gate-server-1', 'host': '127.0.0.1', 'clientPort': 3014, 'frontend': true} + ] + } +}; diff --git a/game-server/docker-compose.yaml b/game-server/docker-compose.yaml new file mode 100644 index 000000000..72d5ba5d9 --- /dev/null +++ b/game-server/docker-compose.yaml @@ -0,0 +1,20 @@ +version: '3' +services: + game-server: + container_name: "zyz_game_server" + build: ../game-server + # depends_on: + # - "mongo" + # - "redis" + volumes: + - "$PWD/../game-server:/game-server" + ports: + - "3050:3050" + - "3051:3051" + - "3052:3052" + - "6050:6050" + - "6051:6051" + - "6052:6052" + - "3014:3014" + + command: sh ./startGameServer.sh #使用 shell脚本启动游戏服务器 diff --git a/game-server/generatePm2Config.js b/game-server/generatePm2Config.js new file mode 100644 index 000000000..57d2df5f5 --- /dev/null +++ b/game-server/generatePm2Config.js @@ -0,0 +1,119 @@ +/** + * Created by superzhan on 2018/3/19. + * + * 根据pomelo 的 servers.json 生成 pm2 启动文件 + */ + +//服务器端 工程代码的目录 +var cwd='/game-server'; + +//项目的运行环境 +var envType= 'production'; + +//配置文件的输出目录 +var outputFilePath = './pomeloPm2Start.json'; + +var masterJsonFile = require('./config/master.ts'); +var serversJosnFile = require('./config/servers.ts'); + +//模板数据 +var processConfigType = { + "name" : "", + "script" : "./dist/app.js", + "args" : [] , + "watch": false, + "out_file": "./logs/app.log", + "error_file": "./logs/err.log", + "cwd": "", + "merge_logs": true, + "exec_mode": "fork_mode", +}; + + +//最后的结果数据 +var resultJson={}; +resultJson.apps=new Array(); + + +var clone = function(origin) { + if(!origin) { + return; + } + var obj = {}; + for(var f in origin) { + obj[f] = origin[f]; + } + return obj; +}; + +// +var masterConfig = masterJsonFile[envType]; +var serversConfig = serversJosnFile[envType]; + +//生成master 的配置 +var pm2Master = clone( processConfigType ); +pm2Master.name="master"; +pm2Master.args = new Array(); +pm2Master.args.push('serverType=master'); +pm2Master.args.push('id='+masterConfig.id); +pm2Master.args.push('host='+masterConfig.host); +pm2Master.args.push('port='+masterConfig.port); +pm2Master.args.push('env='+envType); +pm2Master.args.push('mode=stand-alone'); +pm2Master.cwd= cwd; +pm2Master.out_file = './logs/'+masterConfig.id+"_app.log"; +pm2Master.error_file='./logs/'+masterConfig.id+'_error.log'; +resultJson.apps.push(pm2Master); + +//生成当个服务器的配置 +for(serverType in serversConfig) +{ + var servers = serversConfig[serverType]; + for(var i=0;i= 3.1.0 < 4" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npm.taobao.org/through2/download/through2-2.0.5.tgz?cache=0&sync_timestamp=1593478879807&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fthrough2%2Fdownload%2Fthrough2-2.0.5.tgz", + "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npm.taobao.org/to-array/download/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npm.taobao.org/ts-node/download/ts-node-8.10.2.tgz?cache=0&sync_timestamp=1590685779800&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fts-node%2Fdownload%2Fts-node-8.10.2.tgz", + "integrity": "sha1-7uA3ZGM7EjTd03+NuewQt17H+40=", + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-1.13.0.tgz", + "integrity": "sha1-yIHhPMcBWJTtkUhi0nZDb6mkcEM=", + "dev": true + }, + "tslint": { + "version": "5.20.1", + "resolved": "https://registry.npm.taobao.org/tslint/download/tslint-5.20.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslint%2Fdownload%2Ftslint-5.20.1.tgz", + "integrity": "sha1-5AHortoBUrxE3QfmFANPP4DGe30=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1595168120323&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz", + "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=", + "dev": true + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npm.taobao.org/tsutils/download/tsutils-2.29.0.tgz", + "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npm.taobao.org/typescript/download/typescript-3.9.7.tgz?cache=0&sync_timestamp=1596790269694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftypescript%2Fdownload%2Ftypescript-3.9.7.tgz", + "integrity": "sha1-mNYApevcOPQMsndSLxLcgA6eJfo=", + "dev": true + }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npm.taobao.org/underscore/download/underscore-1.9.1.tgz?cache=0&sync_timestamp=1585605854253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funderscore%2Fdownload%2Funderscore-1.9.1.tgz", + "integrity": "sha1-BtzjSg5op7q8KbNluOdLiSUgOWE=" + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funiversalify%2Fdownload%2Funiversalify-0.1.2.tgz", + "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npm.taobao.org/uuid/download/uuid-3.4.0.tgz?cache=0&sync_timestamp=1592944298186&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.4.0.tgz", + "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=" + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npm.taobao.org/winston/download/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npm.taobao.org/async/download/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npm.taobao.org/colors/download/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + } + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz", + "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "7.3.1", + "resolved": "https://registry.npm.taobao.org/ws/download/ws-7.3.1.tgz?cache=0&sync_timestamp=1593925670988&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-7.3.1.tgz", + "integrity": "sha1-0FR79n985PEqct/jEmLGjX3FUcg=" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz?cache=0&sync_timestamp=1564594177335&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxmlhttprequest-ssl%2Fdownload%2Fxmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz", + "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/y18n/download/y18n-4.0.0.tgz", + "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npm.taobao.org/yargs/download/yargs-15.4.1.tgz", + "integrity": "sha1-DYehbeAa7p2L7Cv7909nhRcw9Pg=", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npm.taobao.org/yargs-parser/download/yargs-parser-18.1.3.tgz?cache=0&sync_timestamp=1595125671180&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs-parser%2Fdownload%2Fyargs-parser-18.1.3.tgz", + "integrity": "sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A=", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/yn/download/yn-3.1.1.tgz", + "integrity": "sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=" + } + } +} diff --git a/game-server/package.json b/game-server/package.json new file mode 100644 index 000000000..83cfa9395 --- /dev/null +++ b/game-server/package.json @@ -0,0 +1,37 @@ +{ + "name": "pinus-sample-websocket-chat-game-server-ts-run", + "version": "1.4.9", + "private": false, + "main": "./dist/app", + "scripts": { + "build": "tsc", + "start": "yarn run build && cd dist && node app", + "dev": "node tsrun.js", + "test": "yarn run build", + "cov": "nyc mocha", + "ci": "yarn run test", + "gen-api-ref": "node ../../../node_modules/typedoc/bin/typedoc --mode file --hideGenerator --excludeExternals --ignoreCompilerErrors --out ../../../run/site/public/api-reference/pinus-loader lib/" + }, + "dependencies": { + "@typegoose/typegoose": "^7.3.0", + "@types/bluebird": "^3.5.19", + "@types/crc": "^3.4.0", + "@types/node": "8.10.54", + "@types/redis": "^2.8.25", + "bluebird": "^3.5.1", + "crc": "^3.5.0", + "mongoose": "^5.9.27", + "pinus": "^1.4.9", + "pinus-robot": "^1.4.9", + "pinus-robot-plugin": "^1.4.9", + "redis": "^3.0.2", + "reflect-metadata": "^0.1.10", + "source-map-support": "^0.5.0", + "ts-node": "^8.2.0" + }, + "devDependencies": { + "@types/mongoose": "^5.7.35", + "tslint": "^5.9.1", + "typescript": "^3.9.7" + } +} diff --git a/game-server/pomeloPm2Start.json b/game-server/pomeloPm2Start.json new file mode 100644 index 000000000..50de1f5f3 --- /dev/null +++ b/game-server/pomeloPm2Start.json @@ -0,0 +1,149 @@ +{ + "apps": [ + { + "name": "master", + "script": "app.ts", + "args": [ + "serverType=master", + "id=master-server-1", + "host=127.0.0.1", + "port=3005", + "env=production", + "mode=stand-alone" + ], + "watch": false, + "out_file": "./logs/master-server-1_app.log", + "error_file": "./logs/master-server-1_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "connector-server-1", + "script": "app.ts", + "args": [ + "env=production", + "id=connector-server-1", + "port=4050", + "host=127.0.0.1", + "serverType=connector", + "frontend=true", + "clientPort=3050" + ], + "watch": false, + "out_file": "./logs/connector-server-1_app.log", + "error_file": "./logs/connector-server-1_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "connector-server-2", + "script": "app.ts", + "args": [ + "env=production", + "id=connector-server-2", + "port=4051", + "host=127.0.0.1", + "serverType=connector", + "frontend=true", + "clientPort=3051" + ], + "watch": false, + "out_file": "./logs/connector-server-2_app.log", + "error_file": "./logs/connector-server-2_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "connector-server-3", + "script": "app.ts", + "args": [ + "env=production", + "id=connector-server-3", + "port=4052", + "host=127.0.0.1", + "serverType=connector", + "frontend=true", + "clientPort=3052" + ], + "watch": false, + "out_file": "./logs/connector-server-3_app.log", + "error_file": "./logs/connector-server-3_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "chat-server-1", + "script": "app.ts", + "args": [ + "env=production", + "id=chat-server-1", + "port=6050", + "host=127.0.0.1", + "serverType=chat" + ], + "watch": false, + "out_file": "./logs/chat-server-1_app.log", + "error_file": "./logs/chat-server-1_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "chat-server-2", + "script": "app.ts", + "args": [ + "env=production", + "id=chat-server-2", + "port=6051", + "host=127.0.0.1", + "serverType=chat" + ], + "watch": false, + "out_file": "./logs/chat-server-2_app.log", + "error_file": "./logs/chat-server-2_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "chat-server-3", + "script": "app.ts", + "args": [ + "env=production", + "id=chat-server-3", + "port=6052", + "host=127.0.0.1", + "serverType=chat" + ], + "watch": false, + "out_file": "./logs/chat-server-3_app.log", + "error_file": "./logs/chat-server-3_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + }, + { + "name": "gate-server-1", + "script": "app.ts", + "args": [ + "env=production", + "id=gate-server-1", + "port=undefined", + "host=127.0.0.1", + "serverType=gate", + "frontend=true", + "clientPort=3014" + ], + "watch": false, + "out_file": "./logs/gate-server-1_app.log", + "error_file": "./logs/gate-server-1_error.log", + "cwd": "/game-server", + "merge_logs": true, + "exec_mode": "fork_mode" + } + ] +} \ No newline at end of file diff --git a/game-server/preload.ts b/game-server/preload.ts new file mode 100644 index 000000000..325856c1c --- /dev/null +++ b/game-server/preload.ts @@ -0,0 +1,40 @@ +import { Promise } from 'bluebird'; +// 支持注解 +import 'reflect-metadata'; +import { pinus } from 'pinus'; + +/** + * 替换全局Promise + * 自动解析sourcemap + * 捕获全局错误 + */ +export function preload() { + // 使用bluebird输出完整的promise调用链 + global.Promise = Promise; + // 开启长堆栈 + Promise.config({ + // Enable warnings + warnings: true, + // Enable long stack traces + longStackTraces: true, + // Enable cancellation + cancellation: true, + // Enable monitoring + monitoring: true + }); + + // 自动解析ts的sourcemap + require('source-map-support').install({ + handleUncaughtExceptions: false + }); + + // 捕获普通异常 + process.on('uncaughtException', function (err) { + console.error(pinus.app.getServerId(), 'uncaughtException Caught exception: ', err); + }); + + // 捕获async异常 + process.on('unhandledRejection', (reason: any, p) => { + console.error(pinus.app.getServerId(), 'Caught Unhandled Rejection at:', p, 'reason:', reason); + }); +} diff --git a/game-server/pushdocker.sh b/game-server/pushdocker.sh new file mode 100755 index 000000000..c66b2a624 --- /dev/null +++ b/game-server/pushdocker.sh @@ -0,0 +1,2 @@ +#!/bin/sh +rsync -av --include '.babelrc' --include '.eslintrc.js' --exclude '.*' --exclude 'node_modules' --exclude 'bower_components' --exclude 'dist' --progress --inplace --no-owner --no-group --rsh='ssh -p22' . root@ltctest:/root/zyz/game-server/ diff --git a/game-server/pushdocker_zyz_test.sh b/game-server/pushdocker_zyz_test.sh new file mode 100755 index 000000000..508cd3e4d --- /dev/null +++ b/game-server/pushdocker_zyz_test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +rsync -av --include '.babelrc' --include '.eslintrc.js' --exclude '.*' --exclude 'node_modules' --exclude 'bower_components' --exclude 'dist' --progress --inplace --no-owner --no-group --rsh='ssh -p22' . root@zyz_test:/root/zyz/game-server/ diff --git a/game-server/robot/robot.ts b/game-server/robot/robot.ts new file mode 100644 index 000000000..19b5a3e59 --- /dev/null +++ b/game-server/robot/robot.ts @@ -0,0 +1,97 @@ + +import { Actor } from 'pinus-robot'; +import { PinusWSClient, PinusWSClientEvent} from 'pinus-robot-plugin'; + + +export class Robot { + constructor(private actor: Actor) { + + } + + openid = String(Math.round(Math.random() * 1000)); + + pinusClient = new PinusWSClient(); + + public connectGate(): void { + + let host = '127.0.0.1'; + let port = '3014'; + this.pinusClient.on(PinusWSClientEvent.EVENT_IO_ERROR, (event) => { + // 错误处理 + console.error('error', event); + }); + this.pinusClient.on(PinusWSClientEvent.EVENT_CLOSE, function(event) { + // 关闭处理 + console.error('close', event); + }); + this.pinusClient.on(PinusWSClientEvent.EVENT_HEART_BEAT_TIMEOUT, function(event) { + // 心跳timeout + console.error('heart beat timeout', event); + }); + this.pinusClient.on(PinusWSClientEvent.EVENT_KICK, function(event) { + // 踢出 + console.error('kick', event); + }); + + // this.actor.emit("incr" , "gateConnReq"); + this.actor.emit('start' , 'gateConn' , this.actor.id); + this.pinusClient.init({ + host: host, + port: port + }, () => { + this.actor.emit('end' , 'gateConn' , this.actor.id); + // 连接成功执行函数 + console.log('gate连接成功'); + + + this.gateQuery(); + }); + } + gateQuery() { + // this.actor.emit("incr" , "gateQueryReq"); + this.actor.emit('start' , 'gateQuery' , this.actor.id); + this.pinusClient.request('gate.gateHandler.queryEntry', {uid: this.openid} , (result: {code: number , host: string , port: number}) => { + // 消息回调 + // console.log("gate返回",JSON.stringify(result)); + this.actor.emit('end' , 'gateQuery' , this.actor.id); + this.pinusClient.disconnect(); + this.connectToConnector(result); + }); + } + + connectToConnector(result: {host: string , port: number}) { + // this.actor.emit("incr" , "loginConnReq"); + this.actor.emit('start' , 'loginConn' , this.actor.id); + this.pinusClient.init({ + host: result.host, + port: result.port + }, () => { + this.actor.emit('end' , 'loginConn' , this.actor.id); + // 连接成功执行函数 + console.log('connector连接成功'); + + this.loginQuery({rid: this.actor.id.toString() , username : this.actor.id.toString()}); + }); + } + + loginQuery(result: {rid: string, username: string}) { + + // this.actor.emit("incr" , "loginQueryReq"); + this.actor.emit('start' , 'loginQuery' , this.actor.id); + this.pinusClient.request('connector.entryHandler.enter', result , (ret: any) => { + // 消息回调 + this.actor.emit('end' , 'loginQuery' , this.actor.id); + console.log('connector返回', JSON.stringify(result)); + + + setTimeout(() => + this.loginQuery(result) , Math.random() * 5000 + 1000); + }); + } +} + +export default function(actor: Actor) { + let client = new Robot(actor); + client.connectGate(); + return client; +} diff --git a/game-server/startGameServer.sh b/game-server/startGameServer.sh new file mode 100644 index 000000000..2cb552a1b --- /dev/null +++ b/game-server/startGameServer.sh @@ -0,0 +1,5 @@ +#/bin/bash +cnpm install -d #安装依赖库 +npm run build +node generatePm2Config.js #使用pm2来做进程管理,生成进程配置文件 +pm2-runtime pomeloPm2Start.json #pm2 启动游戏服务器 diff --git a/game-server/tsconfig.json b/game-server/tsconfig.json new file mode 100644 index 000000000..b9eac9b6d --- /dev/null +++ b/game-server/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + // types option has been previously configured + "types": [ + // add node as an option + "node" + ], + "module": "commonjs", //指定生成哪个模块系统代码 + "target": "es2017", + "lib": [ + "es2015", + "es2016", + "esnext.asynciterable" + ], + "noImplicitAny": false, //暂时关闭在表达式和声明上有隐含的'any'类型时报错。 + "noImplicitThis": true, + "inlineSourceMap": true, //用于debug + + "rootDirs": ["."], //仅用来控制输出的目录结构--outDir。 + "outDir":"./dist", //重定向输出目录。 + "experimentalDecorators":true, + "emitDecoratorMetadata": true, + "moduleResolution": "node", + "watch":false //在监视模式下运行编译器。会监视输出文件,在它们改变时重新编译。 + }, + "include":[ + "./app/**/*.ts", + "./config/**/*.ts", + "./app.ts", + "./preload.ts" + ], + "exclude": [ + "./dist/**/*.*" + ] +} diff --git a/game-server/tsrun.js b/game-server/tsrun.js new file mode 100644 index 000000000..3491e7499 --- /dev/null +++ b/game-server/tsrun.js @@ -0,0 +1,34 @@ +require('ts-node/register'); + +// +// 如果堆栈信息不准确.取消注释下面的代码应该可以解决. +// 参考 ts-node 下错误堆栈问题排查小记: https://zhuanlan.zhihu.com/p/43181384 +// +/* +const sourceMapSupport = require('source-map-support'); +const cacheMap = {}; +const extensions = ['.ts', '.tsx']; + +sourceMapSupport.install({ + environment: 'node', + retrieveFile: function (path) { + // 根据路径找缓存的编译后的代码 + return cacheMap[path]; + } +}); + +extensions.forEach(ext => { + const originalExtension = require.extensions[ext]; + require.extensions[ext] = (module, filePath) => { + const originalCompile = module._compile; + module._compile = function(code, filePath) { + // 缓存编译后的代码 + cacheMap[filePath] = code; + return originalCompile.call(this, code, filePath); + }; + return originalExtension(module, filePath); + }; +}) + + */ +require('./app'); diff --git a/npm-install.bat b/npm-install.bat new file mode 100644 index 000000000..70e10518a --- /dev/null +++ b/npm-install.bat @@ -0,0 +1,4 @@ +::npm-install.bat +@echo off +::install web server dependencies && game server dependencies +cd web-server && npm install -d && cd .. && cd game-server && npm install -d \ No newline at end of file diff --git a/npm-install.sh b/npm-install.sh new file mode 100644 index 000000000..0858be41d --- /dev/null +++ b/npm-install.sh @@ -0,0 +1,5 @@ +cd ./game-server && npm install -d +echo '============ game-server npm installed ============' +cd .. +cd ./web-server && npm install -d +echo '============ web-server npm installed ============'