occaecatidicta
Version:
766 lines (712 loc) • 25.5 kB
text/typescript
/*!
* Omelox -- consoleModule watchServer
* Copyright(c) 2013 fantasyni <fantasyni@163.com>
* MIT Licensed
*/
import { getLogger } from 'omelox-logger';
import * as countDownLatch from '../util/countDownLatch';
import * as monitor from 'omelox-monitor';
import * as utils from '../util/utils';
import * as util from 'util';
import * as fs from 'fs';
import * as vm from 'vm';
import { IModule, MonitorCallback, MasterCallback, ModuleType , MonitorAgent, MasterAgent } from 'omelox-admin';
import { ServerInfo } from '../util/constants';
import { Application } from '../application';
import * as path from 'path';
let logger = getLogger('omelox', path.basename(__filename));
enum HandleType {
client = 'client',
monitor = 'monitor'
}
export class WatchServerModule implements IModule {
static moduleId = 'watchServer';
app: Application;
constructor(opts ?: {app ?: Application}) {
opts = opts || {};
this.app = opts.app;
}
monitorHandler(agent: MonitorAgent, msg: any, cb: MonitorCallback) {
let comd = msg['comd'];
let context = msg['context'];
let param = msg['param'];
let app = this.app;
let handle = HandleType.monitor;
switch (comd) {
case 'servers':
showServers(handle, agent, comd, context, cb);
break;
case 'connections':
showConnections(handle, agent, app, comd, context, cb);
break;
case 'logins':
showLogins(handle, agent, app, comd, context, cb);
break;
case 'modules':
showModules(handle, agent, comd, context, cb);
break;
case 'status':
showStatus(handle, agent, comd, context, cb);
break;
case 'config':
showConfig(handle, agent, app, comd, context, param, cb);
break;
case 'proxy':
showProxy(handle, agent, app, comd, context, param, cb);
break;
case 'handler':
showHandler(handle, agent, app, comd, context, param, cb);
break;
case 'components':
showComponents(handle, agent, app, comd, context, param, cb);
break;
case 'settings':
showSettings(handle, agent, app, comd, context, param, cb);
break;
case 'cpu':
dumpCPU(handle, agent, comd, context, param, cb);
break;
case 'memory':
dumpMemory(handle, agent, comd, context, param, cb);
break;
case 'get':
getApp(handle, agent, app, comd, context, param, cb);
break;
case 'set':
setApp(handle, agent, app, comd, context, param, cb);
break;
case 'enable':
enableApp(handle, agent, app, comd, context, param, cb);
break;
case 'disable':
disableApp(handle, agent, app, comd, context, param, cb);
break;
case 'run':
runScript(handle, agent, app, comd, context, param, cb);
break;
default:
showError(handle, agent, comd, context, cb);
}
}
clientHandler(agent: MasterAgent, msg: any, cb: MasterCallback) {
let comd = msg['comd'];
let context = msg['context'];
let param = msg['param'];
let app = this.app; // master app
if (!comd || !context) {
cb('lack of comd or context param');
return;
}
let handle = HandleType.client;
switch (comd) {
case 'servers':
showServers(handle, agent, comd, context, cb);
break;
case 'connections':
showConnections(handle, agent, app, comd, context, cb);
break;
case 'logins':
showLogins(handle, agent, app, comd, context, cb);
break;
case 'modules':
showModules(handle, agent, comd, context, cb);
break;
case 'status':
showStatus(handle, agent, comd, context, cb);
break;
case 'config':
showConfig(handle, agent, app, comd, context, param, cb);
break;
case 'proxy':
showProxy(handle, agent, app, comd, context, param, cb);
break;
case 'handler':
showHandler(handle, agent, app, comd, context, param, cb);
break;
case 'components':
showComponents(handle, agent, app, comd, context, param, cb);
break;
case 'settings':
showSettings(handle, agent, app, comd, context, param, cb);
break;
case 'cpu':
dumpCPU(handle, agent, comd, context, param, cb);
break;
case 'memory':
dumpMemory(handle, agent, comd, context, param, cb);
break;
case 'get':
getApp(handle, agent, app, comd, context, param, cb);
break;
case 'set':
setApp(handle, agent, app, comd, context, param, cb);
break;
case 'enable':
enableApp(handle, agent, app, comd, context, param, cb);
break;
case 'disable':
disableApp(handle, agent, app, comd, context, param, cb);
break;
case 'run':
runScript(handle, agent, app, comd, context, param, cb);
break;
default:
showError(handle, agent, comd, context, cb);
}
}
}
function showServers(handle: HandleType, agent_: MonitorAgent | MasterAgent, comd: string, context: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = agent_ as MasterAgent;
let sid, record;
let serverInfo: any = {};
let count = Object.keys(agent.idMap).length;
let latch = countDownLatch.createCountDownLatch(count, function () {
cb(null, {
msg: serverInfo
});
});
for (sid in agent.idMap) {
record = agent.idMap[sid];
agent.request(record.id, WatchServerModule.moduleId, {
comd: comd,
context: context
}, function (err , msg) {
serverInfo[msg.serverId] = msg.body;
latch.done();
});
}
} else if (handle === 'monitor') {
let agent = agent_ as MonitorAgent;
let serverId = agent.id;
let serverType = agent.type;
let info = agent.info;
let pid = process.pid;
let heapUsed = (process.memoryUsage().heapUsed / (1000 * 1000)).toFixed(2);
let uptime = (process.uptime() / 60).toFixed(2);
cb(null, {
serverId: serverId,
body: {
serverId: serverId,
serverType: serverType,
host: info['host'],
port: info['port'],
pid: pid,
heapUsed: heapUsed,
uptime: uptime
}
});
}
}
function showConnections(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application , comd: string, context: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
let sid, record;
let serverInfo: any = {};
let count = 0;
for (let key in agent.idMap) {
if ((agent.idMap[key].info as ServerInfo).frontend) {
count++;
}
}
let latch = countDownLatch.createCountDownLatch(count, function () {
cb(null, {
msg: serverInfo
});
});
for (sid in agent.idMap) {
record = agent.idMap[sid];
if ((record.info as ServerInfo).frontend) {
agent.request(record.id, WatchServerModule.moduleId, {
comd: comd,
context: context
}, function (err , msg) {
serverInfo[msg.serverId] = msg.body;
latch.done();
});
}
}
} else {
let record = agent.idMap[context];
if (!record) {
cb('the server ' + context + ' not exist');
}
if ((record.info as ServerInfo).frontend) {
agent.request(record.id, WatchServerModule.moduleId, {
comd: comd,
context: context
}, function (err , msg) {
let serverInfo: any = {};
serverInfo[msg.serverId] = msg.body;
cb(null, {
msg: serverInfo
});
});
} else {
cb('\nthis command should be applied to frontend server\n');
}
}
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let connection = app.components.__connection__;
if (!connection) {
cb(null , {
serverId: agent.id,
body: 'error'
});
return;
}
cb(null , {
serverId: agent.id,
body: connection.getStatisticsInfo()
});
}
}
function showLogins(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , cb: (err?: Error | string , data?: any) => void) {
showConnections(handle, _agent, app, comd, context, cb);
}
function showModules(handle: HandleType, _agent: MonitorAgent | MasterAgent, comd: string, context: string , cb: (err?: Error | string , data?: any) => void) {
let modules = _agent.consoleService.modules;
let result = [];
for (let module in modules) {
result.push(module);
}
cb(null, {
msg: result
});
}
function showStatus(handle: HandleType, _agent: MonitorAgent | MasterAgent, comd: string, context: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
context: context
}, function (err, msg) {
cb(null, {
msg: msg
});
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let serverId = agent.id;
let pid = process.pid;
let params = {
serverId: serverId,
pid: String(pid)
};
monitor.psmonitor.getPsInfo(params, function (err: Error, data: any) {
cb(null, {
serverId: agent.id,
body: data
});
});
}
}
function showConfig(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string, cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (param === 'master') {
cb(null, {
masterConfig: app.get('masterConfig') || 'no config to master in app.js',
masterInfo: app.get('master')
});
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, cb);
} else if (handle === 'monitor') {
let key = param + 'Config';
cb(null, clone(param, app.get(key)));
}
}
function showProxy(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string, param: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
proxyCb(app, context, cb);
}
}
function showHandler(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
handlerCb(app, context, cb);
}
}
function showComponents(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string, cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let _components = app.components;
let res: any = {};
for (let key in _components) {
let name = getComponentName(key);
res[name] = clone(name, app.get(name + 'Config'));
}
cb(null, res);
}
}
function showSettings(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let _settings = app.settings;
let res: any = {};
for (let key in _settings) {
if (key.match(/^__\w+__$/) || key.match(/\w+Config$/)) {
continue;
}
if (!checkJSON(_settings[key])) {
res[key] = 'Object';
continue;
}
res[key] = _settings[key];
}
cb(null, res);
}
}
function dumpCPU(handle: HandleType, _agent: MonitorAgent | MasterAgent, comd: string, context: string , param: {times: number , filepath: string, force: boolean} , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(err, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let times = param['times'];
let filepath = param['filepath'];
let force = param['force'];
cb(null, 'cpu dump is unused in 1.0 of omelox');
/**
if (!/\.cpuprofile$/.test(filepath)) {
filepath = filepath + '.cpuprofile';
}
if (!times || !/^[0-9]*[1-9][0-9]*$/.test(times)) {
cb('no times or times invalid error');
return;
}
checkFilePath(filepath, force, function(err) {
if (err) {
cb(err);
return;
}
//ndump.cpu(filepath, times);
cb(null, filepath + ' cpu dump ok');
});
*/
}
}
function dumpMemory(handle: HandleType, _agent: MonitorAgent | MasterAgent, comd: string, context: string , param: {filepath: string, force: boolean} , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(err, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let filepath = param['filepath'];
let force = param['force'];
if (!/\.heapsnapshot$/.test(filepath)) {
filepath = filepath + '.heapsnapshot';
}
checkFilePath(filepath, force, function (err: string) {
if (err) {
cb(err);
return;
}
let heapdump = null;
try {
heapdump = require('heapdump');
heapdump.writeSnapshot(filepath);
cb(null, filepath + ' memory dump ok');
} catch (e) {
cb('omelox-admin require heapdump');
}
});
}
}
function getApp(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let res = app.get(param);
if (!checkJSON(res)) {
res = 'object';
}
cb(null, res || null);
}
}
function setApp(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: {key: string, value: any}, cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let key = param['key'];
let value = param['value'];
app.set(key, value);
cb(null, 'set ' + key + ':' + value + ' ok');
}
}
function enableApp(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string, cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
app.enable(param);
cb(null, 'enable ' + param + ' ok');
}
}
function disableApp(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string, cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
app.disable(param);
cb(null, 'disable ' + param + ' ok');
}
}
function runScript(handle: HandleType, _agent: MonitorAgent | MasterAgent, app: Application, comd: string, context: string , param: string , cb: (err?: Error | string , data?: any) => void) {
if (handle === 'client') {
let agent = _agent as MasterAgent;
if (context === 'all') {
cb('context error');
return;
}
agent.request(context, WatchServerModule.moduleId, {
comd: comd,
param: param,
context: context
}, function (err, msg) {
cb(null, msg);
});
} else if (handle === 'monitor') {
let agent = _agent as MonitorAgent;
let ctx = {
app: app,
result: null as any
};
try {
vm.createContext(ctx);
vm.runInNewContext('result = ' + param, ctx);
cb(null, util.inspect(ctx.result));
} catch (e) {
cb(null, e.stack);
}
}
}
function showError(handle: HandleType, _agent: MonitorAgent | MasterAgent, comd: string, context: string , cb: (err?: Error | string , data?: any) => void) {
}
function clone(param: any, obj: any) {
let result: any = {};
let flag = 1;
for (let key in obj) {
if (typeof obj[key] === 'function' || typeof obj[key] === 'object') {
continue;
}
flag = 0;
result[key] = obj[key];
}
if (flag) {
// return 'no ' + param + 'Config info';
}
return result;
}
function checkFilePath(filepath: string, force: boolean, cb: (result: string) => void) {
if (!force && fs.existsSync(filepath)) {
cb('filepath file exist');
return;
}
fs.writeFile(filepath, 'test', function (err) {
if (err) {
cb('filepath invalid error');
return;
}
fs.unlinkSync(filepath);
cb(null);
});
}
function proxyCb(app: Application, context: string, cb: MasterCallback) {
let msg: any = {};
let __proxy__ = app.components.__proxy__;
if (__proxy__ && __proxy__.client && __proxy__.client.proxies.user) {
let proxies = __proxy__.client.proxies.user;
let server = app.getServerById(context);
if (!server) {
cb('no server with this id ' + context);
} else {
let type = server['serverType'];
let tmp = proxies[type];
msg[type] = {};
for (let _proxy in tmp) {
let r = tmp[_proxy];
msg[type][_proxy] = {};
for (let _rpc in r) {
if (typeof r[_rpc] === 'function') {
msg[type][_proxy][_rpc] = 'function';
}
}
}
cb(null, msg);
}
} else {
cb('no proxy loaded');
}
}
function handlerCb(app: Application, context: string, cb: MasterCallback) {
let msg: any = {};
let __server__ = app.components.__server__;
if (__server__ && __server__.server && __server__.server.handlerService.handlerMap) {
let handles = __server__.server.handlerService.handlerMap;
let server = app.getServerById(context);
if (!server) {
cb('no server with this id ' + context);
} else {
let type = server['serverType'];
let tmp = handles as any;
msg[type] = {};
for (let _p in tmp) {
let r = tmp[_p];
msg[type][_p] = {};
for (let _r in r) {
if (typeof r[_r] === 'function') {
msg[type][_p][_r] = 'function';
}
}
}
cb(null, msg);
}
} else {
cb('no handler loaded');
}
}
function getComponentName(c: string): string {
let t = c.match(/^__(\w+)__$/);
if (t) {
t = t[1] as any;
}
return t as any;
}
function checkJSON(obj: any) {
if (!obj) {
return true;
}
try {
JSON.stringify(obj);
} catch (e) {
return false;
}
return true;
}