UNPKG

prisme-flow

Version:

prisme platform flow engine

276 lines (263 loc) 7.82 kB
/** * Created by prisme.io on 09/06/2017. */ module.exports = function (RED) { 'use strict' var q = require('q') var util = require('util') var vm = require('vm') var child_process = require('child_process') var request = require('request') var Queue = require('bull') function QueueServerSetup (n) { RED.nodes.createNode(this, n) this.connected = false this.connecting = false this.usecount = 0 // Config node state this.name = n.name this.address = n.address this.port = n.port var node = this this.register = function () { node.usecount += 1 } this.deregister = function () { node.usecount -= 1 if (node.usecount == 0) { } } this.connect = function () { var deferred = q.defer() if (!node.connected && !node.connecting) { node.connecting = true node.queue = Queue(node.name, node.port, node.address) node.log(RED._('connected', { server: (node.address ? node.address + '@' : '') + node.port })) node.connecting = false node.connected = true node.emit('connected') deferred.resolve(node.queue) } else { if (node.queue) { deferred.resolve(node.queue) } } return deferred.promise } this.on('close', function (closecomplete) { if (this.connected) { this.on('disconnected', function () { closecomplete() }) node.queue.close().then(function () { node.log(RED._('closed')) }) } else { closecomplete() } }) } RED.nodes.registerType('queue-server', QueueServerSetup) function sendResults (node, _msgid, msgs) { if (msgs == null) { return } else if (!util.isArray(msgs)) { msgs = [msgs] } var msgCount = 0 for (var m = 0; m < msgs.length; m++) { if (msgs[m]) { if (util.isArray(msgs[m])) { for (var n = 0; n < msgs[m].length; n++) { msgs[m][n]._msgid = _msgid msgCount++ } } else { msgs[m]._msgid = _msgid msgCount++ } } } if (msgCount > 0) { node.send(msgs) } }; function QueueCmdNode (n) { RED.nodes.createNode(this, n) var node = this this.name = n.name this.queue = n.queue this.cmd = n.cmd this.Queue = RED.nodes.getNode(this.queue) this.topic = n.topic if (node.Queue) { node.Queue.register() node.Queue.connect().then(function (queue) { node.status({ fill: 'green', shape: 'ring', text: 'connected' }) }, function (error) { node.status({ fill: 'red', shape: 'ring', text: 'disconnected' }) }) } else { node.error(RED._('common.status.error')) } try { this.on('input', function (msg) { node.Queue.connect().then(function (queue) { switch (parseInt(node.cmd)) { case 0: node.log(RED._('queue.add()', node.cmd)) queue.add(msg, { name: node.name, topic: node.topic }) break case 1: node.log(RED._('queue.pause()', node.cmd)) queue.pause() break case 2: node.log(RED._('queue.resume()', node.cmd)) queue.resume() break default: node.log(RED._('queue.default()', node.cmd)) break } }, function (error) { node.status({ fill: 'red', shape: 'ring', text: 'disconnected' }) }) }) } catch (err) { // eg SyntaxError - which v8 doesn't include line number information // so we can't do better than this this.error(err) } } function QueueRunNode (n) { RED.nodes.createNode(this, n) var node = this this.name = n.name this.func = n.func this.queue = n.queue this.topic = n.topic this.timeout = n.timeout this.Queue = RED.nodes.getNode(this.queue) var functionText = 'var results = null;' + 'results = (function(msg){ ' + 'var __msgid__ = msg._msgid;' + 'var node = {' + 'log:__node__.log,' + 'error:__node__.error,' + 'warn:__node__.warn,' + 'on:__node__.on,' + 'status:__node__.status,' + 'send:function(msgs){ __node__.send(__msgid__,msgs);}' + '};\n' + this.func + '\n' + '})(msg);' var sandbox = { console: console, util: util, Buffer: Buffer, __node__: { log: function () { node.log.apply(node, arguments) }, error: function () { node.error.apply(node, arguments) }, warn: function () { node.warn.apply(node, arguments) }, send: function (id, msgs) { sendResults(node, id, msgs) }, on: function () { node.on.apply(node, arguments) }, status: function () { node.status.apply(node, arguments) } }, context: { global: RED.settings.functionGlobalContext || {} }, setTimeout: setTimeout, clearTimeout: clearTimeout } var context = vm.createContext(sandbox) if (node.Queue) { node.Queue.register() node.script = vm.createScript(functionText) node.Queue.connect().then(function (queue) { queue.process(function (job, completed) { node.log(RED._('queue.run()', job)) try { var start = process.hrtime() context.msg = job.data context.job = job context.done = function (error, results) { sendResults(node, node.name, results) error = error || null completed(error, results) } context.request = request context.child_process = child_process node.script.runInContext(context) sendResults(node, node.name, context.results) var duration = process.hrtime(start) var converted = Math.floor((duration[0] * 1e9 + duration[1]) / 10000) / 100 node.metric('duration', node.name, converted) if (process.env.NODE_RED_FUNCTION_TIME) { node.status({ fill: 'yellow', shape: 'dot', text: '' + converted }) } } catch (err) { var line = 0 var errorMessage var stack = err.stack.split(/\r?\n/) if (stack.length > 0) { while (line < stack.length && stack[line].indexOf('ReferenceError') !== 0) { line++ } if (line < stack.length) { errorMessage = stack[line] var m = /:(\d+):(\d+)$/.exec(stack[line + 1]) if (m) { var lineno = Number(m[1]) - 1 var cha = m[2] errorMessage += ' (line ' + lineno + ', col ' + cha + ')' } } } if (!errorMessage) { errorMessage = err.toString() } node.error(errorMessage, node.name) } }) node.status({ fill: 'green', shape: 'ring', text: 'connected' }) }, function (error) { node.status({ fill: 'red', shape: 'ring', text: 'disconnected' }) }) } else { node.error(RED._('common.status.error')) } } RED.nodes.registerType('queue cmd', QueueCmdNode) RED.nodes.registerType('queue run', QueueRunNode) RED.library.register('functions') }