UNPKG

seneca-alimns-transport

Version:

A Seneca transport plugin for Aliyun-MNS

217 lines (179 loc) 7.7 kB
'use strict'; const PLUGIN_NAME = 'alimns-transport'; var _ = require('lodash'); var AliMNS = require("ali-mns"); module.exports = function(opts) { var seneca = this; var so = seneca.options(); // transport default settings var options = seneca.util.deepextend({ alimns: { region: 'hangzhou', waitSeconds: 30 } }, so.transport, opts); var tu = seneca.export('transport/utils') seneca.add({ role: 'transport', hook: 'listen', type: 'alimns' }, hookListenAliMNS); seneca.add({ role: 'transport', hook: 'client', type: 'alimns' }, hookClientAliMNS); function hookListenAliMNS(args, done) { var seneca = this var type = args.type // merge transport default options var listenOptions = seneca.util.clean(_.extend({}, options[type], args)) var account = new AliMNS.Account( listenOptions.accountId, listenOptions.accessKeyId, listenOptions.accessKeySecret ); var mns = new AliMNS.MNS(account, listenOptions.region) seneca.log.info('listen', 'open', listenOptions, seneca) // find queues to listen to var pins = tu.resolve_pins(args) var queues = [] if (pins) { pins.forEach(function(pin) { var sb = [tu._msgprefix] _.each(_.keys(pin).sort(), function (key) { sb.push(key, pin[key]) }) if (listenOptions.queueSuffix) sb.push(listenOptions.queueSuffix) var queue = sb.join('-').replace(/[^a-zA-Z\d\-]+/g, '') queues.push(queue) }) } else { queues.push('any') } _.forOwn(queues, function(queue) { var requestMq = new AliMNS.MQ( queue, account, listenOptions.region ) seneca.log.info('connecting MQ: ' + queue) mns.createP(queue, listenOptions.queueOptions).then( startListening, function(res) { setTimeout(function() { throw new Error(res.Error.Message) }) } ) function startListening(res) { requestMq.notifyRecv(function(err, request) { if (err) throw err; seneca.log.info('Request received') var reqMsg = tu.parseJSON(seneca, 'listen-' + type, request.Message.MessageBody) var respMq = new AliMNS.MQ( 'seneca-client-' + reqMsg.clientId, account, listenOptions.region ) tu.handle_request(seneca, reqMsg, listenOptions, function(resp) { // delete message after processing requestMq.deleteP(request.Message.ReceiptHandle).then( function(res) { seneca.log.info('Message deleted:(' + res + '):' + request.Message.ReceiptHandle) }, seneca.log.error ) // there may be no result! if (null == resp) return // send response var respMsg = tu.stringifyJSON(seneca, 'listen-' + type, resp) respMq.sendP(respMsg).then( function(res) { seneca.log.info('Response sent', res) }, seneca.log.error ) }) // not delete the received message here return false }, 5, 1) } seneca.add('role:seneca,cmd:close', function(args, done) { requestMq.notifyStopP().then( function(res) { seneca.log.info('Service stopped(' + res + ')') }, seneca.log.error ) this.prior(args, done) }) }) done() } function hookClientAliMNS(args, client_done) { var seneca = this var type = args.type // merge transport default options var clientOptions = seneca.util.clean(_.extend({}, options[type], args)) var account = new AliMNS.Account( clientOptions.accountId, clientOptions.accessKeyId, clientOptions.accessKeySecret ); var mns = new AliMNS.MNS(account, clientOptions.region) var clientMqName = 'seneca-client-' + clientOptions.id var responseMq = new AliMNS.MQ( clientMqName, account, clientOptions.region ); mns.createP(clientMqName).then(function(result){ seneca.log.info('Client MQ ' + clientMqName + ' created (' + result + ')') responseMq.notifyRecv(function(err, response) { if (err) throw err; seneca.log.info('Response received') var respMsg = tu.parseJSON(seneca, 'client-' + type, response.Message.MessageBody) if (respMsg.error) { respMsg.error.input = respMsg.input } tu.handle_response(seneca, respMsg, clientOptions) // ack receiving as there's no chance to callback after handle_response() return true }) tu.make_client( make_send, clientOptions, client_done ) // make_send is called per topic // not sure what @spec is here, seems that only {} or undefined will be passed in function make_send( spec, topic, send_done ) { var reqMqName = topic.replace(/_/g, '-'); if (clientOptions.queueSuffix) reqMqName += clientOptions.queueSuffix else reqMqName = reqMqName.slice(0, -1) var requestMq = new AliMNS.MQ( reqMqName, account, clientOptions.region ); seneca.log.info('connecting MQ: ' + reqMqName) send_done( null, function( args, done ) { // create message JSON var request = tu.prepare_request( seneca, args, done ) request.clientId = clientOptions.id var reqMsg = tu.stringifyJSON(seneca, 'client-alimns', request) requestMq.sendP(reqMsg).then( function(res) { seneca.log.info('Request sent', res) }, seneca.log.error ) }) } }, seneca.log.error) seneca.add('role:seneca,cmd:close', function (close_args, done) { responseMq.notifyStopP().then( function(res) { seneca.log.info('Client stopped(' + res + '): ' + clientOptions.id) }, seneca.log.error ) mns.deleteP(clientMqName) this.prior(close_args, done) }) } return { name: PLUGIN_NAME }; };