Pre code styling

This commit is contained in:
Steve Walsh
2023-11-09 15:09:03 +00:00
parent 893eb2007f
commit 1aa0e89de9

View File

@@ -15,146 +15,134 @@
**/ **/
const clone = require("clone"); const clone = require("clone");
const PayloadValidator = require("../../PayloadValidator"); const PayloadValidator = require('../../PayloadValidator')
module.exports = function (RED) { module.exports = function(RED) {
"use strict"; "use strict";
var util = require("util"); var util = require("util");
var vm2 = require("vm2"); var vm2 = require("vm2");
function sendResults(node, _msgid, msgs) { function sendResults(node,_msgid,msgs) {
if (msgs == null) { if (msgs == null) {
return; return;
} else if (!util.isArray(msgs)) { } else if (!util.isArray(msgs)) {
msgs = [msgs]; msgs = [msgs];
} }
var msgCount = 0; var msgCount = 0;
for (var m = 0; m < msgs.length; m++) { for (var m=0; m<msgs.length; m++) {
if (msgs[m]) { if (msgs[m]) {
if (!util.isArray(msgs[m])) { if (!util.isArray(msgs[m])) {
msgs[m] = [msgs[m]]; msgs[m] = [msgs[m]];
} }
for (var n = 0; n < msgs[m].length; n++) { for (var n=0; n < msgs[m].length; n++) {
var msg = msgs[m][n]; var msg = msgs[m][n];
if (msg !== null && msg !== undefined) { if (msg !== null && msg !== undefined) {
if ( if (typeof msg === 'object' && !Buffer.isBuffer(msg) && !util.isArray(msg)) {
typeof msg === "object" &&
!Buffer.isBuffer(msg) &&
!util.isArray(msg)
) {
msg._msgid = _msgid; msg._msgid = _msgid;
msgCount++; msgCount++;
} else { } else {
var type = typeof msg; var type = typeof msg;
if (type === "object") { if (type === 'object') {
type = Buffer.isBuffer(msg) type = Buffer.isBuffer(msg)?'Buffer':(util.isArray(msg)?'Array':'Date');
? "Buffer"
: util.isArray(msg)
? "Array"
: "Date";
} }
node.error( node.error(RED._("function.error.non-message-returned",{ type: type }))
RED._("function.error.non-message-returned", { type: type })
);
} }
} }
} }
} }
} }
if (msgCount > 0) { if (msgCount>0) {
node.send(msgs); node.send(msgs);
} }
} }
function FunctionNode(n) { function FunctionNode(n) {
RED.nodes.createNode(this, n); RED.nodes.createNode(this,n);
var node = this; var node = this;
this.name = n.name; this.name = n.name;
this.func = n.func; this.func = n.func;
var functionText = var functionText = "var results = null;"+
"var results = null;" + "results = (function(msg){ "+
"results = (function(msg){ " + "var __msgid__ = msg._msgid;"+
"var __msgid__ = msg._msgid;" + "var node = {"+
"var node = {" + "log:__node__.log,"+
"log:__node__.log," + "error:__node__.error,"+
"error:__node__.error," + "warn:__node__.warn,"+
"warn:__node__.warn," + "debug:__node__.debug,"+
"debug:__node__.debug," + "trace:__node__.trace,"+
"trace:__node__.trace," + "on:__node__.on,"+
"on:__node__.on," + "status:__node__.status,"+
"status:__node__.status," + "send:function(msgs){ __node__.send(__msgid__,msgs);}"+
"send:function(msgs){ __node__.send(__msgid__,msgs);}" + "};\n"+
"};\n" + this.func+"\n"+
this.func +
"\n" +
"})(msg);"; "})(msg);";
this.topic = n.topic; this.topic = n.topic;
this.outstandingTimers = []; this.outstandingTimers = [];
this.outstandingIntervals = []; this.outstandingIntervals = [];
var sandbox = { var sandbox = {
console: console, console: console,
util: util, util:util,
//Buffer:Buffer, //Buffer:Buffer,
//Date: Date, //Date: Date,
RED: { RED: {
util: RED.util, util: RED.util
}, },
__node__: { __node__: {
log: function () { log: function() {
node.log.apply(node, arguments); node.log.apply(node, arguments);
}, },
error: function () { error: function() {
node.error.apply(node, arguments); node.error.apply(node, arguments);
}, },
warn: function () { warn: function() {
node.warn.apply(node, arguments); node.warn.apply(node, arguments);
}, },
debug: function () { debug: function() {
node.debug.apply(node, arguments); node.debug.apply(node, arguments);
}, },
trace: function () { trace: function() {
node.trace.apply(node, arguments); node.trace.apply(node, arguments);
}, },
send: function (id, msgs) { send: function(id, msgs) {
sendResults(node, id, msgs); sendResults(node, id, msgs);
}, },
on: function () { on: function() {
if (arguments[0] === "input") { if (arguments[0] === "input") {
throw new Error(RED._("function.error.inputListener")); throw new Error(RED._("function.error.inputListener"));
} }
node.on.apply(node, arguments); node.on.apply(node, arguments);
}, },
status: function () { status: function() {
node.status.apply(node, arguments); node.status.apply(node, arguments);
}, }
}, },
context: { context: {
set: function () { set: function() {
node.context().set.apply(node, arguments); node.context().set.apply(node,arguments);
}, },
get: function () { get: function() {
return node.context().get.apply(node, arguments); return node.context().get.apply(node,arguments);
}, },
keys: function () { keys: function() {
return node.context().keys.apply(node, arguments); return node.context().keys.apply(node,arguments);
}, },
get global() { get global() {
return node.context().global; return node.context().global;
}, },
get flow() { get flow() {
return node.context().flow; return node.context().flow;
}, }
}, },
flow: { flow: {
set: function () { set: function() {
node.context().flow.set.apply(node, arguments); node.context().flow.set.apply(node,arguments);
}, },
get: function () { get: function() {
return node.context().flow.get.apply(node, arguments); return node.context().flow.get.apply(node,arguments);
},
keys: function () {
return node.context().flow.keys.apply(node, arguments);
}, },
keys: function() {
return node.context().flow.keys.apply(node,arguments);
}
}, },
// global: { // global: {
// set: function() { // set: function() {
@@ -170,155 +158,131 @@ module.exports = function (RED) {
setTimeout: function () { setTimeout: function () {
var func = arguments[0]; var func = arguments[0];
var timerId; var timerId;
arguments[0] = function () { arguments[0] = function() {
sandbox.clearTimeout(timerId); sandbox.clearTimeout(timerId);
try { try {
func.apply(this, arguments); func.apply(this,arguments);
} catch (err) { } catch(err) {
node.error(err, {}); node.error(err,{});
} }
}; };
timerId = setTimeout.apply(this, arguments); timerId = setTimeout.apply(this,arguments);
node.outstandingTimers.push(timerId); node.outstandingTimers.push(timerId);
return timerId; return timerId;
}, },
clearTimeout: function (id) { clearTimeout: function(id) {
clearTimeout(id); clearTimeout(id);
var index = node.outstandingTimers.indexOf(id); var index = node.outstandingTimers.indexOf(id);
if (index > -1) { if (index > -1) {
node.outstandingTimers.splice(index, 1); node.outstandingTimers.splice(index,1);
} }
}, },
setInterval: function () { setInterval: function() {
var func = arguments[0]; var func = arguments[0];
var timerId; var timerId;
arguments[0] = function () { arguments[0] = function() {
try { try {
func.apply(this, arguments); func.apply(this,arguments);
} catch (err) { } catch(err) {
node.error(err, {}); node.error(err,{});
} }
}; };
timerId = setInterval.apply(this, arguments); timerId = setInterval.apply(this,arguments);
node.outstandingIntervals.push(timerId); node.outstandingIntervals.push(timerId);
return timerId; return timerId;
}, },
clearInterval: function (id) { clearInterval: function(id) {
clearInterval(id); clearInterval(id);
var index = node.outstandingIntervals.indexOf(id); var index = node.outstandingIntervals.indexOf(id);
if (index > -1) { if (index > -1) {
node.outstandingIntervals.splice(index, 1); node.outstandingIntervals.splice(index,1);
}
} }
},
}; };
if (util.hasOwnProperty("promisify")) { if (util.hasOwnProperty('promisify')) {
sandbox.setTimeout[util.promisify.custom] = function (after, value) { sandbox.setTimeout[util.promisify.custom] = function(after, value) {
return new Promise(function (resolve, reject) { return new Promise(function(resolve, reject) {
sandbox.setTimeout(function () { sandbox.setTimeout(function(){ resolve(value) }, after);
resolve(value);
}, after);
}); });
}; }
} }
try { try {
this.on("input", async function (msg) { this.on("input", async function(msg) {
try { try {
const originalMessage = clone(msg); const orginalMessage= clone(msg)
const payloadValidator = new PayloadValidator(msg, this.id); const payloadValidator = new PayloadValidator(msg, this.id)
var start = process.hrtime(); var start = process.hrtime();
sandbox.msg = msg; sandbox.msg = msg;
const vm2Instance = new vm2.VM({ sandbox, timeout: 5000 }); const vm2Instance = new vm2.VM({ sandbox, timeout: 5000 });
const beforeVm2 = process.hrtime(); const beforeVm2 = process.hrtime();
const result = vm2Instance.run(functionText); const result = vm2Instance.run(functionText);
const afterVm2 = process.hrtime(beforeVm2); const afterVm2 = process.hrtime(beforeVm2);
payloadValidator.verify(result); payloadValidator.verify(result)
sendResults(this, msg._msgid, result); sendResults(this,msg._msgid, result);
const logger = clone(msg.logger); const logger = clone(msg.logger)
let lambdaRequestId; let lambdaRequestId;
let { let {
payload: { payload: {
system: { organization }, system: {
organization,
}
}, },
event: { event: {
workers: [{ id: workerId }], workers: [{ id: workerId }]
}, }
} = originalMessage; } = orginalMessage
try{
const { const messageToSend = clone(msg)
settings: { delete messageToSend.logger
api: { codefile = false },
},
} = RED;
if (codefile) {
try {
const messageToSend = clone(msg);
delete messageToSend.logger;
const { settings: {api:{codefile}}} = RED
// record how long this takes to run
const beforeCodefile = process.hrtime(); const beforeCodefile = process.hrtime();
const { const {result:{Result:{msg: responseMessage}}} = await codefile.run({srcCode: this.func, context: {msg}})
result: {
Result: { msg: responseMessage },
},
} = await codefile.run({ srcCode: this.func, context: { msg } });
const afterCodefile = process.hrtime(beforeCodefile); const afterCodefile = process.hrtime(beforeCodefile);
responseMessage.logger = logger; responseMessage.logger = logger
payloadValidator.verify(responseMessage); payloadValidator.verify(responseMessage)
// to make function node return result from code file uncomment this line, and comment out the sendResults above // to make function node return result from code file uncomment this line, and comment out the sendResults above
// sendResults(this,msg._msgid, responseMessage); // sendResults(this,msg._msgid, responseMessage);
workerId = workerId.split(":::")[0]; workerId = workerId.split(':::')[0];
const nodeId = this.id.split(`${organization}-${workerId}-`)[1]; const nodeId = this.id.split(`${organization}-${workerId}-`)[1];
lambdaRequestId = responseMessage.lambdaRequestId; lambdaRequestId = responseMessage.lambdaRequestId
const metrics = { const metrics = {
lambdaRequestId: requestId, lambdaRequestId: requestId,
organization, organization,
workerId: workerId, workerId: workerId,
nodeId: nodeId, nodeId: nodeId,
rawCode: this.func, rawCode: this.func,
vm2Runtime: `${ vm2Runtime: `${Math.floor((afterVm2[0] * 1e9 + afterVm2[1])/10000)/100}ms`,
Math.floor((afterVm2[0] * 1e9 + afterVm2[1]) / 10000) / 100 codefileRuntime: `${Math.floor((afterCodefile[0] * 1e9 + afterCodefile[1])/10000)/100}ms`
}ms`, }
codefileRuntime: `${ logger.info(JSON.stringify(metrics, null, 2))
Math.floor( }catch(e){
(afterCodefile[0] * 1e9 + afterCodefile[1]) / 10000
) / 100
}ms`,
};
logger.info(JSON.stringify(metrics, null, 2));
} catch (e) {
logger.error({ logger.error({
message: "Error running codefile", message:'Error running codefile',
error: e, error: e,
lambdaRequestId, lambdaRequestId,
organization, organization,
workerId: workerId, workerId: workerId,
nodeId: nodeId, nodeId: nodeId,
rawCode: this.func, rawCode: this.func,
}); })
}
} }
// sendResults(this,msg._msgid, responseMessage); // sendResults(this,msg._msgid, responseMessage);
var duration = process.hrtime(start); var duration = process.hrtime(start);
var converted = var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100;
Math.floor((duration[0] * 1e9 + duration[1]) / 10000) / 100;
this.metric("duration", msg, converted); this.metric("duration", msg, converted);
if (process.env.NODE_RED_FUNCTION_TIME) { if (process.env.NODE_RED_FUNCTION_TIME) {
this.status({ fill: "yellow", shape: "dot", text: "" + converted }); this.status({fill:"yellow",shape:"dot",text:""+converted});
} }
} catch (err) { } catch(err) {
//remove unwanted part //remove unwanted part
var index = err.stack.search( var index = err.stack.search(/\n\s*at ContextifyScript.Script.runInContext/);
/\n\s*at ContextifyScript.Script.runInContext/ err.stack = err.stack.slice(0, index).split('\n').slice(0,-1).join('\n');
);
err.stack = err.stack
.slice(0, index)
.split("\n")
.slice(0, -1)
.join("\n");
var stack = err.stack.split(/\r?\n/); var stack = err.stack.split(/\r?\n/);
//store the error in msg to be used in flows //store the error in msg to be used in flows
@@ -328,20 +292,17 @@ module.exports = function (RED) {
var errorMessage; var errorMessage;
var stack = err.stack.split(/\r?\n/); var stack = err.stack.split(/\r?\n/);
if (stack.length > 0) { if (stack.length > 0) {
while ( while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) {
line < stack.length &&
stack[line].indexOf("ReferenceError") !== 0
) {
line++; line++;
} }
if (line < stack.length) { if (line < stack.length) {
errorMessage = stack[line]; errorMessage = stack[line];
var m = /:(\d+):(\d+)$/.exec(stack[line + 1]); var m = /:(\d+):(\d+)$/.exec(stack[line+1]);
if (m) { if (m) {
var lineno = Number(m[1]) - 1; var lineno = Number(m[1])-1;
var cha = m[2]; var cha = m[2];
errorMessage += " (line " + lineno + ", col " + cha + ")"; errorMessage += " (line "+lineno+", col "+cha+")";
} }
} }
} }
@@ -358,21 +319,21 @@ module.exports = function (RED) {
this.error(errorMessage, msg); this.error(errorMessage, msg);
} }
}); });
this.on("close", function () { this.on("close", function() {
while (node.outstandingTimers.length > 0) { while (node.outstandingTimers.length > 0) {
clearTimeout(node.outstandingTimers.pop()); clearTimeout(node.outstandingTimers.pop())
} }
while (node.outstandingIntervals.length > 0) { while (node.outstandingIntervals.length > 0) {
clearInterval(node.outstandingIntervals.pop()); clearInterval(node.outstandingIntervals.pop())
} }
this.status({}); this.status({});
}); })
} catch (err) { } catch(err) {
// eg SyntaxError - which v8 doesn't include line number information // eg SyntaxError - which v8 doesn't include line number information
// so we can't do better than this // so we can't do better than this
this.error(err); this.error(err);
} }
} }
RED.nodes.registerType("function", FunctionNode); RED.nodes.registerType("function",FunctionNode);
RED.library.register("functions"); RED.library.register("functions");
}; }