Added support for codefile

This commit is contained in:
Steve Walsh 2023-11-09 14:57:53 +00:00
parent c5ee350d7a
commit 7c0ec67015
4 changed files with 1287 additions and 1218 deletions

View File

@ -6,10 +6,13 @@ To make a change to the node-red runtime being used by K4 avalanche:
3. PR into this branch 3. PR into this branch
4. Merge on approval 4. Merge on approval
5. Manually bump the package version 5. Manually bump the package version
6. Run `npm run build` 6. Run `npm run build` - note you need to run node 10 to do this, you also need to have xcode installed
7. Manually publish to NPM with `npm publish` - Request creds from ops for this 7. Manually publish to NPM with `npm publish` - Request creds from ops for this
# Dev Work
When doing dev work dont try to link into k4/k5 it just causes issue, instead just go into the node-modules of k4/k5 and make your changes in there
# CHANGE-LOG # CHANGE-LOG
## 0.18.7-patch-11 ## 0.18.7-patch-11

View File

@ -14,7 +14,8 @@
* limitations under the License. * limitations under the License.
**/ **/
const PayloadValidator = require('../../PayloadValidator') const clone = require("clone");
const PayloadValidator = require("../../PayloadValidator");
module.exports = function (RED) { module.exports = function (RED) {
"use strict"; "use strict";
@ -36,15 +37,25 @@ module.exports = function(RED) {
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 (typeof msg === 'object' && !Buffer.isBuffer(msg) && !util.isArray(msg)) { if (
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)?'Buffer':(util.isArray(msg)?'Array':'Date'); type = Buffer.isBuffer(msg)
? "Buffer"
: util.isArray(msg)
? "Array"
: "Date";
} }
node.error(RED._("function.error.non-message-returned",{ type: type })) node.error(
RED._("function.error.non-message-returned", { type: type })
);
} }
} }
} }
@ -60,7 +71,8 @@ module.exports = function(RED) {
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 results = null;"+ var functionText =
"var results = null;" +
"results = (function(msg){ " + "results = (function(msg){ " +
"var __msgid__ = msg._msgid;" + "var __msgid__ = msg._msgid;" +
"var node = {" + "var node = {" +
@ -73,7 +85,8 @@ module.exports = function(RED) {
"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 = [];
@ -84,7 +97,7 @@ module.exports = function(RED) {
//Buffer:Buffer, //Buffer:Buffer,
//Date: Date, //Date: Date,
RED: { RED: {
util: RED.util util: RED.util,
}, },
__node__: { __node__: {
log: function () { log: function () {
@ -113,7 +126,7 @@ module.exports = function(RED) {
}, },
status: function () { status: function () {
node.status.apply(node, arguments); node.status.apply(node, arguments);
} },
}, },
context: { context: {
set: function () { set: function () {
@ -130,7 +143,7 @@ module.exports = function(RED) {
}, },
get flow() { get flow() {
return node.context().flow; return node.context().flow;
} },
}, },
flow: { flow: {
set: function () { set: function () {
@ -141,7 +154,7 @@ module.exports = function(RED) {
}, },
keys: function () { keys: function () {
return node.context().flow.keys.apply(node, arguments); return node.context().flow.keys.apply(node, arguments);
} },
}, },
// global: { // global: {
// set: function() { // set: function() {
@ -196,37 +209,116 @@ module.exports = function(RED) {
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(){ resolve(value) }, after); sandbox.setTimeout(function () {
resolve(value);
}, after);
}); });
} };
} }
try { try {
this.on("input", function(msg) { this.on("input", async function (msg) {
try { try {
const payloadValidator = new PayloadValidator(msg, this.id) const originalMessage = clone(msg);
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 result = vm2Instance.run(functionText); const result = vm2Instance.run(functionText);
payloadValidator.verify(result) const afterVm2 = process.hrtime(beforeVm2);
payloadValidator.verify(result);
sendResults(this, msg._msgid, result); sendResults(this, msg._msgid, result);
const logger = clone(msg.logger);
let lambdaRequestId;
let {
payload: {
system: { organization },
},
event: {
workers: [{ id: workerId }],
},
} = originalMessage;
const {
settings: {
api: { codefile = false }
},
} = RED;
if (codefile) {
try {
const messageToSend = clone(msg);
delete messageToSend.logger;
const beforeCodefile = process.hrtime();
const {
result: {
Result: { msg: responseMessage },
},
} = await codefile.run({ srcCode: this.func, context: { msg } });
const afterCodefile = process.hrtime(beforeCodefile);
responseMessage.logger = logger;
payloadValidator.verify(responseMessage);
// to make function node return result from code file uncomment this line, and comment out the sendResults above
// sendResults(this,msg._msgid, responseMessage);
workerId = workerId.split(":::")[0];
const nodeId = this.id.split(`${organization}-${workerId}-`)[1];
lambdaRequestId = responseMessage.lambdaRequestId;
const metrics = {
lambdaRequestId: requestId,
organization,
workerId: workerId,
nodeId: nodeId,
rawCode: this.func,
vm2Runtime: `${
Math.floor((afterVm2[0] * 1e9 + afterVm2[1]) / 10000) / 100
}ms`,
codefileRuntime: `${
Math.floor(
(afterCodefile[0] * 1e9 + afterCodefile[1]) / 10000
) / 100
}ms`,
};
logger.info(JSON.stringify(metrics, null, 2));
} catch (e) {
logger.error({
message: "Error running codefile",
error: e,
lambdaRequestId,
organization,
workerId: workerId,
nodeId: nodeId,
rawCode: this.func,
});
}
}
// sendResults(this,msg._msgid, responseMessage);
var duration = process.hrtime(start); var duration = process.hrtime(start);
var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100; var converted =
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(/\n\s*at ContextifyScript.Script.runInContext/); var index = err.stack.search(
err.stack = err.stack.slice(0, index).split('\n').slice(0,-1).join('\n'); /\n\s*at ContextifyScript.Script.runInContext/
);
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
@ -236,7 +328,10 @@ 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 (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) { while (
line < stack.length &&
stack[line].indexOf("ReferenceError") !== 0
) {
line++; line++;
} }
@ -265,13 +360,13 @@ module.exports = function(RED) {
}); });
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
@ -280,4 +375,4 @@ module.exports = function(RED) {
} }
RED.nodes.registerType("function", FunctionNode); RED.nodes.registerType("function", FunctionNode);
RED.library.register("functions"); RED.library.register("functions");
} };

1885
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -97,7 +97,7 @@
"grunt-jsonlint": "~1.1.0", "grunt-jsonlint": "~1.1.0",
"grunt-mocha-istanbul": "5.0.2", "grunt-mocha-istanbul": "5.0.2",
"grunt-nodemon": "~0.4.2", "grunt-nodemon": "~0.4.2",
"grunt-sass": "~2.0.0", "grunt-sass": "^2.0.0",
"grunt-simple-mocha": "~0.4.1", "grunt-simple-mocha": "~0.4.1",
"grunt-webdriver": "^2.0.3", "grunt-webdriver": "^2.0.3",
"http-proxy": "^1.16.2", "http-proxy": "^1.16.2",