occaecatidicta
Version:
253 lines (228 loc) • 7.88 kB
text/typescript
import { getLogger } from 'omelox-logger';
import { MqttClient } from '../protocol/mqtt/mqttClient';
import {EventEmitter } from 'events';
import * as protocol from '../util/protocol';
import * as utils from '../util/utils';
import * as Util from 'util';
import { ServerInfo, AdminServerInfo, Callback } from '../util/constants';
import { ConsoleService } from '../consoleService';
import * as path from 'path';
let logger = getLogger('omelox-admin', path.basename(__filename));
let ST_INITED = 1;
let ST_CONNECTED = 2;
let ST_REGISTERED = 3;
let ST_CLOSED = 4;
let STATUS_INTERVAL = 5 * 1000; // 60 seconds
export interface MonitorAgentOpts { id: string; type: string; info: ServerInfo; consoleService: ConsoleService; }
/**
* MonitorAgent Constructor
*
* @class MasterAgent
* @constructor
* @param {Object} opts construct parameter
* opts.consoleService {Object} consoleService
* opts.id {String} server id
* opts.type {String} server type, 'master', 'connector', etc.
* opts.info {Object} more server info for current server, {id, serverType, host, port}
* @api public
*/
export class MonitorAgent extends EventEmitter {
opts: MonitorAgentOpts;
id: string;
type: string;
info: ServerInfo;
consoleService: ConsoleService;
reqId = 1;
socket: MqttClient;
callbacks: {[reqId: number]: Callback} = {};
state = ST_INITED;
constructor(opts: MonitorAgentOpts) {
super();
this.reqId = 1;
this.opts = opts;
this.id = opts.id;
this.socket = null;
this.callbacks = {};
this.type = opts.type;
this.info = opts.info;
this.state = ST_INITED;
this.consoleService = opts.consoleService;
}
/**
* register and connect to master server
*
* @param {String} port
* @param {String} host
* @param {Function} cb callback function
* @api public
*/
connect(port: number, host: string, cb: (err?: Error) => void) {
if (this.state > ST_INITED) {
logger.error('monitor client has connected or closed.');
return;
}
cb = cb || function () { };
this.socket = new MqttClient(this.opts);
this.socket.connect(host, port);
// this.socket = sclient.connect(host + ':' + port, {
// 'force new connection': true,
// 'reconnect': true,
// 'max reconnection attempts': 20
// });
let self = this;
this.socket.on('register', function (msg) {
if (msg && msg.code === protocol.PRO_OK) {
self.state = ST_REGISTERED;
cb();
} else {
self.emit('close');
logger.error('server %j %j register master failed:' + JSON.stringify(msg), self.id, self.type, );
}
});
this.socket.on('monitor', function (msg) {
if (self.state !== ST_REGISTERED) {
return;
}
msg = protocol.parse(msg);
if (msg.command) {
// a command from master
self.consoleService.command(msg.command, msg.moduleId, msg.body, function (err, res) {
// notify should not have a callback
});
} else {
let respId = msg.respId;
if (respId) {
// a response from monitor
let respCb = self.callbacks[respId];
if (!respCb) {
logger.warn('unknown resp id:' + respId);
return;
}
delete self.callbacks[respId];
respCb(msg.error, msg.body);
return;
}
// request from master
self.consoleService.execute(msg.moduleId, 'monitorHandler', msg.body, function (err, res) {
if (protocol.isRequest(msg)) {
let resp = protocol.composeResponse(msg, err, res);
if (resp) {
self.doSend('monitor', resp);
}
} else {
// notify should not have a callback
logger.error('notify should not have a callback.');
}
});
}
});
this.socket.on('connect', function () {
if (self.state > ST_INITED) {
// ignore reconnect
return;
}
self.state = ST_CONNECTED;
let req = {
id: self.id,
type: 'monitor',
serverType: self.type,
pid: process.pid,
info: self.info,
token: undefined as string
};
let authServer = self.consoleService.authServer;
let env = self.consoleService.env;
authServer(req, env, function (token) {
req['token'] = token;
self.doSend('register', req);
});
});
this.socket.on('error', function (err) {
if (self.state < ST_CONNECTED) {
// error occurs during connecting stage
cb(err);
} else {
self.emit('error', err);
}
});
this.socket.on('disconnect', function (reason) {
self.state = ST_CLOSED;
self.emit('close');
});
this.socket.on('reconnect', function () {
self.state = ST_CONNECTED;
let req = {
id: self.id,
type: 'monitor',
info: self.info,
pid: process.pid,
serverType: self.type
};
self.doSend('reconnect', req);
});
this.socket.on('reconnect_ok', function (msg) {
if (msg && msg.code === protocol.PRO_OK) {
self.state = ST_REGISTERED;
}
});
}
/**
* close monitor agent
*
* @api public
*/
close() {
if (this.state >= ST_CLOSED) {
return;
}
this.state = ST_CLOSED;
this.socket.disconnect();
}
/**
* set module
*
* @param {String} moduleId module id/name
* @param {Object} value module object
* @api public
*/
set(moduleId: string, value: any) {
this.consoleService.set(moduleId, value);
}
/**
* get module
*
* @param {String} moduleId module id/name
* @api public
*/
get(moduleId: string) {
return this.consoleService.get(moduleId);
}
/**
* notify master server without callback
*
* @param {String} moduleId module id/name
* @param {Object} msg message
* @api public
*/
notify(moduleId: string, msg: any) {
if (this.state !== ST_REGISTERED) {
logger.error('agent can not notify now, state:' + this.state);
return;
}
this.doSend('monitor', protocol.composeRequest(null, moduleId, msg));
// this.socket.emit('monitor', protocol.composeRequest(null, moduleId, msg));
}
request(moduleId: string, msg: any, cb: Callback) {
if (this.state !== ST_REGISTERED) {
logger.error('agent can not request now, state:' + this.state);
return;
}
let reqId = this.reqId++;
this.callbacks[reqId] = cb;
this.doSend('monitor', protocol.composeRequest(reqId, moduleId, msg));
// this.socket.emit('monitor', protocol.composeRequest(reqId, moduleId, msg));
}
doSend(topic: string, msg: any) {
this.socket.send(topic, msg);
}
}