gamecloud
Version:
game logic server over cloud
577 lines (513 loc) • 19.2 kB
JavaScript
/**
* bootstrap
*/
let httpProxy = require('http-proxy');
let express = require('express');
let fs = require('fs')
let EventEmitter = require('events').EventEmitter;
EventEmitter.defaultMaxListeners = 0;
//注入通用函数
require('./util/mixin/base');
// Uncaught exception handler
process.on('uncaughtException', function(err) {
console.error(' Caught exceptio n: ' + err.stack);
});
let commonFunc = require('./util/commonFunc');
let getAsnyc = require('./util/async')
let cache = require('./util/cache')
let formula = require('./util/formula')
let Indicator = require('./util/Indicator')
let updateMgr = require('./util/updateMgr')
let Collection = require('./util/Collection')
let config = require('./util/configInterface') //配置文件管理
let {applyMixins, extendObj, clone} = require('./util/mixin/comm')
let filelist = require('./util/filelist')
let iniFile = require(`${process.cwd()}/gameconfig`);
/**
* 门面对象
*/
class Facade
{
/**
* 启动支持反向代理的静态门户网站
* @param {String} options.protocol 协议 http/https
* @param {Object} options.router 路由 {host: {target,}}
* @param {String} options.port 守护端口
*/
static startProxy(options) {
// 新建一个代理 Proxy Server 对象. 常用策略是对外使用https, 映射至内部的http体系
var proxy = httpProxy.createProxyServer({});
proxy.on('error', function (err, req, res) {
// res.writeHead(500, {'Content-Type': 'text/plain'}); //代理有可能传入的是 TLSSocket 而不是 ServerResponse, 所以不能调用 writeHead
res.end('Something went wrong.');
});
proxy.on('proxyReq', function(proxyReq, req, res, options) {
proxyReq.setHeader('Access-Control-Allow-Origin', '*');
proxyReq.setHeader('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
proxyReq.setHeader('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
});
// 在每次请求中,调用 proxy.web(req, res config) 方法进行请求分发
var server = null;
if(options.protocol == 'https') {
// 注意要提前在 /config/cert/ 目录下布置泛域名证书
server = require('https').createServer(
{
key: fs.readFileSync(process.cwd() + '/config/cert/server.key', 'utf8'),
cert: fs.readFileSync(process.cwd() + '/config/cert/server.crt', 'utf8')
},
function(req, res) {
var host = req.headers.host;
if(options.router[host]) {
proxy.web(req, res, { target: options.router[host].target, changeOrigin: true });
} else {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Welcome! visit [wallet.vallnet.cn] for wallet service and [crm.vallnet.cn] for crm service.');
}
}
);
// Listen to the `upgrade` event and proxy the WebSocket requests as well. --TODO 如下ws代理的代码未验证
server.on('upgrade', function (req, socket, head) {
var host = req.headers.host;
if(options.router[host]) {
proxy.ws(req, socket, head, { target: options.router[host].target, changeOrigin: true });
} else {
socket.disconnect();
}
});
} else {
server = require('http').createServer(function(req, res) {
var host = req.headers.host;
if(options.router[host]) {
proxy.web(req, res, { target: options.router[host].target, changeOrigin: true });
} else {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Welcome! visit [wallet.vallnet.cn] for wallet service and [crm.vallnet.cn] for crm service.');
}
});
}
server.listen(options.port);
}
/**
* 添加一个静态内容服务站
* @description 相比通过 facade.boot 传入 static 数组而言,该方法能灵活指定协议、地址和端口
*
* @param {*} protocol 协议 http / https
* @param {*} host 主机地址
* @param {*} port 主机端口
* @param {Object} route 路由设置
*/
static addWebSite(protocol, host, port, route) {
let app = express();
if(Array.isArray(route)) {
route.map(rt => {
if(typeof rt.dir == 'string') {
app.use(rt.path, express.static(rt.dir));
} else if(typeof rt.dir == 'function') {
let router = express.Router();
router.request(path, async (req, res) => {
try {
res.send(await rt.dir(req.query));
} catch(e) {
res.end();
console.error(e);
}
});
app.use("/", router);
}
});
}
let httpObj = require(protocol);
let hrv = httpObj.createServer(app);
hrv.listen(port, host, () => {
console.log(`静态网站服务在 ${protocol}://${host}:${port} 上准备就绪`);
});
}
/**
* 系统主引导流程
* @param {*} env 节点类型参数对象
*/
static async boot(env) {
env = env || {};
//主程序启动,提供包括Http、Socket、路由解析等服务
let core = this.FactoryOfCore({env: env});
if(this.$addition) { //加载用户自定义模块
await core.loadModel();
}
//将用户自定义表添加到自动加载列表中
if(core.DynamicOptions().loading) {
core.DynamicOptions().loading.map(table=>{
core.addLoadingModel(table);
});
}
let app = express();
//启用跨域访问
app.all('*',function (req, res, next) {
// 允许应用的跨域访问
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
if (req.method == 'OPTIONS') {
//让options请求快速返回
res.sendStatus(200);
} else {
next();
}
});
//region 添加POST模式下的body解析器
let bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json());
//endregion
//载入持久化层数据,开放通讯服务端口,加载所有控制器相关的路由、中间件设定
await core.Start(app);
if(core.DynamicOptions().static) {
for(let [route, path] of core.DynamicOptions().static) {
core.addRouter(route, path);
}
}
//如果通过 plugin 机制定义了 startAfter 函数,则在此自动执行
if(typeof core.startAfter == 'function') {
await core.startAfter();
}
//下发404 必须在控制器路由、静态资源路由全部加载之后设定
app.use(function(req, res, next) {
res.status(404).send('Sorry cant find the path!');
});
//捕获并下发错误码 必须放在最后!
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
return core;
}
/**
* 创建核心类实例的类工厂
* @param {*} options.env 运行环境
* @returns {CoreOfBase}
*/
static FactoryOfCore(options) {
if(!this.serverType || !this.serverTypeMapping) {
this.serverType = {};
this.serverTypeMapping = {};
//自动从指定目录载入系统定义和用户自定义的核心类
let corelist = filelist.mapPackagePath(`${__dirname}/./core/`, {filename:'core.js'});
if(this.$addition) {
corelist = corelist.concat(filelist.mapPath('app/core/', {filename:'core.js'}));
}
corelist.map(srv => {
let srvObj = require(srv.path);
this.serverType[srv.cname] = srvObj; //节点类列表
srvObj.mapping.map(key => {
this.serverTypeMapping[key] = srvObj; //节点类映射列表,每个节点类可能映射多个条目
});
});
}
let env = options.env || {};
if(!!this.serverTypeMapping[env.serverType] && !!this.ini.servers[env.serverType] && !!this.ini.servers[env.serverType][env["serverId"]]) {
let ret = new this.serverTypeMapping[env.serverType](this.tools.extend(
{serverType: env.serverType, serverId: env.serverId},
this.ini.servers["CoreOfIndex"][1],
this.ini.servers[env.serverType][env["serverId"]]
));
extendObj(ret.options, options);
return ret;
} else {
throw new Error(`无法识别的服务器类型和编号 ${env.serverType}.${env.serverId}`);
}
}
/**
* 读取加载附加自定义模块标志
*/
static get addition() {
return this.$addition || false;
}
/**
* 设置加载附加自定义模块标志,链式操作
*/
static set addition(val) {
this.$addition = val;
return this;
}
/**
* 建立关键字和核心类之间的映射关系,用于建立核心对象的类工厂中
* @param {Array} pair 形如[keyword, CoreClassName]的数组
*
* @note 核心类的静态mapping方法规定了服务器类型映射关系,但可以随时调用registerServer补充新的映射关系
*/
static registerServer(pair) {
if(!!pair) { //带参数表示补录映射关系
this.serverTypeMapping[pair[0]] = pair[1];
}
}
/**
* 获取当前运行环境的节点对象
*/
static get current(){
return this.$current;
}
/**
* 设置当前运行环境的节点对象
*/
static set current(val){
this.$current = val;
return this.$current;
}
//region 内置的节点类
static get CoreOfBase() {
return require('./core/CoreOfBase/core');
}
static get CoreOfIndex() {
return require('./core/CoreOfIndex/core');
}
static get CoreOfLogic() {
return require('./core/CoreOfLogic/core');
}
//endregion
//region 可用于继承的基础类
/**
* 集合管理类
*/
static get Collection(){
return Collection;
}
/**
* 基础控制器类
*/
static get Control(){
return require('./util/baseCtrl');
}
/**
* 索引服远程控制器类
*/
static get RemoteIndexCtrl() {
return require('./util/indexCtrl');
}
/**
* 逻辑服远程控制器类
*/
static get RemoteLogicCtrl() {
return require('./util/logicCtrl');
}
/**
* 基础服务类
*/
static get Service(){
return require('./util/baseService');
}
/**
* 基础助手类
*/
static get Assistant(){
return require('./util/baseAssistant');
}
/**
* 背包管理基础类
*/
static get Assistants() {
return {
Pocket: require('./core/CoreOfBase/model/assistant/item'),
Action: require('./core/CoreOfBase/model/assistant/action'),
}
}
/**
* 指向原生基础实体类
*/
static get BaseEntity(){
return require('./util/BaseEntity');
}
/**
* 指向原生基础用户类
*/
static get BaseUserEntity() {
return require('./core/CoreOfBase/model/entity/BaseUserEntity');
}
/**
* 指向原生基础联盟类
*/
static get BaseAllyObject() {
return require('./core/CoreOfBase/model/entity/BaseAllyObject');
}
/**
* 指向原生基础日志类
*/
static get BaseLogEntity() {
return require('./core/CoreOfBase/model/entity/BuyLogEntity');
}
//endregion
/**
* 返回全部助手类
*/
static get assistants() {
if(!this.$assistants){
this.$assistants = {};
filelist.mapPackagePath(`${__dirname}/./model/assistant`).map(mod=>{
let mid = mod.name.split('.')[0];
this.$assistants[mid] = require(mod.path);
});
if(this.$addition) {
filelist.mapPath('app/model/assistant').map(mod=>{
let mid = mod.name.split('.')[0];
this.$assistants[mid] = require(mod.path);
});
}
}
return this.$assistants;
}
/**
* 工具箱
*/
static get tools() {
return {
mixin: applyMixins, //混合对象属性函数
extend: extendObj, //扩展对象函数
clone: clone, //深度复刻对象函数
Sequelize: require('sequelize'), //sequelize类
seqconn: require('./util/sequel'), //mysql连接器
maintain: require('./util/maintain'), //执行数据维护任务
formula: formula, //表达式计算
cache: cache, //缓存管理
Indicator: Indicator, //标志位管理
updateMgr: updateMgr, //定时刷新器
getAsnyc: getAsnyc,
Lock: require('./util/Lock')
};
}
/**
* 所有自动化执行类的列表
*/
static get autoExec() {
if(!this.$autoExec){
this.$autoExec = {};
filelist.mapPackagePath(`${__dirname}/./util/autoExec`).map(mod=>{
let mid = mod.name.split('.')[0];
this.$autoExec[mid] = require(mod.path);
});
if(this.$addition) {
filelist.mapPath('app/util/autoExec').map(mod=>{
let mid = mod.name.split('.')[0];
this.$autoExec[mid] = require(mod.path);
});
}
}
return this.$autoExec;
}
/**
* 返回运行环境配置文件
*/
static get ini(){
return iniFile;
}
/**
* 业务配置文件管理
*/
static get config(){
return config;
}
/**
* 获取常用函数集
*/
static get util(){
return commonFunc;
}
/**
* 获取常用枚举集
* @description facade.const 只载入 CoreOfBase/enum 中的常量定义,而 core.const 严格按照原型链顺序载入全部常量定义
*/
static get const() {
if(!this.$constList) {
this.$constList = require('./core/CoreOfBase/enum'); //载入框架定义常量
if(this.$addition) { //载入用户自定义常量,注意先前载入的同名常量会被覆盖
extendObj(this.$constList, require(`${process.cwd()}/app/core/CoreOfBase/enum`));
}
}
return this.$constList;
}
/**
* 添加用户自定义资源类型
* @param {*} num 资源类型数值定义,数值介乎 90000~99999 之间
* @param {*} type 资源类型字符串定义
* @returns {Boolean} 定义是否生效
*/
static addResType(num, type) {
if(num >= 90000 && num <= 99999 && !this.const.ResType[type]) {
this.const.ResType[type] = num;
return true;
}
return false;
}
}
class Util
{
static get BonusObject() {
return require('./util/comm/BonusObject');
}
/**
* 反向代理
*/
static get StartProxy() {
return require('./util/proxy/startproxy');
}
static get ConfigManager() {
return require('./util/potential/ConfigManager');
}
static get PotentialItem() {
return require('./util/potential/PotentialItem');
}
static get ActionOfTimer() {
return require('./util/potential/ActionOfTimer');
}
static get PotentialClientItem() {
return require('./util/potential/PetClientItem');
}
static get CheckValid() {
return require('./util/mixin/CheckValid');
}
static get ConfigMgr() {
let {ConfigMgr} = require('./util/battle/Action');
return ConfigMgr;
}
static get EffectManager() {
return require('./util/comm/EffectManager');
}
static get ChatPrivateManager() {
return require('./util/comm/ChatPrivateManager');
}
static get EffectObject() {
return require('./util/comm/EffectObject');
}
static get TollgateObject() {
return require('./util/tollgate/TollgateObject');
}
static get OperationInfo() {
return require('./util/tollgate/OperationInfo');
}
static get TollgateHangup() {
return require('./util/tollgate/TollgateHangup');
}
static get GateEvent() {
return require('./util/tollgate/GateEvent');
}
static get BattleManager() {
return require('./util/battle/BattleManager');
}
static get BaseBattleParam() {
let {BaseBattleParam} = require('./util/battle/util');
return BaseBattleParam;
}
static get BattleHero() {
let {BattleHero} = require('./util/battle/hero');
return BattleHero;
}
static get TaskObject() {
return require('./util/comm/TaskObject');
}
static get LargeNumberCalculator() {
return require('./util/comm/LargeNumberCalculator');
}
static get EventData() {
let {EventData} = require('./util/comm/EventData');
return EventData;
}
}
Facade.Util = Util;
exports = module.exports = Facade;