根据 chat 示例创建 game-server,支持分布式部署、域名访问、数据库连接和基础使用
This commit is contained in:
16
README.md
16
README.md
@@ -1,3 +1,15 @@
|
||||
# zyz_server
|
||||
# 环境搭建
|
||||
- 安装 ts 环境
|
||||
`npm install -g tsc ts-node typescript`
|
||||
- 安装 pinus
|
||||
`npm install -g pinus`
|
||||
|
||||
赵云传服务器
|
||||
# 运行
|
||||
## 简介
|
||||
服务器主要分为游戏服和账号服,游戏服以长连接为主,处理主要的游戏逻辑。账号服以短连接为主,处理账号等功能。
|
||||
|
||||
## 运行游戏服
|
||||
`cd game-server && node tsrun.js`
|
||||
|
||||
## 运行 web-server
|
||||
`cd web-server && node app`
|
||||
9
game-server/Dockerfile
Normal file
9
game-server/Dockerfile
Normal file
@@ -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
|
||||
172
game-server/app.ts
Normal file
172
game-server/app.ts
Normal file
@@ -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();
|
||||
24
game-server/app/db/BaseModel.ts
Normal file
24
game-server/app/db/BaseModel.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { prop, pre } from '@typegoose/typegoose';
|
||||
|
||||
/**
|
||||
* BaseModel
|
||||
*/
|
||||
@pre<BaseModel>('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
|
||||
}
|
||||
45
game-server/app/db/User.ts
Normal file
45
game-server/app/db/User.ts
Normal file
@@ -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);
|
||||
76
game-server/app/servers/chat/handler/chatHandler.ts
Normal file
76
game-server/app/servers/chat/handler/chatHandler.ts
Normal file
@@ -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
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
game-server/app/servers/chat/remote/chatRemote.ts
Normal file
92
game-server/app/servers/chat/remote/chatRemote.ts
Normal file
@@ -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<FrontendSession, ChatRemote>;
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
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);
|
||||
}
|
||||
}
|
||||
63
game-server/app/servers/connector/handler/entryHandler.ts
Normal file
63
game-server/app/servers/connector/handler/entryHandler.ts
Normal file
@@ -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'));
|
||||
}
|
||||
}
|
||||
42
game-server/app/servers/gate/handler/gateHandler.ts
Normal file
42
game-server/app/servers/gate/handler/gateHandler.ts
Normal file
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
14
game-server/app/servers/user.rpc.define.ts
Normal file
14
game-server/app/servers/user.rpc.define.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
// 这种
|
||||
|
||||
// UserRpc的命名空间自动合并
|
||||
import { FrontendSession, RemoterClass } from 'pinus';
|
||||
import { ChatRemote } from './chat/remote/chatRemote';
|
||||
|
||||
declare global {
|
||||
interface UserRpc {
|
||||
chat: {
|
||||
chatRemote: RemoterClass<FrontendSession, ChatRemote>;
|
||||
};
|
||||
}
|
||||
}
|
||||
7
game-server/app/util/dispatcher.ts
Normal file
7
game-server/app/util/dispatcher.ts
Normal file
@@ -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];
|
||||
}
|
||||
15
game-server/app/util/routeUtil.ts
Normal file
15
game-server/app/util/routeUtil.ts
Normal file
@@ -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);
|
||||
}
|
||||
11
game-server/config/adminServer.ts
Normal file
11
game-server/config/adminServer.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
module.exports = [{
|
||||
'type': 'connector',
|
||||
'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn'
|
||||
}, {
|
||||
'type': 'chat',
|
||||
'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn'
|
||||
}, {
|
||||
'type': 'gate',
|
||||
'token': 'agarxhqb98rpajloaxn34ga8xrunpagkjwlaw3ruxnpaagl29w4rxn'
|
||||
}
|
||||
];
|
||||
17
game-server/config/adminUser.ts
Normal file
17
game-server/config/adminUser.ts
Normal file
@@ -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
|
||||
}
|
||||
];
|
||||
14
game-server/config/clientProtos.ts
Normal file
14
game-server/config/clientProtos.ts
Normal file
@@ -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
|
||||
},
|
||||
};
|
||||
1
game-server/config/dictionary.ts
Normal file
1
game-server/config/dictionary.ts
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = [];
|
||||
134
game-server/config/log4js.ts
Normal file
134
game-server/config/log4js.ts
Normal file
@@ -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
|
||||
};
|
||||
30
game-server/config/log4js.without.logfile.ts
Normal file
30
game-server/config/log4js.without.logfile.ts
Normal file
@@ -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
|
||||
};
|
||||
13
game-server/config/master.ts
Normal file
13
game-server/config/master.ts
Normal file
@@ -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
|
||||
}
|
||||
};
|
||||
7
game-server/config/serverProtos.ts
Normal file
7
game-server/config/serverProtos.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
'onChat': {
|
||||
'required string msg': 1,
|
||||
'required string from': 2,
|
||||
'required string target': 3
|
||||
},
|
||||
};
|
||||
45
game-server/config/servers.ts
Normal file
45
game-server/config/servers.ts
Normal file
@@ -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}
|
||||
]
|
||||
}
|
||||
};
|
||||
45
game-server/config/servers_multi_ser.ts
Normal file
45
game-server/config/servers_multi_ser.ts
Normal file
@@ -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}
|
||||
]
|
||||
}
|
||||
};
|
||||
20
game-server/docker-compose.yaml
Normal file
20
game-server/docker-compose.yaml
Normal file
@@ -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脚本启动游戏服务器
|
||||
119
game-server/generatePm2Config.js
Normal file
119
game-server/generatePm2Config.js
Normal file
@@ -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<servers.length;++i)
|
||||
{
|
||||
var singleServer= servers[i];
|
||||
|
||||
var appPm2Config = clone(processConfigType);
|
||||
appPm2Config.name=singleServer.id;
|
||||
appPm2Config.args= new Array();
|
||||
appPm2Config.args.push('env='+envType);
|
||||
appPm2Config.args.push('id='+singleServer.id);
|
||||
appPm2Config.args.push('port='+singleServer.port);
|
||||
appPm2Config.args.push('host='+singleServer.host);
|
||||
appPm2Config.args.push('serverType='+serverType);
|
||||
|
||||
if(singleServer.frontend !=null)
|
||||
{
|
||||
appPm2Config.args.push('frontend='+ singleServer.frontend);
|
||||
appPm2Config.args.push('clientPort='+singleServer.clientPort);
|
||||
}
|
||||
|
||||
appPm2Config.cwd= cwd;
|
||||
appPm2Config.out_file = './logs/'+ singleServer.id+'_app.log';
|
||||
appPm2Config.error_file = './logs/'+singleServer.id+'_error.log';
|
||||
|
||||
resultJson.apps.push(appPm2Config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//生成结果数据
|
||||
var resultFileStr = JSON.stringify(resultJson);
|
||||
//console.log(resultFileStr);
|
||||
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
fs.writeFile(outputFilePath, resultFileStr, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log('finish genereate Server pm2 config');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1726
game-server/package-lock.json
generated
Normal file
1726
game-server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
game-server/package.json
Normal file
37
game-server/package.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
149
game-server/pomeloPm2Start.json
Normal file
149
game-server/pomeloPm2Start.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
40
game-server/preload.ts
Normal file
40
game-server/preload.ts
Normal file
@@ -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);
|
||||
});
|
||||
}
|
||||
2
game-server/pushdocker.sh
Executable file
2
game-server/pushdocker.sh
Executable file
@@ -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/
|
||||
2
game-server/pushdocker_zyz_test.sh
Executable file
2
game-server/pushdocker_zyz_test.sh
Executable file
@@ -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/
|
||||
97
game-server/robot/robot.ts
Normal file
97
game-server/robot/robot.ts
Normal file
@@ -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;
|
||||
}
|
||||
5
game-server/startGameServer.sh
Normal file
5
game-server/startGameServer.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#/bin/bash
|
||||
cnpm install -d #安装依赖库
|
||||
npm run build
|
||||
node generatePm2Config.js #使用pm2来做进程管理,生成进程配置文件
|
||||
pm2-runtime pomeloPm2Start.json #pm2 启动游戏服务器
|
||||
35
game-server/tsconfig.json
Normal file
35
game-server/tsconfig.json
Normal file
@@ -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/**/*.*"
|
||||
]
|
||||
}
|
||||
34
game-server/tsrun.js
Normal file
34
game-server/tsrun.js
Normal file
@@ -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');
|
||||
4
npm-install.bat
Normal file
4
npm-install.bat
Normal file
@@ -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
|
||||
5
npm-install.sh
Normal file
5
npm-install.sh
Normal file
@@ -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 ============'
|
||||
Reference in New Issue
Block a user