proton-quark-amqp
Version:
Quark to load proton-amqp-exchange(s) and proton-amqp-queue(s) and use them with proton microframework
131 lines (112 loc) • 3.93 kB
JavaScript
const Quark = require('proton-quark')
const fs = require('fs')
const path = require('path')
const _ = require('lodash')
const amqp = require('amqplib')
const co = require('co')
module.exports = class AMQPQuark extends Quark {
constructor(proton) {
super(proton)
proton.app.amqp = { exchanges: {}, queues: {}, __connections: [] }
}
validate() {
// Nothing to do ....
return new Promise((resolve, reject) => resolve())
}
initialize() {
return Promise.all([co.wrap(this._initializeQueues.bind(this))(),
co.wrap(this._initializeExchanges.bind(this))()]).then((values) => values)
}
* _initializeQueues() {
const queues = this._queues
for(let Q in queues) {
const queue = queues[Q]
let conn = this._existsConn({ url: queue.url, socketOptions: queue.socketOptions })
if(!conn) conn = yield this._connect(queue)
yield this._initializeQueue(queue, (queue.customName || Q), conn)
}
}
* _initializeExchanges() {
const exchanges = this._exchanges
for(let E in exchanges) {
const exchange = exchanges[E]
let conn = this._existsConn({ url: exchange.url, socketOptions: exchange.socketOptions })
if(!conn) conn = yield this._connect(exchange)
yield this._initializeExchange(exchange, (exchange.customName || E), conn)
}
}
configure() {
// Nothing to do ....
return new Promise((resolve, reject) => resolve())
}
get _exchanges() {
const exchangesPath = path.join(this.proton.paths.api, '/amqp/exchanges')
return fs.existsSync(exchangesPath) ? require('require-all')(exchangesPath) : {}
}
get _queues() {
const queuesPath = path.join(this.proton.paths.api, '/amqp/queues')
return fs.existsSync(queuesPath) ? require('require-all')(queuesPath) : {}
}
* _connect(ExQ) {
const conn = yield amqp.connect(ExQ.url, ExQ.socketOptions)
this.proton.app.amqp.__connections.push({
params: {
url: ExQ.url,
socketOptions: ExQ.socketOptions
},
connection: conn
})
return conn
}
* _createChannel(ExQ, conn) {
yield ExQ.beforeCreateChannel(conn)
const ch = yield conn.createChannel()
return ch
}
* _initializeExchange(E, name, conn) {
const ch = yield this._createChannel(E, conn)
yield ch.assertExchange(name, E.type, E.options)
const exchange = new E(ch, name)
yield this._bindingsFromExchange(exchange)
this.proton.app.amqp.exchanges[name] = exchange
}
* _initializeQueue(Q, name, conn) {
const ch = yield this._createChannel(Q, conn)
yield ch.assertQueue(name, Q.options)
const queue = new Q(ch, name)
yield this._bindingsFromQueue(queue)
this.proton.app.amqp.queues[name] = queue
}
_bindingsFromExchange(exchange) {
const { bindings } = exchange
return Promise.all(bindings.map(b => {
if(b.source) {
return exchange.channel.bindExchange(exchange.name, b.source, b.routingKey, b.args)
} else if(b.destination) {
if(b.to === 'queue') return exchange.channel.bindQueue(b.destination, exchange.name, b.routingKey, b.args)
else if(b.to === 'exchange') return exchange.channel.bindExchange(b.destination, exchange.name, b.routingKey, b.args)
else throw new Error('In order to define a destination binding, param `to` must be defined')
} else {
throw new Error('Either source or exchange must be defined')
}
}))
}
* _bindingsFromQueue(queue) {
const bindings = queue.bindings
for(let b in bindings) {
yield queue.channel.bindQueue(queue.name, bindings[b].source, bindings[b].routingKey, bindings[b].args)
}
}
_existsConn(conn) {
const connections = this.proton.app.amqp.__connections
let exists = false
for(let c in connections) {
if(_.isEqual(c.params, conn)) {
exists = c.connection
break
}
}
return exists
}
}