1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00
node-red/nodes/core/core/80-function.js

225 lines
8.1 KiB
JavaScript
Raw Normal View History

2013-09-05 16:02:48 +02:00
/**
* Copyright 2013,2015 IBM Corp.
2013-09-05 16:02:48 +02:00
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
2014-05-04 00:32:04 +02:00
module.exports = function(RED) {
2014-07-08 13:27:09 +02:00
"use strict";
2014-05-04 00:32:04 +02:00
var util = require("util");
var vm = require("vm");
2014-05-05 09:58:53 +02:00
2015-03-17 14:40:12 +01:00
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);
}
}
2014-05-04 00:32:04 +02:00
function FunctionNode(n) {
RED.nodes.createNode(this,n);
var node = this;
2014-05-04 00:32:04 +02:00
this.name = n.name;
this.func = n.func;
2015-03-17 14:40:12 +01:00
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,"+
2015-10-15 14:33:01 +02:00
"status:__node__.status,"+
2015-03-17 14:40:12 +01:00
"send:function(msgs){ __node__.send(__msgid__,msgs);}"+
"};\n"+
this.func+"\n"+
"})(msg);";
2014-05-04 00:32:04 +02:00
this.topic = n.topic;
this.outstandingTimers = [];
this.outstandingIntervals = [];
var sandbox = {
console:console,
util:util,
Buffer:Buffer,
2015-03-17 14:40:12 +01:00
__node__: {
log: function() {
node.log.apply(node, arguments);
},
2015-10-15 14:33:01 +02:00
error: function() {
node.error.apply(node, arguments);
},
warn: function() {
node.warn.apply(node, arguments);
2015-03-17 14:40:12 +01:00
},
2015-10-15 14:33:01 +02:00
send: function(id, msgs) {
sendResults(node, id, msgs);
2015-03-17 14:40:12 +01:00
},
on: function() {
2015-10-15 14:33:01 +02:00
node.on.apply(node, arguments);
},
status: function() {
node.status.apply(node, arguments);
}
},
context: {
set: function() {
node.context().set.apply(node,arguments);
},
get: function() {
return node.context().get.apply(node,arguments);
},
get global() {
return node.context().global;
},
get flow() {
return node.context().flow;
}
},
flow: {
set: function() {
node.context().flow.set.apply(node,arguments);
},
get: function() {
return node.context().flow.get.apply(node,arguments);
}
},
global: {
set: function() {
node.context().global.set.apply(node,arguments);
},
get: function() {
return node.context().global.get.apply(node,arguments);
}
2015-03-17 14:40:12 +01:00
},
setTimeout: function () {
var func = arguments[0];
var timerId;
arguments[0] = function() {
sandbox.clearTimeout(timerId);
try {
func.apply(this,arguments);
} catch(err) {
node.error(err,{});
}
};
timerId = setTimeout.apply(this,arguments);
node.outstandingTimers.push(timerId);
return timerId;
},
clearTimeout: function(id) {
clearTimeout(id);
var index = node.outstandingTimers.indexOf(id);
if (index > -1) {
node.outstandingTimers.splice(index,1);
}
},
setInterval: function() {
var func = arguments[0];
var timerId;
arguments[0] = function() {
try {
func.apply(this,arguments);
} catch(err) {
node.error(err,{});
}
};
timerId = setInterval.apply(this,arguments);
node.outstandingIntervals.push(timerId);
return timerId;
},
clearInterval: function(id) {
clearInterval(id);
var index = node.outstandingIntervals.indexOf(id);
if (index > -1) {
node.outstandingIntervals.splice(index,1);
}
}
};
var context = vm.createContext(sandbox);
2014-05-04 00:32:04 +02:00
try {
this.script = vm.createScript(functionText);
this.on("input", function(msg) {
2014-09-08 22:10:06 +02:00
try {
var start = process.hrtime();
context.msg = msg;
this.script.runInContext(context);
2015-03-17 14:40:12 +01:00
sendResults(this,msg._msgid,context.results);
2015-02-04 11:01:46 +01:00
var duration = process.hrtime(start);
2015-10-15 14:33:01 +02:00
var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100;
2015-02-04 11:01:46 +01:00
this.metric("duration", msg, converted);
if (process.env.NODE_RED_FUNCTION_TIME) {
this.status({fill:"yellow",shape:"dot",text:""+converted});
2014-09-08 22:10:06 +02:00
}
} catch(err) {
var line = 0;
var errorMessage;
var stack = err.stack.split(/\r?\n/);
if (stack.length > 0) {
2015-10-15 14:33:01 +02:00
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) {
2015-10-15 14:33:01 +02:00
var lineno = Number(m[1])-1;
var cha = m[2];
2015-10-15 14:33:01 +02:00
errorMessage += " (line "+lineno+", col "+cha+")";
}
}
}
if (!errorMessage) {
errorMessage = err.toString();
}
2015-03-16 14:58:01 +01:00
this.error(errorMessage, msg);
2014-05-05 09:58:53 +02:00
}
2014-05-04 00:32:04 +02:00
});
this.on("close", function() {
while(node.outstandingTimers.length > 0) {
clearTimeout(node.outstandingTimers.pop())
}
while(node.outstandingIntervals.length > 0) {
clearInterval(node.outstandingIntervals.pop())
}
})
2014-05-04 00:32:04 +02:00
} catch(err) {
// eg SyntaxError - which v8 doesn't include line number information
// so we can't do better than this
2014-05-04 00:32:04 +02:00
this.error(err);
}
2013-09-05 16:02:48 +02:00
}
2014-05-04 00:32:04 +02:00
RED.nodes.registerType("function",FunctionNode);
RED.library.register("functions");
2013-09-05 16:02:48 +02:00
}