UNPKG

node-red-contrib-rabbit-rpc

Version:

mqpt nodes to send and receive messages from rabbit with rpc functionality

232 lines (215 loc) 8.27 kB
var amqp = require('amqplib/callback_api'); module.exports = function (RED) { function RabbitRPCReq(config) { RED.nodes.createNode(this, config); var node = this; node.queueName = config.queueName; node.host = config.host; node.login = config.login; node.pass = config.pass; node.timeout = 30000; node.reconnect = true; node.on('close', function () { console.log("Connection closing due to restart"); node.reconnect = false; node.amqpConn.close(); }) node.opt = { credentials: require('amqplib').credentials.plain(node.login, node.pass) }; connectClient(node); } RED.nodes.registerType("rabbit-rpc-req", RabbitRPCReq); function RabbitRPCServer(config) { RED.nodes.createNode(this, config); var node = this; node.timeout = 10000; // if the connection is closed or fails to be established at all, we will reconnect node.myId = Math.random(); node.amqpConn = null; node.queueName = config.queueName; node.host = config.host; node.login = config.login; node.pass = config.pass; node.opt = { credentials: require('amqplib').credentials.plain(node.login, node.pass) }; node.reconnect = true; node.on('close', function () { console.log("Connection closing due to restart"); node.reconnect = false; node.amqpConn.close(); }) connectServer(node); } RED.nodes.registerType("rabbit-rpc-server", RabbitRPCServer); } function connectServer(node) { amqp.connect(`amqp://${node.host}`, node.opt, function (err, conn) { if (err) { console.error("[AMQP-server]", err.message); return setTimeout(function () { connectServer(node) }, node.timeout); } conn.on("error", function (err) { if (err.message !== "Connection closing") { console.error("[AMQP-server] conn error", err.message); } }); conn.on("close", function () { if (node.reconnect) { console.error("[AMQP-server] reconnecting"); return setTimeout(function () { connectServer(node) }, node.timeout); } }); console.log("[AMQP-server] connected"); node.amqpConn = conn; startListener(node); }); } function startListener(node) { node.amqpConn.createChannel(function (err, channel) { if (closeOnErr(err)) return; channel.on("error", function (err) { console.error("[AMQP-server] channel error", err.message); }); channel.on("close", function () { console.log("[AMQP-server] channel closed"); }); var queue = node.queueName; channel.assertQueue(queue, { //durable: false }); channel.prefetch(1); console.log(' [x] Awaiting RPC requests'); channel.consume(queue, function reply(rabbitMsg) { console.log(' [x] Got %s', rabbitMsg.content.toString()); console.log(node.myId); let msg = { payload: rabbitMsg.content.toString(), replyTo: rabbitMsg.properties.replyTo, correlationId: rabbitMsg.properties.correlationId, nodeId: node.myId }; node.send(msg) channel.ack(rabbitMsg); }); }); } function closeOnErr(err, node) { if (!err) return false; console.error("[AMQP-server] error", err); node.amqpConn.close(); return true; } function generateUuid() { return Math.random().toString() + Math.random().toString() + Math.random().toString(); } function connectClient(node) { amqp.connect(`amqp://${node.host}`, node.opt, function (err, conn) { if (err) { console.error("[AMQP-client]", err.message); return setTimeout(function () { connectClient(node) }, node.timeout); } conn.on("error", function (err) { if (err.message !== "Connection closing") { console.error("[AMQP-client] conn error", err.message); } }); conn.on("close", function () { if (node.reconnect) { console.error("[AMQP-client] reconnecting"); return setTimeout(function () { connectClient(node) }, node.timeout); } }); console.log("[AMQP-client] connected"); node.amqpConn = conn; startClient(node); }); } function startClient(node) { node.on("input", async function (msg) { node.amqpConn.createChannel(function (err, channel) { if (closeOnErr(err)) { return }; channel.on("error", function (err) { channel = null; console.error("[AMQP-client] channel error", err.message); }); channel.on("close", function () { channel = null; console.log("[AMQP-client] channel closed"); }); var correlationId = msg.correlationId || generateUuid(); var num = msg.payload; var queueName = node.queueName; var replyQueue; if (!msg.replyTo) { var timer = setTimeout(function () { if (channel) { try { channel.deleteQueue(replyQueue, {ifEmpty:false}); channel.close(); } catch (e) { node.error(e); } channel = null; console.log("[AMQP-client] timeout"); } //process.exit(0); }, 30000); channel.assertQueue('', { exclusive: true }, function (error2, q) { if (error2) { node.error(error2); return; } replyQueue = q.queue; channel.consume(q.queue, function reply(rabbitMsg) { console.log(' [.] Got %s', rabbitMsg.content.toString()); console.log(node.myId); msg.payload = rabbitMsg.content.toString(), msg.replyTo = rabbitMsg.properties.replyTo, msg.correlationId = rabbitMsg.properties.correlationId, //msg.nodeId: node.myId node.send(msg) clearTimeout(timer); setTimeout(function () { if (channel) { try { channel.ack(rabbitMsg); channel.deleteQueue(replyQueue, {ifEmpty:false}); channel.close(); } catch (e) { node.error(e); } console.log("[AMQP-client] done"); channel = null; } //process.exit(0); }, 500); return; }); channel.sendToQueue(queueName, Buffer.from(num.toString()), { replyTo: q.queue, correlationId: correlationId //headers: headers }); return; }, { noAck: true, consumerTag: correlationId }); return; } else { channel.sendToQueue(msg.replyTo, Buffer.from(num.toString()), { correlationId: correlationId //headers: headers }); channel.close(); return; } }); }); }