occaecatidicta
Version:
128 lines (112 loc) • 3.72 kB
text/typescript
import { createDefaultAcceptor, IAcceptor, IAcceptorFactory } from './acceptor';
import { EventEmitter } from 'events';
import { Dispatcher, MsgPkg, Services } from './dispatcher';
import * as Loader from 'omelox-loader';
import * as utils from '../util/utils';
import { Tracer } from '../util/tracer';
import * as util from 'util';
import * as fs from 'fs';
import { AcceptorOpts } from './acceptor';
import { LoaderPathType } from 'omelox-loader';
export interface RpcServerOpts extends AcceptorOpts {
port?: number | string;
paths?: Array<RemoteServerCode>;
context?: object;
services?: Services;
acceptorFactory?: IAcceptorFactory;
}
export interface RemoteServerCode {
namespace: string;
serverType: string;
path: string;
}
export class Gateway extends EventEmitter {
opts: any;
port: number;
started = false;
stoped = false;
services: Services;
acceptor: IAcceptor;
dispatcher: Dispatcher;
constructor(opts: RpcServerOpts) {
super();
this.opts = opts || {};
this.port = <number>opts.port || 3050;
this.started = false;
this.stoped = false;
let acceptorFactory = opts.acceptorFactory || createDefaultAcceptor;
this.services = opts.services;
const dispatcher = this.dispatcher = new Dispatcher(this.services);
if (!!this.opts.reloadRemotes) {
this.watchServices();
}
this.acceptor = acceptorFactory(opts as AcceptorOpts, (tracer, msg, cb) => {
dispatcher.route(tracer, msg, cb);
});
}
stop(force: boolean) {
if (!this.started || this.stoped) {
return;
}
this.stoped = true;
try {
this.acceptor.close();
} catch (err) {
}
}
start() {
if (this.started) {
throw new Error('gateway already start.');
}
this.started = true;
let self = this;
this.acceptor.on('error', self.emit.bind(self, 'error'));
this.acceptor.on('closed', self.emit.bind(self, 'closed'));
this.acceptor.listen(this.port);
}
watchServices() {
let paths = this.opts.paths;
let app = this.opts.context;
for (let i = 0; i < paths.length; i++) {
((index) => {
fs.watch(paths[index].path, (event: string, name: string) => {
if (event === 'change') {
this.reloadRemoter(app, paths[index]);
}
});
})(i);
}
}
manualReloadRemoters() {
let paths = this.opts.paths;
let app = this.opts.context;
for (let i = 0; i < paths.length; i++) {
this.reloadRemoter(app, paths[i]);
}
}
private reloadRemoter(app: any, item: any) {
let res: { [key: string]: any } = {};
let m: { [key: string]: any } = Loader.load(item.path, app, true, true, LoaderPathType.OMELOX_REMOTER);
if (m) {
createNamespace(item.namespace, res);
for (let s in m) {
res[item.namespace][s] = m[s];
}
}
this.dispatcher.emit('reload', res);
}
}
/**
* create and init gateway
*
* @param opts {services: {rpcServices}, connector:conFactory(optional), router:routeFunction(optional)}
*/
export function createGateway(opts: RpcServerOpts) {
if (!opts || !opts.services) {
throw new Error('opts and opts.services should not be empty.');
}
return new Gateway(opts);
}
let createNamespace = function (namespace: string, proxies: { [key: string]: object }) {
proxies[namespace] = proxies[namespace] || {};
};