UNPKG

@pandorajs/hub

Version:

pandora.js messenge hub

317 lines 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HubClient = void 0; const uuid = require("uuid"); const messenger_1 = require("@pandorajs/messenger"); const const_1 = require("../const"); const SelectorUtils_1 = require("./SelectorUtils"); const util_1 = require("util"); const DefaultDispatchHandler_1 = require("./DefaultDispatchHandler"); const events_1 = require("events"); class HubClient extends events_1.EventEmitter { constructor(options) { super(); this.messengerClient = null; this.publishedSelectors = []; this.location = { ...options.location, clientId: uuid.v4(), }; this.logger = options.logger || console; this.dispatchHandlers = [new DefaultDispatchHandler_1.DefaultDispatchHandler()]; } /** * Set a handler to hand HUB Dispatching message * @param {DispatchHandler} dispatchHandler */ pushDispatchHandler(dispatchHandler) { this.dispatchHandlers.push(dispatchHandler); } async handleHubDispatch(message) { for (const dispatchHandler of this.dispatchHandlers) { const ret = await dispatchHandler.dispatch(message); if (ret) { return ret; } } this.emit(message.action, message); } isReady() { return !!this.messengerClient; } /** * Let this client online * @return {Promise<void>} */ async start() { if (this.messengerClient) { throw new Error('HubClient already started'); } await new Promise((resolve, reject) => { this.messengerClient = new messenger_1.MessengerClient({ name: const_1.HUB_SOCKET_NAME, reConnectTimes: 10, responseTimeout: const_1.TIMEOUT_OF_RESPONSE, unref: true, }); this.messengerClient.once('error', reject); this.messengerClient.ready(resolve); }); this.startListen(); await this.sendOnline(); // When reconnected this.messengerClient.on('connect', () => { this.resendPublishedSelectors().catch(err => { this.logger.error(err); this.logger.error('resendPublishedSelectors() went wrong'); }); }); } async sendOnline() { await this.sendToHubAndWaitReply(const_1.PANDORA_HUB_ACTION_ONLINE_UP); } /** * Publish a selector to Hub, so Hub will set a relation in RouteTable between client and selector * @param {Selector} selector * @return {Promise<ReplyPackage>} */ async publish(selector) { // Make sure each selector are unique. this.assertExistSelector(selector); const res = await this.sendPublishToHub(selector); this.publishedSelectors.push(selector); return res; } /** * Unpublish a selector to Hub, so Hub will forget the relation in RouteTable between client and selector * @param {Selector} selector * @return {Promise<ReplyPackage>} */ async unpublish(selector) { const filteredSelectors = []; const batchReply = []; for (const targetSelector of this.publishedSelectors) { if (!SelectorUtils_1.SelectorUtils.match(selector, targetSelector)) { filteredSelectors.push(targetSelector); continue; } const res = await this.sendToHubAndWaitReply(const_1.PANDORA_HUB_ACTION_UNPUBLISH_UP, { data: { selector: targetSelector, }, }); batchReply.push(res); if (!res.success) { throw new Error(util_1.format('Unpublish selector %j went wrong, cause from Hub: %s', selector, res.error)); } } this.publishedSelectors = filteredSelectors; return { success: true, batchReply, }; } /** * Resend all published selectors to HUB when reconnected * @return {Promise<void>} */ async resendPublishedSelectors() { await this.sendOnline(); for (const selector of this.publishedSelectors) { await this.sendPublishToHub(selector); } } // /** // * Get all route relations within Hub // * @return {Promise<any>} // */ // async discover() { // const res = await this.sendToHubAndWaitReply(PANDORA_HUB_ACTION_DISCOVER_UP); // if(!res.success) { // throw new Error(format('discover whole hub went wrong, cause from Hub: %j', res.error)); // } // return res.data; // } // // /** // * Lookup route relations by a certain selector // * @param {Selector} selector // * @return {Promise<any>} // */ // async lookup(selector: Selector) { // const res = await this.sendToHubAndWaitReply<LookupPackage>(PANDORA_HUB_ACTION_DISCOVER_UP, { // data: { // selector: selector // } // }); // if(!res.success) { // throw new Error(format('lookup selector %j went wrong, cause from Hub: %j', selector, res.error)); // } // return res.data; // } /** * Invoke a remote Object only from a random one of all selected clients * @return {Promise<any>} */ async invoke(remote, action, message) { const res = await this.sendToHubAndWaitReply(const_1.PANDORA_HUB_ACTION_MSG_UP, { remote: remote, action, broadcast: false, ...message, }); return res; } /** * Invoke a remote Object from all selected clients * @param {Selector} remote * @param message * @return {Promise<Array<ReplyPackage>>} */ async multipleInvoke(remote, action, message) { const res = await this.sendToHubAndWaitReply(const_1.PANDORA_HUB_ACTION_MSG_UP, { remote: remote, action, broadcast: true, ...message, }); return res.batchReply; } /** * Send a message to a random one of all selected clients * @param remote * @param data * @return {Promise<void>} */ send(remote, action, message) { this.sendToHub(const_1.PANDORA_HUB_ACTION_MSG_UP, { remote: remote, action, broadcast: false, ...message, }); } /** * Send a message to all selected clients * @param remote * @param message * @return {Promise<void>} */ multipleSend(remote, action, message) { this.sendToHub(const_1.PANDORA_HUB_ACTION_MSG_UP, { remote: remote, action, broadcast: true, ...message, }); } /** * Get location of this client * @return {Location} */ getLocation() { return this.location; } /** * Send a message to Hub */ sendToHub(action, message) { message = (message || {}); message.host = this.location; this.messengerClient.send(action, message); } /** * Send a message to Hub and wait reply * @param action * @param {MessageType} message * @return {Promise<ReplyPackage>} */ async sendToHubAndWaitReply(action, message) { message = (message || {}); message.host = this.location; message.needReply = true; return new Promise((resolve, reject) => { this.messengerClient.send(action, message, (err, message) => { if (err) { reject(err); return; } resolve(message); }, message.timeout); }); } /** * only send publish message to Hub without state keeping * @param {Selector} selector * @return {Promise<ReplyPackage>} */ async sendPublishToHub(selector) { const res = await this.sendToHubAndWaitReply(const_1.PANDORA_HUB_ACTION_PUBLISH_UP, { data: { selector: selector, }, }); if (!res.success) { throw new Error(util_1.format('Publish selector %j went wrong, cause from Hub: %s', selector, res.error)); } return res; } /** * Make sure each selector are unique * @param selector */ assertExistSelector(selector) { for (const targetSelector of this.publishedSelectors) { if (SelectorUtils_1.SelectorUtils.match(selector, targetSelector)) { throw new Error(util_1.format('Selector %j already exist', selector)); } } } startListen() { this.messengerClient.on(const_1.PANDORA_HUB_ACTION_MSG_DOWN, async (message, reply) => { try { let replyPkg = null; try { const data = await this.handleHubDispatch(message); replyPkg = { host: this.location, remote: message.host, success: true, data: data, }; } catch (error) { replyPkg = { host: this.location, remote: message.host, success: false, error: error, }; } if (message.needReply) { reply(replyPkg); } } catch (err) { this.logger.error(err); this.logger.error(util_1.format('Handing PANDORA_HUB_ACTION_MSG_DOWN went wrong, remote message: %j', message)); } }); } /** * Close this client */ async stop() { if (!this.messengerClient) { throw new Error('HubClient has not started yet'); } await this.sendToHubAndWaitReply(const_1.PANDORA_HUB_ACTION_OFFLINE_UP); this.messengerClient.close(); this.messengerClient = null; } getMessengerClient() { return this.messengerClient; } } exports.HubClient = HubClient; //# sourceMappingURL=HubClient.js.map