gamecloud
Version:
game logic server over cloud
892 lines (793 loc) • 33.3 kB
JavaScript
let express = require('express')
let io = require('socket.io')
let fs = require('fs')
let facade = require('../../Facade')
let extendObj = facade.tools.extend
let {ReturnCode, EntityType, IndexType, CommMode, env} = facade.const
let Control = facade.Control
let connectMonitor = require('../../util/autoExec/connectMonitor')
let AutoTaskManager = require('../../util/taskManager')
let Mapping = require('../../util/mixin/Mapping')
let Ranking = require('../../util/mixin/Ranking')
let ConfigManager = require('../../util/potential/ConfigManager')
let {ConfigMgr} = require('../../util/battle/Action')
/**
* 门面管理类
*
* @noet node.js模块化方案中,交叉引用可能引发问题
* @note 一旦已经赋值了 module.exports 后,继续使用 exports.* 引入其他内容将无效
* @note 类静态函数中可以使用 this,它指向类本身
*/
class CoreOfBase
{
/**
* 构造器,传入外部配置信息
* @param {env} $env
*/
constructor($env) {
//为节点命名,外部不可更改
this.$nodeName = 'base';
this.app = null; //express 对象的缓存
let self = this;
/**
* 证书
*/
this.credentials = {};
//载入控制器
this.$router = {};
let keyName = process.cwd() + '/config/cert/server.key', crtName = process.cwd() + '/config/cert/server.crt';
if(fs.existsSync(keyName) && fs.existsSync(crtName)) {
this.credentials.key = fs.readFileSync(keyName, 'utf8');
this.credentials.cert = fs.readFileSync(crtName, 'utf8');
}
/**
* 所有服务器的配置信息列表
*/
this.serversInfo = require(`${process.cwd()}/gameconfig`).servers;
/**
* 当前服务器的配置信息
*/
this.options = $env;
//中间件配置管理,子类可覆盖, 约定和类名称相同的中间件为鉴权中间件
this.middlewareSetting = {};
this.middlewareSetting.default = ['parseParams', 'auth', 'commonHandle', 'afterHandle'];
//中间件列表
this.middleware = {};
this.service = {};
/**
* Control列表 由子类构造函数载入实际内容
* @type {Array<Control>}
*/
this.control = {};
//系统内部事件映射表,由子类视需要补充加载
this.eventHandleList = {};
//配置表列表
this.fileMap = {};
for(let cls of this.GetInheritArray()) {
//载入控制器(具备文件级可继承特性,继承过程中,低级的同名控制器模块会被高级的覆盖)
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/control`).map(ctrl => {
let ctrlObj = require(ctrl.path);
let token = ctrl.name.split('.')[0];
this.control[token] = new ctrlObj(this);
//读取控制器自带的中间件设置
if(!!this.control[token].middleware) {
this.middlewareSetting[token] = this.control[token].middleware;
}
//读取控制器自带的Url路由设置
if(!!this.control[token].router) {
this.$router[token] = this.control[token].router;
}
});
//载入框架预定义的Service(具备文件级可继承特性,继承过程中,低级的同名服务模块会被高级的覆盖)
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/service`).map(srv => {
let srvObj = require(srv.path);
this.service[srv.name.split('.')[0]] = new srvObj(this);
});
//载入框架规定的中间件(具备文件级可继承特性,继承过程中,低级的同名中间件模块会被高级的覆盖)
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/middleware`).map(srv => {
let handle = require(srv.path).handle;
let handleName = !!srv.cname ? `${srv.cname}.${srv.name.split('.')[0]}` : `${srv.name.split('.')[0]}`;
this.middleware[handleName] = handle;
});
//载入框架预定义的plugin函数(具备函数级可继承特性,继承过程中,低级的同名函数(而不是文件模块)会被高级的覆盖)
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/plugin`).map(srv=>{
let moduleName = srv.name.split('.')[0];
let funcList = require(srv.path);
Object.keys(funcList).map(key => {
if(moduleName == 'default') {
//default.js 中的函数,作为Core的一级属性
this[key] = function(...arg) {
return funcList[key](self, ...arg);
}
} else {
//其余文件模块中的函数,以模块名为一级属性,函数为二级属性
if(!this[moduleName]) {
this[moduleName] = {};
}
this[moduleName][key] = function(...arg) {
return funcList[key](self, ...arg);
}
}
});
});
//载入框架规范的逻辑事件
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/events`).map(srv=>{
let handle = require(srv.path).handle;
let handleName = !!srv.cname ? `${srv.cname}.${srv.name.split('.')[0]}` : `${srv.name.split('.')[0]}`;
this.eventHandleList[handleName] = handle.bind(this);
});
//载入配置表文件, 可继承
for(let fl of facade.config.filelist.mapPath(`config/data`)) {
let id = fl.name.split('.')[0];
this.fileMap[id] = facade.config.ini.get(fl.path).GetInfo();
}
}
//定时任务管理器
this.autoTaskMgr = new AutoTaskManager(this);
this.potentialConfig = new ConfigManager(this);
this.TaskStaticList = {};
//战斗配置管理
this.ConfigMgr = new ConfigMgr(this);
//映射门面对象,方便在this指针指向FacadeOfBase实例的环境内快速调用
this.facade = facade;
//初始载入的数据库表列表
this.loadingList = [];
//特殊资源处理登记 - 并非存储于背包中的普通物品
this.specialRes = {};
this.RegisterResHandle('$default', async (user, bonus) => {
});
}
/**
* 登记特殊资源处理句柄
* @param {*} type 资源类型
* @param {Function} handle 处理句柄 (user, bonus) => {}
*/
RegisterResHandle(type, handle) {
this.specialRes[type] = handle;
}
/**
* 获取常用枚举集
*/
get const() {
if(!this.$constList) {
this.$constList = {};
for(let cls of this.GetInheritArray()) {
try {
let en = require(`../${cls}/enum`);
if(!!en) {
extendObj(this.$constList, en);
}
} catch(e) { }
if(facade.$addition) {
try {
let en = require(`${process.cwd()}/app/core/${cls}/enum`);
if(!!en) {
extendObj(this.$constList, en);
}
} catch(e) { }
}
}
}
return this.$constList;
}
/**
* 返回全部表映射类
*/
get models() {
if(!this.$models){
this.$models = {};
for(let cls of this.GetInheritArray()) {
//载入全部ORM模块
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/model/table`).map(mod=>{
let mid = mod.name.split('.')[0];
this.$models[mid] = require(mod.path)[mid];
});
if(facade.$addition) {
facade.config.filelist.mapPath(`app/core/${cls}/model/table`).map(mod=>{
let mid = mod.name.split('.')[0];
this.$models[mid] = require(mod.path)[mid];
});
}
}
}
return this.$models;
}
/**
* 返回全部 ORM 映射类
*/
get entities() {
if(!this.$entities) {
this.$entities = {};
//将 UserEntity AllyObject 也指向原生模块
this.$entities.UserEntity = require('./model/entity/BaseUserEntity'); //指向原生定义的角色类
this.$entities.AllyObject = require('./model/entity/BaseAllyObject'); //指向原生定义的联盟类
for(let cls of this.GetInheritArray()) {
//载入原生Entity模块
facade.config.filelist.mapPackagePath(`${__dirname}/../${cls}/model/entity`).map(mod=>{
let mid = mod.name.split('.')[0];
this.$entities[mid] = require(mod.path);
});
if(facade.$addition) {
//载入用户自定义Entity模块,如果用户有重载 UserEntity AllyObject 则自动覆盖之前的设置
facade.config.filelist.mapPath(`app/core/${cls}/model/entity`).map(mod=>{
let mid = mod.name.split('.')[0];
this.$entities[mid] = require(mod.path);
});
}
}
}
return this.$entities;
}
/**
* 添加路由: 静态型或函数型
* @param {String} path 路由的路径
* @param {Function} func 资源路径或者路由处理句柄 data => {}
*/
addRouter(path, func) {
if(!this.app) {
return;
}
if(typeof func == 'string') {
this.app.use(path, express.static(func));
} else if(typeof func == 'function') {
let router = express.Router();
router.get(path, async (req, res) => {
try {
res.send(await (func.bind(this))(req.query));
} catch(e) {
res.end();
console.error(e);
}
});
router.post(path, async (req, res) => {
try {
res.send(await (func.bind(this))(req.query));
} catch(e) {
res.end();
console.error(e);
}
});
this.app.use("/", router);
}
}
/**
* 添加启动阶段载入的模型
* @param {*} ty 模型的类型
*/
addLoadingModel(ty) {
this.loadingList.push(ty);
}
/**
* 映射自己的服务器类型数组,提供给核心类的类工厂使用
* @returns {Array}
*/
static get mapping() {
return [];
}
/**
* 查询并返回实体对象
* @param {*} etype 实体对象的类型
* @param {*} index 索引值
* @param {*} itype 索引类型
*/
GetObject(etype, index, itype = facade.const.IndexType.Primary){
return this.GetMapping(etype).GetObject(index, itype);
}
/**
* 处理特殊奖励
* @param {*} user
* @param {*} bonus
*/
handleSpecialRes(user, bonus) {
if(this.specialRes[bonus.type]) {
this.specialRes[bonus.type](user, bonus).catch(e=>{
console.log(e);
});
} else {
this.specialRes['$default'](user, bonus).catch(e=>{
console.log(e);
});
}
}
/**
* 获取实体对象的集合映射体
* @param {*} etype 实体对象的类型
* @return {Mapping}
*/
GetMapping(etype) {
if(!this.muster) {
this.muster = {};
Object.keys(this.entities).map(key => {
let entity = this.entities[key];
this.muster[entity.mapParams.etype] = Mapping.muster(entity, this);
});
}
return this.muster[etype];
}
/**
* 获取类/对象的排序管理器
* @param {*} obj 代表排序集合的类/对象
* @return {Ranking}
*/
GetRanking(obj){
if(!this.rankMuster){
this.rankMuster = {};
}
if(!this.rankMuster[obj]) {
this.rankMuster[obj] = Ranking.muster(obj);
}
return this.rankMuster[obj];
}
/**
* 获取类/对象的排序结果
* @param {*} obj 代表排序集合的类/对象
* @param {*} id 标识集合中对象的索引值
* @param {*} type 排序类别
*/
GetRankInfo(obj, id, type){
return this.GetRanking(obj).result(id, type);
}
/**
* 返回描述类继承关系的数组,以基类为首个元素
*/
GetInheritArray() {
let proto = this.__proto__, clsInherit = [];
while(proto) {
clsInherit.push(proto.constructor.name);
if(proto.constructor.name == 'CoreOfBase') { //处理到基类,停止迭代
break;
}
proto = proto.__proto__;
}
return clsInherit.reverse();
}
/**
* 加载用户自定义模块
*/
async loadModel() {
let self = this;
//遍历静态配置表,载入全部任务
this.TaskStaticList = {};
//战斗配置管理
this.ConfigMgr = new ConfigMgr(this);
/**
* 角色升级配置表
*/
this.upgradeChip = {1: Math.ceil(this.fileMap.constdata.getRoleNum.num)};
for(let cls of this.GetInheritArray()) {
//载入用户自定义的全局扩展服务对象
facade.config.filelist.mapPath(`app/core/${cls}/service`).map(srv=>{
let srvObj = require(srv.path);
this.service[srv.name.split('.')[0]] = new srvObj(this);
});
//挂载用户自定义的plugin函数到核心类
facade.config.filelist.mapPath(`app/core/${cls}/plugin`).map(srv=>{
let funcList = require(srv.path);
let moduleName = srv.name.split('.')[0];
Object.keys(funcList).map(key=>{
if(moduleName == 'default') {
this[key] = function(...arg){
return funcList[key](self, ...arg);
}
} else {
if(!this[moduleName]){
this[moduleName] = {};
}
this[moduleName][key] = function(...arg){
return funcList[key](self, ...arg);
}
}
});
});
//载入各自独立的控制器
facade.config.filelist.mapPath(`app/core/${cls}/control`).map(ctrl => {
let ctrlObj = require(ctrl.path);
let token = ctrl.name.split('.')[0];
this.control[token] = new ctrlObj(this);
//读取控制器自带的中间件设置
if(!!this.control[token].middleware){
this.middlewareSetting[token] = this.control[token].middleware;
}
//读取控制器自带的Url路由设置
if(!!this.control[token].router){
this.$router[token] = this.control[token].router;
}
});
//载入用户自定义中间件,@note:将覆盖同名系统中间件
facade.config.filelist.mapPath(`app/core/${cls}/middleware`).map(srv => {
let handle = require(srv.path).handle;
let handleName = !!srv.cname ? `${srv.cname}.${srv.name.split('.')[0]}` : `${srv.name.split('.')[0]}`;
this.middleware[handleName] = handle;
});
//载入用户自定义的逻辑事件
facade.config.filelist.mapPath(`app/core/${cls}/events`).map(srv=>{
let handle = require(srv.path).handle;
let handleName = !!srv.cname ? `${srv.cname}.${srv.name.split('.')[0]}` : `${srv.name.split('.')[0]}`;
this.eventHandleList[handleName] = handle.bind(this);
});
//载入用户自定义配置文件
for(let fl of facade.config.filelist.mapPath(`config/${cls}`)) {
let id = fl.name.split('.')[0];
this.fileMap[id] = facade.config.ini.get(fl.path).GetInfo();
}
}
}
/**
* 自启函数,子类可继承
* 绑定Http Server服务,将对index.html的访问映射到Control
* @param {*} app Http Server对象
*/
async Start(app) {
this.app = app;
//加载路由配置
Object.keys(this.$router).map(id=>{
app.use("/", this.makeRouter(id, this.$router[id]));
});
app.get('/index.html', async (req, res) => {
console.log(`来访URL(${Date()}):${JSON.stringify(req.query)}`);
let _socket = {};
try{
_socket.user = await this.GetObject(EntityType.User, req.query.oemInfo.token, IndexType.Token);
//提取客户端IP信息
req.query.userip = req.ip.match(/\d+.\d+.\d+.\d+/)[0];
let ini = {socket:_socket, msg: req.query, fn: res.send.bind(res), recy:true, facade: this};
let middles = (req.query.control && !!this.middlewareSetting[req.query.control]) ? this.middlewareSetting[req.query.control] : this.middlewareSetting["default"];
if(!!middles){
for(let func of middles){
if(ini.recy && this.middleware[func]){
await this.middleware[func](ini);
}
}
}
else{
res.end();
}
}catch(e){
res.end();
}
});
app.post('/index.html', async (req, res) => {
console.log(`来访URL(${Date()}):${JSON.stringify(req.body)}`);
let _socket = {};
try{
_socket.user = await this.GetObject(EntityType.User, req.body.oemInfo.token, IndexType.Token);
//提取客户端IP信息
req.body.userip = req.ip.match(/\d+.\d+.\d+.\d+/)[0];
let ini = {socket:_socket, msg: req.body, fn: res.send.bind(res), recy:true, facade: this};
let middles = (req.body.control && !!this.middlewareSetting[req.body.control]) ? this.middlewareSetting[req.body.control] : this.middlewareSetting["default"];
if(!!middles){
for(let func of middles){
if(ini.recy && this.middleware[func]){
await this.middleware[func](ini);
}
}
}
else{
res.end();
}
}catch(e){
res.end();
}
});
}
/**
* 生成路由对象
* @param {*} control 指定映射的控制器名称
* @param {Array} config 路由配置数组 [[path, func]]
*/
makeRouter(control, config){
let router = express.Router();
config.map(item=>{
router.get(item[0], async (req, res) => {
try {
//配置型路由不能自动注入用户对象,这类路由的处理句柄是 async data => {params} 而非普通控制器方法的 async (user, data) => {}
let ret = await this.callFunc(control, item[1], Object.assign({req:req, res:res}, req.query||{}, req.params||{}, req.body||{}));
res.send(ret);
} catch(e) {
console.error(e);
res.end();
}
});
router.post(item[0], async (req, res) => {
try{
//配置型路由不能自动注入用户对象,这类路由的处理句柄是 async data => {params} 而非普通控制器方法的 async (user, data) => {}
let ret = await this.callFunc(control, item[1], Object.assign({req:req, res:res}, req.query||{}, req.params||{}, req.body||{}));
res.send(ret);
}
catch(e){
console.error(e);
res.end();
}
});
});
return router;
}
/**
* 利用反射机制,调用相应的控制器方法
* @param ctrl 控制器名称
* @param type 控制器内部函数名
* @param user 来访者实体对象
* @param objData 参数对象
* @returns {Promise.<*>}
*/
async callFunc(ctrl, type, user, objData){
try{
if(this.control.hasOwnProperty(ctrl)) {
if(this.control[ctrl].__proto__.hasOwnProperty(type)
|| this.control[ctrl].hasOwnProperty(type)
|| (typeof this.control[ctrl][type] === 'function')) {
return await this.control[ctrl][type](user, objData);
}
}
}
catch(e){
console.error(e);
}
return {code: ReturnCode.Error};
}
/**
* 创建WS类型的Socket服务
* @param app
*/
StartSocketServer(app){
let httpObj = require(this.options.UrlHead);
httpObj.globalAgent.maxSockets = Infinity;
let hrv = this.options.UrlHead == "https" ?
httpObj.createServer(this.credentials, app) :
httpObj.createServer(app);
//启动网络服务
this.numOfOnline = 0;
hrv.listen(this.options.webserver.port, this.options.webserver.host, () => {
console.log(`网络服务在端口 ${this.options.webserver.port} 上准备就绪`);
//在既有http服务的基础上,创建WebSocket服务
this.service.io = io(hrv);
this.service.server = this.service.io.on('connection', socket => {
if(this.numOfOnline > this.options.MaxConnection){//限制最大连接数
socket.disconnect();
return;
}
socket.commMode = CommMode.ws;
socket.once('disconnect', () => {//断线处理
socket.removeAllListeners();
if(!!socket.user){
try{
this.notifyEvent('user.afterLogout', {user:socket.user});
}
finally{
socket.user.socket = null;
socket.user = null;
}
}
});
socket.on('req', (msg, fn) => {//JSONP请求
if(!!msg.url) {//Restfu形式的请求, 要对参数数组进行转化
function UrltoParams(url){
let tmp = url.split('?');
if(tmp.length>1){
let array = tmp[1].split('&');
return array.reduce((sofar, cur)=>{
let param = cur.split('=');
if(param.length>1 && !!param[1]){
sofar[param[0]] = param[1];
}
return sofar;
}, {});
}
}
let params = UrltoParams(msg.url);
params.url = msg.url;
//params.oemInfo = {openid:params.sessionid, domain:params.domain, token:params.token};
params.oemInfo = {openid:params.sessionid||"18681223392", domain:params.domain||"official"};
params.control = `P${params.act}`;
if(!params.func){
params.func = 'Execute'; //设置默认的入口函数名
}
msg = params;
}
msg.userip = socket.request.connection.remoteAddress; //记录客户端IP
if(this.options.debug){
console.dir(msg); //打印上行参数
}
this.onSocketReq(socket, msg, fn).then(()=>{}).catch(e=>{console.log(e);});
});
socket.on('notify', (msg) => {//客户端通知消息
msg.userip = socket.request.connection.remoteAddress; //记录客户端IP
this.onSocketReq(socket, msg, null).then(()=>{}).catch(e=>{console.log(e);});
});
});
});
//网络连接监控
this.autoTaskMgr.addMonitor(new connectMonitor());
//排行榜监控
this.autoTaskMgr.addCommonMonitor(this.GetRanking(this.entities.UserEntity));
}
/**
* 指定类型的服务器数量
* @param {*} stype
*/
serverNum(stype){
if(!!this.serversInfo[stype]){
return Object.keys(this.serversInfo[stype]).length;
}
return 0;
}
/**
* 触发内部自定义事件
* @param {*} ev
* @param {*} data
* @returns {Object} {code, data}
*/
async notifyEvent(ev, data) {
let func = this.eventHandleList[ev];
if(!!func) {
try {
return await func(data);
} catch(e) {
return Promise.reject(e);
}
}
return {code:0};
}
/**
* 检测密码是否有效
* @param id
* @param token
* @returns {boolean}
*/
checkMobileToken(id, token){
return this.options.admin.role.default == token;
}
/**
* 认证或生成新的session
* @param id 手机号
* @param key 验证码或密码
* @param session 先前生成的session
*/
registerSession(id, key, session){
if(!this.mobileSessions){
this.mobileSessions = {};
}
if(!!session && !!this.mobileSessions[session]
&& ((facade.util.now() - this.mobileSessions[session].time) < this.options.auth.sessionExp)
&& (this.mobileSessions[session].session == session)
){
return this.mobileSessions[session]; //返回session
}
else{
//如果session不存在,或者已经超过有效期,开始检测验证码或者密码
if(this.options.debug || (this.checkMobileToken(id, key))){
session = facade.util.sign({id:id, key:key},this.options.game_secret);
let ret = {
openid:id,
openkey:key,
session: session,
time: facade.util.now()
};
//注册新的session
this.mobileSessions[session] = ret;
return ret;
}
else{
return null;
}
}
}
/**
* Socket报文处理句柄
* @param socket 通讯管理器
* @param msg 收到的消息
* @param fn 回调函数
* @returns {Promise.<void>}
*/
async onSocketReq(socket, msg, fn){
fn = fn || (()=>{});
msg = msg || {};
if(!socket.user && !!msg.oemInfo && !!msg.oemInfo.token){
//根据用户上行的token进行预登录
socket.user = this.GetObject(EntityType.User, msg.oemInfo.token, IndexType.Token)
}
let ini = {socket:socket, msg:msg, fn:fn, recy:true, facade: this};
let middles = (!!msg.control && !!this.middlewareSetting[msg.control]) ? this.middlewareSetting[msg.control] : this.middlewareSetting["default"];
if(!!middles){
for(let func of middles){
if(ini.recy && this.middleware[func]){
try {
await this.middleware[func](ini);
}
catch(e) {
console.error(e);
}
}
}
}
else{
fn({ code: ReturnCode.routerFailed });
}
}
/**
* 遍历在线用户
* @param cb
*/
forAll(cb){
Object.keys(this.service.server.connected).map(it=>{
if(!!this.service.server.connected[it].user){
cb(this.service.server.connected[it].user);
}
});
}
/**
* 远程调用服务类方法
* @param {*} $func
* @param {*} $params
* @param {*} $cb
*/
async remoteService($func, $params, $cb) {
$cb = $cb || (msg => { return msg; });
return await this.remoteCall('service', {func: $func, msg: $params}, $cb);
}
/**
* 从一个逻辑节点,远程调用另一个逻辑节点的控制器方法
* @param {*} $func
* @param {*} $params
* @param {*} $si
* @param {*} $cb
*/
async remoteLogic($func, $params, $si, $cb) {
$cb = $cb || (msg => { return msg; });
return await this.remoteCall('routeCommand', {func: $func, msg: $params, si: $si}, $cb);
}
/**
* 远程调用控制器方法,支持req和notify两种方式
* @param $func //远程函数名称
* @param $params //参数数组
* @param $cb //回调,为空则表示notify
* @param si //服务器类型、编号, 逻辑服到索引服不需填写
* @returns {Promise.<{code: number}>}
*/
async remoteCall($func, $params, $cb, si) {
$params = $params || {};
$func = $func.split('.');
let attr = {
msg: $params,
};
attr.control = 'remote'; //锁定只能访问 remote 控制器
if($func.length >=2) {
attr.func = $func[1];
} else {
attr.func = $func[0];
}
let connector = null;
if(this.options.serverType == 'Index') {
let svr = this.service.servers.getServer(si.stype, si.sid);
if(!!svr){
connector = svr.socket;
}
} else {
if(!this.remoting.user) { //尚未登录,补充登录信息
attr.oemInfo = {openid:"system", openkey: this.options.admin.role.system};
attr.stype = this.options.serverType;
attr.sid = this.options.serverId;
}
connector = this.remoting;
}
if(!!connector) {
if(!!$cb) {
let ret = await new Promise(resolve => {
connector.emit('req', attr, msg=>{
resolve(msg);
});
});
return $cb(ret);
} else {
connector.emit('notify', attr);
}
}
}
}
/**
* 关于exports和module.exports的释义:
* 初始时,module.exports = exports = {}; 真正的接口是 module.exports, exports只是辅助性的,直白点,就是个备胎
* module.exports 没有被修改,则 exports与module.exports还是引用同一个对象,
* 如果module.exports 被改变,则module.exports 与 exports已经不是一条心了,任你exports怎么改,跟module.exports有什么关系呢
*/
exports = module.exports = CoreOfBase;