omelop
Version:
[](https://travis-ci.org/node-omelop/omelop)
889 lines • 53.5 kB
JavaScript
"use strict";
/*!
* Omelop -- proto
* Copyright(c) 2012 xiechengchao <xiecc@163.com>
* MIT Licensed
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Application = void 0;
/**
* Module dependencies.
*/
const utils = require("./util/utils");
const omelop_logger_1 = require("omelop-logger");
const events_1 = require("events");
const events_2 = require("./util/events");
const appUtil = require("./util/appUtil");
const Constants = require("./util/constants");
const appManager = require("./common/manager/appManager");
const fs = require("fs");
const path = require("path");
const util_1 = require("util");
let logger = (0, omelop_logger_1.getLogger)('omelop', path.basename(__filename));
/**
* Application states
*/
let STATE_INITED = 1; // app has inited
let STATE_BEFORE_START = 2; // app before start
let STATE_START = 3; // app start
let STATE_STARTED = 4; // app has started
let STATE_STOPED = 5; // app has stoped
class Application {
constructor() {
this.loaded = []; // loaded component list
this.components = {}; // name -> component map
this.settings = {}; // collection keep set/get
this.event = new events_1.EventEmitter(); // event object to sub/pub events
// global server infos
this.master = null; // master server info
this.servers = {}; // current global server info maps, id -> info
this.serverTypeMaps = {}; // current global type maps, type -> [info]
this.serverTypes = []; // current global server type list
this.usedPlugins = []; // current server custom lifecycle callbacks
this.clusterSeq = {}; // cluster id seqence
this.astart = utils.promisify(this.start);
this.aconfigure = utils.promisify(this.configure);
}
/**
* Initialize the server.
*
* - setup default configuration
*/
init(opts) {
opts = opts || {};
let base = opts.base || path.dirname(require.main.filename);
this.set(Constants.RESERVED.BASE, base);
this.base = base;
appUtil.defaultConfiguration(this);
this.state = STATE_INITED;
logger.info('application inited: %j', this.getServerId());
}
/**
* Get application base path
*
* // cwd: /home/game/
* omelop start
* // app.getBase() -> /home/game
*
* @return {String} application base path
*
* @memberOf Application
*/
getBase() {
return this.get(Constants.RESERVED.BASE);
}
/**
* Override require method in application
*
* @param {String} relative path of file
*
* @memberOf Application
*/
require(ph) {
return require(path.join(this.getBase(), ph));
}
/**
* Configure logger with {$base}/config/log4js.json
*
* @param {Object} logger omelop-logger instance without configuration
*
* @memberOf Application
*/
configureLogger(logger) {
if (process.env.POMELO_LOGGER !== 'off') {
let serverId = this.getServerId();
let base = this.getBase();
let env = this.get(Constants.RESERVED.ENV);
let originPath = path.join(base, Constants.FILEPATH.LOG);
let presentPath = path.join(base, Constants.FILEPATH.CONFIG_DIR, env, path.basename(Constants.FILEPATH.LOG));
if (this._checkCanRequire(originPath)) {
logger.configure(originPath, { serverId: serverId, base: base });
}
else if (this._checkCanRequire(presentPath)) {
logger.configure(presentPath, { serverId: serverId, base: base });
}
else {
console.error('logger file path configuration is error.');
}
}
}
/**
* add a filter to before and after filter
*
* @param {Object} filter provide before and after filter method.
* A filter should have two methods: before and after.
* @memberOf Application
*/
filter(filter) {
this.before(filter);
this.after(filter);
}
/**
* Add before filter.
*
* @param {Object|Function} bf before fileter, bf(msg, session, next)
* @memberOf Application
*/
before(bf) {
addFilter(this, Constants.KEYWORDS.BEFORE_FILTER, bf);
}
/**
* Add after filter.
*
* @param {Object|Function} af after filter, `af(err, msg, session, resp, next)`
* @memberOf Application
*/
after(af) {
addFilter(this, Constants.KEYWORDS.AFTER_FILTER, af);
}
/**
* add a global filter to before and after global filter
*
* @param {Object} filter provide before and after filter method.
* A filter should have two methods: before and after.
* @memberOf Application
*/
globalFilter(filter) {
this.globalBefore(filter);
this.globalAfter(filter);
}
/**
* Add global before filter.
*
* @param {Object|Function} bf before fileter, bf(msg, session, next)
* @memberOf Application
*/
globalBefore(bf) {
addFilter(this, Constants.KEYWORDS.GLOBAL_BEFORE_FILTER, bf);
}
/**
* Add global after filter.
*
* @param {Object|Function} af after filter, `af(err, msg, session, resp, next)`
* @memberOf Application
*/
globalAfter(af) {
addFilter(this, Constants.KEYWORDS.GLOBAL_AFTER_FILTER, af);
}
/**
* Add rpc before filter.
*
* @param {Object|Function} bf before fileter, bf(serverId, msg, opts, next)
* @memberOf Application
*/
rpcBefore(bf) {
addFilter(this, Constants.KEYWORDS.RPC_BEFORE_FILTER, bf);
}
/**
* Add rpc after filter.
*
* @param {Object|Function} af after filter, `af(serverId, msg, opts, next)`
* @memberOf Application
*/
rpcAfter(af) {
addFilter(this, Constants.KEYWORDS.RPC_AFTER_FILTER, af);
}
/**
* add a rpc filter to before and after rpc filter
*
* @param {Object} filter provide before and after filter method.
* A filter should have two methods: before and after.
* @memberOf Application
*/
rpcFilter(filter) {
this.rpcBefore(filter);
this.rpcAfter(filter);
}
load(name, component, opts) {
if (typeof name !== 'string') {
opts = component;
component = name;
name = null;
}
if ((0, util_1.isFunction)(component)) {
component = new component(this, opts);
}
if (!name && typeof component.name === 'string') {
name = component.name;
}
if (name && this.components[name]) {
// ignore duplicat component
logger.warn('ignore duplicate component: %j', name);
return;
}
this.loaded.push(component);
if (name) {
// components with a name would get by name throught app.components later.
this.components[name] = component;
}
return component;
}
_checkCanRequire(path) {
try {
path = require.resolve(path);
}
catch (err) {
return null;
}
return path;
}
/**
* Load Configure json file to settings.(support different enviroment directory & compatible for old path)
*
* @param {String} key environment key
* @param {String} val environment value
* @param {Boolean} reload whether reload after change default false
* @return {Server|Mixed} for chaining, or the setting value
* @memberOf Application
*/
loadConfigBaseApp(key, val, reload = false) {
let self = this;
let env = this.get(Constants.RESERVED.ENV);
let originPath = path.join(this.getBase(), val);
let presentPath = path.join(this.getBase(), Constants.FILEPATH.CONFIG_DIR, env, path.basename(val));
let realPath;
let tmp;
if (self._checkCanRequire(originPath)) {
realPath = require.resolve(originPath);
let file = require(originPath);
if (file[env]) {
file = file[env];
}
this.set(key, file);
}
else if (self._checkCanRequire(presentPath)) {
realPath = require.resolve(presentPath);
let pfile = require(presentPath);
this.set(key, pfile);
}
else {
logger.error('invalid configuration with file path: %s', key);
}
if (!!realPath && !!reload) {
const watcher = fs.watch(realPath, function (event, filename) {
if (event === 'change') {
self.clearRequireCache(require.resolve(realPath));
watcher.close();
self.loadConfigBaseApp(key, val, reload);
}
});
}
}
clearRequireCache(path) {
const moduleObj = require.cache[path];
if (!moduleObj) {
logger.warn('can not find module of truepath', path);
return;
}
if (moduleObj.parent) {
// console.log('has parent ',moduleObj.parent);
moduleObj.parent.children.splice(moduleObj.parent.children.indexOf(moduleObj), 1);
}
delete require.cache[path];
}
/**
* Load Configure json file to settings.
*
* @param {String} key environment key
* @param {String} val environment value
* @return {Server|Mixed} for chaining, or the setting value
* @memberOf Application
*/
loadConfig(key, val) {
let env = this.get(Constants.RESERVED.ENV);
let cfg = require(val);
if (cfg[env]) {
cfg = cfg[env];
}
this.set(key, cfg);
}
/**
* Set the route function for the specified server type.
*
* Examples:
*
* app.route('area', routeFunc);
*
* let routeFunc = function(session, msg, app, cb) {
* // all request to area would be route to the first area server
* let areas = app.getServersByType('area');
* cb(null, areas[0].id);
* };
*
* @param {String} serverType server type string
* @param {Function} routeFunc route function. routeFunc(session, msg, app, cb)
* @return {Object} current application instance for chain invoking
* @memberOf Application
*/
route(serverType, routeFunc) {
let routes = this.get(Constants.KEYWORDS.ROUTE);
if (!routes) {
routes = {};
this.set(Constants.KEYWORDS.ROUTE, routes);
}
routes[serverType] = routeFunc;
return this;
}
/**
* Set before stop function. It would perform before servers stop.
*
* @param {Function} fun before close function
* @return {Void}
* @memberOf Application
*/
beforeStopHook(fun) {
logger.warn('this method was deprecated in omelop 0.8');
if (!!fun && typeof fun === 'function') {
this.set(Constants.KEYWORDS.BEFORE_STOP_HOOK, fun);
}
}
/**
* Start application. It would load the default components and start all the loaded components.
*
* @param {Function} cb callback function
* @memberOf Application
*/
start(cb) {
this.startTime = Date.now();
if (this.state > STATE_INITED) {
utils.invokeCallback(cb, new Error('application has already start.'));
return;
}
let self = this;
appUtil.startByType(self, function () {
appUtil.loadDefaultComponents(self);
let startUp = function () {
self.state = STATE_BEFORE_START;
logger.info('%j enter before start...', self.getServerId());
appUtil.optComponents(self.loaded, Constants.RESERVED.BEFORE_START, function (err) {
if (err) {
utils.invokeCallback(cb, err);
}
else {
logger.info('%j enter start...', self.getServerId());
appUtil.optComponents(self.loaded, Constants.RESERVED.START, function (err) {
self.state = STATE_START;
if (err) {
utils.invokeCallback(cb, err);
}
else {
logger.info('%j enter after start...', self.getServerId());
self.afterStart(cb);
}
});
}
});
};
appUtil.optLifecycles(self.usedPlugins, Constants.LIFECYCLE.BEFORE_STARTUP, self, function (err) {
if (err) {
utils.invokeCallback(cb, err);
}
else {
startUp();
}
});
});
}
/**
* Lifecycle callback for after start.
*
* @param {Function} cb callback function
* @return {Void}
*/
afterStart(cb) {
if (this.state !== STATE_START) {
utils.invokeCallback(cb, new Error('application is not running now.'));
return;
}
let self = this;
appUtil.optComponents(this.loaded, Constants.RESERVED.AFTER_START, function (err) {
self.state = STATE_STARTED;
let id = self.getServerId();
if (!err) {
logger.info('%j finish start', id);
}
appUtil.optLifecycles(self.usedPlugins, Constants.LIFECYCLE.AFTER_STARTUP, self, function (err) {
let usedTime = Date.now() - self.startTime;
logger.info('%j startup in %s ms', id, usedTime);
self.event.emit(events_2.default.START_SERVER, id);
cb && cb(err);
});
});
}
/**
* Stop components.
*
* @param {Boolean} force whether stop the app immediately
*/
stop(force) {
if (this.state > STATE_STARTED) {
logger.warn('[omelop application] application is not running now.');
return;
}
this.state = STATE_STOPED;
let self = this;
this.stopTimer = setTimeout(function () {
process.exit(0);
}, Constants.TIME.TIME_WAIT_STOP);
let cancelShutDownTimer = function () {
if (!!self.stopTimer) {
clearTimeout(self.stopTimer);
}
};
let shutDown = function () {
appUtil.stopComps(self.loaded, 0, force, function () {
cancelShutDownTimer();
if (force) {
process.exit(0);
}
});
};
let fun = this.get(Constants.KEYWORDS.BEFORE_STOP_HOOK);
appUtil.optLifecycles(self.usedPlugins, Constants.LIFECYCLE.BEFORE_SHUTDOWN, self, function (err) {
if (err) {
console.error(`throw err when beforeShutdown `, err.stack);
}
else {
if (!!fun) {
utils.invokeCallback(fun, self, shutDown, cancelShutDownTimer);
}
else {
shutDown();
}
}
}, cancelShutDownTimer);
}
set(setting, val, attach) {
this.settings[setting] = val;
if (attach) {
this[setting] = val;
}
return this;
}
get(setting) {
return this.settings[setting];
}
/**
* Check if `setting` is enabled.
*
* @param {String} setting application setting
* @return {Boolean}
* @memberOf Application
*/
enabled(setting) {
return !!this.get(setting);
}
/**
* Check if `setting` is disabled.
*
* @param {String} setting application setting
* @return {Boolean}
* @memberOf Application
*/
disabled(setting) {
return !this.get(setting);
}
/**
* Enable `setting`.
*
* @param {String} setting application setting
* @return {app} for chaining
* @memberOf Application
*/
enable(setting) {
return this.set(setting, true);
}
/**
* Disable `setting`.
*
* @param {String} setting application setting
* @return {app} for chaining
* @memberOf Application
*/
disable(setting) {
return this.set(setting, false);
}
configure(env, type, fn) {
let args = [].slice.call(arguments);
fn = args.pop();
env = type = Constants.RESERVED.ALL;
if (args.length > 0) {
env = args[0];
}
if (args.length > 1) {
type = args[1];
}
if (env === Constants.RESERVED.ALL || contains(this.settings.env, env)) {
if (type === Constants.RESERVED.ALL || contains(this.settings.serverType, type)) {
fn.call(this);
}
}
return this;
}
registerAdmin(moduleId, module, opts) {
let modules = this.get(Constants.KEYWORDS.MODULE);
if (!modules) {
modules = {};
this.set(Constants.KEYWORDS.MODULE, modules);
}
if (typeof moduleId !== 'string') {
opts = module;
module = moduleId;
if (module) {
moduleId = (module.moduleId);
if (!moduleId)
moduleId = module.constructor.name;
}
}
if (!moduleId) {
return;
}
modules[moduleId] = {
moduleId: moduleId,
module: module,
opts: opts
};
}
/**
* Use plugin.
*
* @param {Object} plugin plugin instance
* @param {[type]} opts (optional) construct parameters for the factory function
* @memberOf Application
*/
use(plugin, opts) {
opts = opts || {};
if (!plugin) {
throw new Error(`pluin is null!]`);
}
if (this.usedPlugins.indexOf(plugin) >= 0) {
throw new Error(`pluin[${plugin.name} was used already!]`);
}
if (plugin.components) {
for (let componentCtor of plugin.components) {
this.load(componentCtor, opts);
}
}
if (plugin.events) {
for (let eventCtor of plugin.events) {
this.loadEvent(eventCtor, opts);
}
}
this.usedPlugins.push(plugin);
console.warn(`used Plugin : ${plugin.name}`);
}
/**
* Application transaction. Transcation includes conditions and handlers, if conditions are satisfied, handlers would be executed.
* And you can set retry times to execute handlers. The transaction log is in file logs/transaction.log.
*
* @param {String} name transaction name
* @param {Object} conditions functions which are called before transaction
* @param {Object} handlers functions which are called during transaction
* @param {Number} retry retry times to execute handlers if conditions are successfully executed
* @memberOf Application
*/
transaction(name, conditions, handlers, retry) {
appManager.transaction(name, conditions, handlers, retry);
}
/**
* Get master server info.
*
* @return {Object} master server info, {id, host, port}
* @memberOf Application
*/
getMaster() {
return this.master;
}
/**
* Get current server info.
*
* @return {Object} current server info, {id, serverType, host, port}
* @memberOf Application
*/
getCurServer() {
return this.curServer;
}
/**
* Get current server id.
*
* @return {String|Number} current server id from servers.json
* @memberOf Application
*/
getServerId() {
return this.serverId;
}
/**
* Get current server
* @returns ServerInfo
*/
getCurrentServer() {
return this.curServer;
}
/**
* Get current server type.
*
* @return {String|Number} current server type from servers.json
* @memberOf Application
*/
getServerType() {
return this.serverType;
}
/**
* Get all the current server infos.
*
* @return {Object} server info map, key: server id, value: server info
* @memberOf Application
*/
getServers() {
return this.servers;
}
/**
* Get all server infos from servers.json.
*
* @return {Object} server info map, key: server id, value: server info
* @memberOf Application
*/
getServersFromConfig() {
return this.get(Constants.KEYWORDS.SERVER_MAP);
}
/**
* Get all the server type.
*
* @return {Array} server type list
* @memberOf Application
*/
getServerTypes() {
return this.serverTypes;
}
/**
* Get server info by server id from current server cluster.
*
* @param {String} serverId server id
* @return {Object} server info or undefined
* @memberOf Application
*/
getServerById(serverId) {
return this.servers[serverId];
}
/**
* Get server info by server id from servers.json.
*
* @param {String} serverId server id
* @return {Object} server info or undefined
* @memberOf Application
*/
getServerFromConfig(serverId) {
return this.get(Constants.KEYWORDS.SERVER_MAP)[serverId];
}
/**
* Get server infos by server type.
*
* @param {String} serverType server type
* @return {Array} server info list
* @memberOf Application
*/
getServersByType(serverType) {
return this.serverTypeMaps[serverType];
}
/**
* Check the server whether is a frontend server
*
* @param {server} server server info. it would check current server
* if server not specified
* @return {Boolean}
*
* @memberOf Application
*/
isFrontend(server) {
server = server || this.getCurServer();
return !!server && server.frontend === 'true';
}
/**
* Check the server whether is a backend server
*
* @param {server} server server info. it would check current server
* if server not specified
* @return {Boolean}
* @memberOf Application
*/
isBackend(server) {
server = server || this.getCurServer();
return !!server && !server.frontend;
}
/**
* Check whether current server is a master server
*
* @return {Boolean}
* @memberOf Application
*/
isMaster() {
return this.serverType === Constants.RESERVED.MASTER;
}
/**
* Add new server info to current application in runtime.
*
* @param {Array} servers new server info list
* @memberOf Application
*/
addServers(servers) {
if (!servers || !servers.length) {
return;
}
let item, slist;
for (let i = 0, l = servers.length; i < l; i++) {
item = servers[i];
// update global server map
this.servers[item.id] = item;
// update global server type map
slist = this.serverTypeMaps[item.serverType];
if (!slist) {
this.serverTypeMaps[item.serverType] = slist = [];
}
replaceServer(slist, item);
// update global server type list
if (this.serverTypes.indexOf(item.serverType) < 0) {
this.serverTypes.push(item.serverType);
}
}
this.event.emit(events_2.default.ADD_SERVERS, servers);
}
/**
* Remove server info from current application at runtime.
*
* @param {Array} ids server id list
* @memberOf Application
*/
removeServers(ids) {
if (!ids || !ids.length) {
return;
}
let id, item, slist;
for (let i = 0, l = ids.length; i < l; i++) {
id = ids[i];
item = this.servers[id];
if (!item) {
continue;
}
// clean global server map
delete this.servers[id];
// clean global server type map
slist = this.serverTypeMaps[item.serverType];
removeServer(slist, id);
// TODO: should remove the server type if the slist is empty?
}
this.event.emit(events_2.default.REMOVE_SERVERS, ids);
}
/**
* Replace server info from current application at runtime.
*
* @param {Object} server id map
* @memberOf Application
*/
replaceServers(servers) {
if (!servers) {
return;
}
this.servers = servers;
this.serverTypeMaps = {};
this.serverTypes = [];
let serverArray = [];
for (let id in servers) {
let server = servers[id];
let serverType = server[Constants.RESERVED.SERVER_TYPE];
let slist = this.serverTypeMaps[serverType];
if (!slist) {
this.serverTypeMaps[serverType] = slist = [];
}
this.serverTypeMaps[serverType].push(server);
// update global server type list
if (this.serverTypes.indexOf(serverType) < 0) {
this.serverTypes.push(serverType);
}
serverArray.push(server);
}
this.event.emit(events_2.default.REPLACE_SERVERS, serverArray);
}
/**
* Add crons from current application at runtime.
*
* @param {Array} crons new crons would be added in application
* @memberOf Application
*/
addCrons(crons) {
if (!crons || !crons.length) {
logger.warn('crons is not defined.');
return;
}
this.event.emit(events_2.default.ADD_CRONS, crons);
}
/**
* Remove crons from current application at runtime.
*
* @param {Array} crons old crons would be removed in application
* @memberOf Application
*/
removeCrons(crons) {
if (!crons || !crons.length) {
logger.warn('ids is not defined.');
return;
}
this.event.emit(events_2.default.REMOVE_CRONS, crons);
}
/**
* 加载一个事件侦听
* @param Event
* @param opts
*/
loadEvent(Event, opts) {
let eventInstance = new Event(opts);
for (let evt in events_2.AppEvents) {
let name = events_2.AppEvents[evt];
let method = eventInstance[name];
if (method) {
this.event.on(name, method.bind(eventInstance));
}
}
}
}
exports.Application = Application;
let replaceServer = function (slist, serverInfo) {
for (let i = 0, l = slist.length; i < l; i++) {
if (slist[i].id === serverInfo.id) {
slist[i] = serverInfo;
return;
}
}
slist.push(serverInfo);
};
let removeServer = function (slist, id) {
if (!slist || !slist.length) {
return;
}
for (let i = 0, l = slist.length; i < l; i++) {
if (slist[i].id === id) {
slist.splice(i, 1);
return;
}
}
};
let contains = function (str, settings) {
if (!settings) {
return false;
}
let ts = settings.split('|');
for (let i = 0, l = ts.length; i < l; i++) {
if (str === ts[i]) {
return true;
}
}
return false;
};
let addFilter = function (app, type, filter) {
let filters = app.get(type);
if (!filters) {
filters = [];
app.set(type, filters);
}
filters.push(filter);
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvYXBwbGljYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7OztBQUVIOztHQUVHO0FBQ0gsc0NBQXNDO0FBQ3RDLGlEQUFtRDtBQUNuRCxtQ0FBc0M7QUFDdEMsMENBQTZEO0FBQzdELDBDQUEwQztBQUUxQyw4Q0FBOEM7QUFFOUMsMERBQTBEO0FBRTFELHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsK0JBQWtDO0FBNEJsQyxJQUFJLE1BQU0sR0FBRyxJQUFBLHlCQUFTLEVBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztBQWtFNUQ7O0dBRUc7QUFDSCxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUMsQ0FBRSxpQkFBaUI7QUFDeEMsSUFBSSxrQkFBa0IsR0FBRyxDQUFDLENBQUMsQ0FBRSxtQkFBbUI7QUFDaEQsSUFBSSxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUUsWUFBWTtBQUNsQyxJQUFJLGFBQWEsR0FBRyxDQUFDLENBQUMsQ0FBRSxrQkFBa0I7QUFDMUMsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDLENBQUUsaUJBQWlCO0FBRXhDLE1BQWEsV0FBVztJQUF4QjtRQUVJLFdBQU0sR0FBaUIsRUFBRSxDQUFDLENBQU8sd0JBQXdCO1FBQ3pELGVBQVUsR0FlTixFQUFFLENBQUMsQ0FBRyx3QkFBd0I7UUFNbEMsYUFBUSxHQUEyQixFQUFFLENBQUMsQ0FBSywwQkFBMEI7UUFDckUsVUFBSyxHQUFHLElBQUkscUJBQVksRUFBRSxDQUFDLENBQUUsaUNBQWlDO1FBUTlELHNCQUFzQjtRQUN0QixXQUFNLEdBQW9CLElBQUksQ0FBQyxDQUFTLHFCQUFxQjtRQUM3RCxZQUFPLEdBQWlDLEVBQUUsQ0FBQyxDQUFVLDhDQUE4QztRQUNuRyxtQkFBYyxHQUFxQyxFQUFFLENBQUMsQ0FBRywyQ0FB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