fa-comm
Version:
214 lines (203 loc) • 8.44 kB
JavaScript
const fac = require('../../index');
const amqp = require('amqplib');
const EventEmitter = require('events');
module.exports = {
/**
* 获取RabbitMQ连接
* @param {STRING|JSON} option 连接参数
* @returns 连接成功返回连接对象,连接失败返回null
*/
'createRabbitMqConn': function (option) {
return new Promise(function (resolve, reject) {
option = option || "amqp://guest:guest@127.0.0.1:5672";
if (typeof option != "string") {
option = {
user: option.user || (option.username || 'guest'),
password: option.password || (option.pwd || 'guest'),
host: option.host || (option.url || '127.0.0.1'),
port: option.port || '5672'
};
option = `amqp://${option.user}:${option.password}@${option.host}:${option.port}`;
}
// option = `amqp://guest:guest@172.16.1.8:5672`;
// amqp.connect(option);
amqp.connect(option).then(function (conn) {
conn._hosts = option;
conn.declareChannel = _declareChannel;
console.info(`open rabbitmq ${option} connection success`.toInfo());
resolve(conn);
}).catch(function (e) {
console.error(`open rabbitmq ${option} connection error:${e}`.toError());
reject(e);
});
});
}
};
/**
* 获取RabbitMQ通道
* @param {*} conn 连接对象
* @returns RabbitMQ通道
*/
function _declareChannel(name) {
name = name || fac.guid.guid22();
let self = this;
return new Promise(function (resolve, reject) {
self.createChannel().then(function (channel) {
channel._name = name;
channel._conn = self;
channel.declareQueue = _declareQueue;
channel.delQueue = _deleteQueue;
channel.declareExchange = _declareExchange;
channel.send = _send;
console.info(`declare rabbitmq ${self._hosts} channel ${name} success`.toInfo());
resolve(channel);
}).catch(function (e) {
console.error(`declare rabbitmq ${self._hosts} channel ${name} error:${e}`.toError());
// resolve(null);
reject(e);
});
});
}
/**
* 声明交换机
* @param {*} name 交换机名称
* @param {*} type 交换机类型(topic/fanout/direct/headers)
* 1)Direct,翻译过来就是”直接的”,方式类似于点对点投递,建立Binding时候依赖于exchangeName,queueName、routingKey,消息投递的时候,只需要依赖于exchangeName和routingKey就能分发到被绑定的Queue中。
* 2)Topic类型的Exchange通过支持通配符的RoutingKey管理复杂的发布订阅关系,发送消息时指定的RoutingKey必须是点号(.)分隔的单词 "#"代表0个或者多个关键字。 "*"表示一个关键字。
* 3)对于Fanout类型的Exchange,只要有消息投递到该exchange,它会分发这个消息到所有绑定在它上面的队列,也就是routingKey对于Fanout类型的Exchange是无意义的,但是在声明队列Binding到Fanout类型的Exchange的时候,routingKey不能为null,随便写个值例如空字符串也是可以的,在发送消息的时候也是这样。
* 4)Headers类型的Exchanges是不处理路由键的,而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到RabbitMQ时会取到该消息的headers与Exchange绑定时指定的键值对进行匹配;如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers属性是一个键值对,可以是Hashtable,键值对的值可以是任何类型。
* @returns 交换机对象
*/
function _declareExchange(name, type) {
type = type || "topic";
let self = this;
return new Promise(function (resolve, reject) {
self.assertExchange(name, type, {
durable: true,
autoDelete: false
}).then(function (mqExchange) {
console.info(`declare rabbitmq ${self._conn._hosts} exchange ${name}(${type}) success`.toInfo());
mqExchange._name = name;
mqExchange._type = type;
mqExchange._channel = self;
mqExchange.declareProducer = _declareProducer;
resolve(mqExchange);
}).catch(function (e) {
console.error(`declare rabbitmq ${self._conn._hosts} exchange ${name}(${type}) error:${e}`.toError());
// resolve(null);
reject(e);
});
});
}
/**
* 声明生产者
* @returns
*/
function _declareProducer() {
let self = this;
return new Promise(function (resolve, reject) {
resolve({
_exchange: self,
publish: _publish
});
});
}
/**
* 发布消息到交换机
* @param {*} message 消息内容
* @param {*} routeKey 路由键
* @param {*} options
* @returns true/false
*/
function _publish(message, routeKey, options) {
let self = this;
return new Promise(function (resolve, reject) {
let result = self._exchange._channel.publish(self._exchange._name, routeKey || "#", message, options);
console.info(`publish message ${message} to exchange ${self._exchange._name}(${routeKey}) ${result ? 'success' : 'failed'}`.toInfo());
resolve(result);
});
}
/**
* 声明队列
* @param {String} name 队列名称
* @returns 队列对象
*/
function _declareQueue(name) {
let self = this;
return new Promise(function (resolve, reject) {
self.assertQueue(name).then(function (mqQueue) {
mqQueue._name = name;
mqQueue._channel = self;
mqQueue.bindExchange = _bindExchange;
mqQueue.consume = _consume;
// mqQueue.send = _sendToQueue;
console.info(`declare rabbitmq ${self._conn._hosts} queue ${name} success`.toInfo());
resolve(mqQueue);
}).catch(function (e) {
console.error(`declare rabbitmq ${self._conn._hosts} queue ${name} error:${e}`.toError());
// resolve(null);
reject(e);
});
});
}
/**
* 发送消息到指定队列
* @param {*} message
* @param {*} queue
* @returns
*/
function _send(message, queue) {
let self = this;
return new Promise(function (resolve, reject) {
self.sendToQueue((queue && queue.name ? queue.name : queue), message);
resolve();
});
}
/**
* 删除队列
* @param {*} name
* @returns
*/
function _deleteQueue(name) {
let self = this;
return self.deleteQueue(name);
}
/**
* 将队列绑定到交换机
* @param {*} exchange 交换机对象或交换机名称
* @param {String} routerKey 路由键
* @returns true/false
*/
function _bindExchange(exchange, routerKey) {
let self = this;
exchange = exchange && exchange._name ? exchange._name : (exchange || "");
return new Promise(function (resolve, reject) {
self._channel.bindQueue(self._name, exchange, routerKey || "#").then(function (r) {
console.info(`bind queue ${self._name} to exchange ${exchange} by rabbitmq ${self._channel._conn._hosts} ${r ? 'success' : 'failed'}`.toInfo());
resolve(r);
}).catch(function (e) {
console.error(`bind queue ${self._name} to exchange ${exchange} by rabbitmq ${self._channel._conn._hosts} error:${e}`.toError());
// resolve(false);
reject(e);
});
});
}
/**
* 获取消费者对象
* @returns consumer对象,可以通过消费者对象的事件(msg)监听,获得队列消息,例如:consumer.on('msg',function(msg){});
*/
function _consume() {
let self = this;
class MyEmitter extends EventEmitter { }
let myEmitter = new MyEmitter();
return new Promise(function (resolve, reject) {
self._channel.consume(self._name, function (msg) {
if (msg) {
self._channel.ack(msg);
let data = msg.content;
myEmitter.emit('msg', data);
}
});
resolve(myEmitter);
});
}