UNPKG

ali-ons-sdk

Version:

Aliyun Open Notification Service Client

188 lines (168 loc) 4.95 kB
'use strict'; const assert = require('assert'); const Base = require('sdk-base'); const logger = require('./logger'); const Channel = require('./channel'); const defaultOptions = { logger, responseTimeout: 30000, }; class RemotingClient extends Base { /** * rocketmq remoting client * @param {Object} options * - {HttpClient} httpclient - http request client * - {Object} [logger] - log module * - {Number} [responseTimeout] - tcp response timeout * @constructor */ constructor(options) { assert(options.onsAddr || options.nameSrv, '[RemotingClient] options.onsAddr or options.nameSrv one of them is required'); assert(options.httpclient, '[RemotingClient] options.httpclient is required'); super(Object.assign({ initMethod: 'init' }, defaultOptions, options)); this._index = 0; this._inited = false; this._namesrvAddrList = []; this._channels = new Map(); } /** * @property {HttpClient} RemotingClient#httpclient */ get httpclient() { return this.options.httpclient; } /** * @property {Object} RemotingClient#logger */ get logger() { return this.options.logger; } /** * @property {Number} RemotingClient#responseTimeout */ get responseTimeout() { return this.options.responseTimeout; } /** * start the client * @return {void} */ async init() { // get name server address at first await this.updateNameServerAddressList(); this._inited = true; this.logger.info('[mq:remoting_client] remoting client started'); } /** * close the client * @return {void} */ async close() { if (!this._inited) { return; } // wait all channel close await Promise.all(Array.from(this._channels.keys()).map(addr => { return new Promise(resolve => { const channel = this._channels.get(addr); if (channel && channel.isOK) { channel.once('close', resolve); channel.close(); } else { resolve(); } this._channels.delete(addr); }); })); this._inited = false; this.emit('close'); this.removeAllListeners(); this.logger.info('[mq:remoting_client] remoting client is closed'); } /** * default error handler * @param {Error} err - error object * @return {void} */ error(err) { this.emit('error', err); } async handleClose(addr, channel) { if (this._channels.get(addr) && this._channels.get(addr).clientId === channel.clientId) { this._channels.delete(addr); } // refresh latest server list await this.updateNameServerAddressList(); } /** * fetch name server address list * @return {void} */ async updateNameServerAddressList() { if (this.options.nameSrv) { this._namesrvAddrList = [ this.options.nameSrv ]; return; } const ret = await this.httpclient.request(this.options.onsAddr, { timeout: this.options.connectTimeout || 10000, }); if (ret.status === 200) { const addrs = ret.data.toString().trim(); const newList = addrs.split(';'); if (newList.length) { this._namesrvAddrList = newList; } this.logger.info('[mq:remoting_client] fetch name server addresses successfully, address: %s', addrs); } else { throw new Error('[mq:remoting_client] fetch name server addresses failed, ret.statusCode: ' + ret.status); } } /** * invoke command * @param {String} addr - server address * @param {RemotingCommand} command - remoting command * @param {Number} [timeout] - response timeout * @return {Object} response */ async invoke(addr, command, timeout) { if (!this._inited) { await this.ready(); } return await this.getAndCreateChannel(addr) .invoke(command, timeout || this.responseTimeout); } /** * invoke command without response * @param {String} addr - server address * @param {RemotingCommand} command - remoting command * @return {void} */ async invokeOneway(addr, command) { if (!this._inited) { await this.ready(); } await this.getAndCreateChannel(addr).invokeOneway(command); } /** * get request channel from address * @param {String} [addr] - server address * @return {Channel} request channel */ getAndCreateChannel(addr) { if (!addr) { this._index = ++this._index % this._namesrvAddrList.length; addr = this._namesrvAddrList[this._index]; } let channel = this._channels.get(addr); if (channel && channel.isOK) { return channel; } channel = new Channel(addr, this.options); this._channels.set(addr, channel); channel.once('close', this.handleClose.bind(this, addr, channel)); channel.on('error', err => this.error(err)); channel.on('request', (request, address) => this.emit('request', request, address)); return channel; } } module.exports = RemotingClient;