mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge pull request #3064 from node-red/revert-external-modules-dir
Move externalModules back into the user dir
This commit is contained in:
@@ -7,36 +7,53 @@
|
||||
padding: 0px;
|
||||
}
|
||||
#node-input-libs-container-row .red-ui-editableList-container li {
|
||||
padding:5px;
|
||||
padding:0px;
|
||||
}
|
||||
#node-input-libs-container-row .red-ui-editableList-item-remove {
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
#node-input-libs-container-row .red-ui-editableList-header {
|
||||
display: flex;
|
||||
background: var(--red-ui-tertiary-background);
|
||||
padding-right: 75px;
|
||||
}
|
||||
#node-input-libs-container-row .red-ui-editableList-header > div {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.node-libs-entry {
|
||||
display: flex;
|
||||
}
|
||||
.node-libs-entry .node-input-libs-var, .node-libs-entry .red-ui-typedInput-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.node-libs-entry > code,.node-libs-entry > span {
|
||||
line-height: 30px;
|
||||
}
|
||||
.node-libs-entry > input[type=text] {
|
||||
border-radius: 0;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 2px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.node-libs-entry > span > i {
|
||||
.node-libs-entry .red-ui-typedInput-container {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
.node-libs-entry .red-ui-typedInput-type-select {
|
||||
border-radius: 0 !important;
|
||||
height: 34px;
|
||||
}
|
||||
.node-libs-entry > span > input[type=text] {
|
||||
border-radius: 0;
|
||||
border-top-color: var(--red-ui-form-background);
|
||||
border-bottom-color: var(--red-ui-form-background);
|
||||
border-right-color: var(--red-ui-form-background);
|
||||
}
|
||||
.node-libs-entry > span > input[type=text].input-error {
|
||||
}
|
||||
.node-libs-entry > span {
|
||||
flex-grow: 1;
|
||||
width: 50%;
|
||||
position: relative;
|
||||
}
|
||||
.node-libs-entry span .node-input-libs-var, .node-libs-entry span .red-ui-typedInput-container {
|
||||
width: 100%;
|
||||
}
|
||||
.node-libs-entry > span > span > i {
|
||||
display: none;
|
||||
}
|
||||
.node-libs-entry > span.input-error > i {
|
||||
.node-libs-entry > span > span.input-error > i {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
@@ -209,47 +226,24 @@
|
||||
})
|
||||
|
||||
var libList = $("#node-input-libs-container").css('min-height','100px').css('min-width','450px').editableList({
|
||||
header: $('<div><div data-i18n="node-red:function.require.moduleName"></div><div data-i18n="node-red:function.require.importAs"></div></div>'),
|
||||
addItem: function(container,i,opt) {
|
||||
var parent = container.parent();
|
||||
var row0 = $("<div/>").addClass("node-libs-entry").appendTo(container);
|
||||
var fieldWidth = "260px";
|
||||
$('<code>const </code>').appendTo(row0);
|
||||
var fvar = $("<input/>", {
|
||||
class: "node-input-libs-var red-ui-font-code",
|
||||
placeholder: RED._("node-red:function.require.var"),
|
||||
type: "text"
|
||||
}).css({
|
||||
width: "120px",
|
||||
"margin-left": "5px"
|
||||
}).appendTo(row0).val(opt.var);
|
||||
var vnameWarning = $('<span style="display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(row0);
|
||||
RED.popover.tooltip(vnameWarning.find("i"),function() {
|
||||
var val = fvar.val();
|
||||
if (invalidModuleVNames.indexOf(val) !== -1) {
|
||||
return RED._("node-red:function.error.moduleNameReserved",{name:val})
|
||||
} else {
|
||||
return RED._("node-red:function.error.moduleNameError",{name:val})
|
||||
}
|
||||
})
|
||||
|
||||
$('<code> = require(</code>').appendTo(row0);
|
||||
var fmoduleSpan = $("<span>").appendTo(row0);
|
||||
var fmodule = $("<input/>", {
|
||||
class: "node-input-libs-val",
|
||||
placeholder: RED._("node-red:function.require.module"),
|
||||
type: "text"
|
||||
}).css({
|
||||
width: "180px",
|
||||
}).appendTo(row0).typedInput({
|
||||
}).appendTo(fmoduleSpan).typedInput({
|
||||
types: typedModules,
|
||||
default: usedModules.indexOf(opt.module) > -1 ? opt.module : "_custom_"
|
||||
});
|
||||
if (usedModules.indexOf(opt.module) === -1) {
|
||||
fmodule.typedInput('value', opt.module);
|
||||
}
|
||||
|
||||
$('<code>)</code>').appendTo(row0);
|
||||
|
||||
var moduleWarning = $('<span style="display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(row0);
|
||||
var moduleWarning = $('<span style="position: absolute;right:2px;top:7px; display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(fmoduleSpan);
|
||||
RED.popover.tooltip(moduleWarning.find("i"),function() {
|
||||
var val = fmodule.typedInput("type");
|
||||
if (val === "_custom_") {
|
||||
@@ -264,6 +258,26 @@
|
||||
}
|
||||
})
|
||||
|
||||
var fvarSpan = $("<span>").appendTo(row0);
|
||||
|
||||
var fvar = $("<input/>", {
|
||||
class: "node-input-libs-var red-ui-font-code",
|
||||
placeholder: RED._("node-red:function.require.var"),
|
||||
type: "text"
|
||||
}).css({
|
||||
}).appendTo(fvarSpan).val(opt.var);
|
||||
var vnameWarning = $('<span style="position: absolute; right:2px;top:7px;display:inline-block; width: 16px;"><i class="fa fa-warning"></i></span>').appendTo(fvarSpan);
|
||||
RED.popover.tooltip(vnameWarning.find("i"),function() {
|
||||
var val = fvar.val();
|
||||
if (invalidModuleVNames.indexOf(val) !== -1) {
|
||||
return RED._("node-red:function.error.moduleNameReserved",{name:val})
|
||||
} else {
|
||||
return RED._("node-red:function.error.moduleNameError",{name:val})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
fvar.on("change keyup paste", function (e) {
|
||||
var v = $(this).val().trim();
|
||||
if (v === "" || / /.test(v) || invalidModuleVNames.indexOf(v) !== -1) {
|
||||
@@ -280,7 +294,7 @@
|
||||
if (val === "_custom_") {
|
||||
val = $(this).val();
|
||||
}
|
||||
var varName = val.trim().replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/]./g, function(v) { return v[1].toUpperCase() });
|
||||
var varName = val.trim().replace(/^@/,"").replace(/@.*$/,"").replace(/[-_/].?/g, function(v) { return v[1]?v[1].toUpperCase():"" });
|
||||
fvar.val(varName);
|
||||
fvar.trigger("change");
|
||||
|
||||
|
@@ -290,6 +290,7 @@ module.exports = function(RED) {
|
||||
};
|
||||
sandbox.promisify = util.promisify;
|
||||
}
|
||||
const moduleLoadPromises = [];
|
||||
|
||||
if (node.hasOwnProperty("libs")) {
|
||||
let moduleErrors = false;
|
||||
@@ -303,25 +304,21 @@ module.exports = function(RED) {
|
||||
return;
|
||||
}
|
||||
sandbox[vname] = null;
|
||||
try {
|
||||
var spec = module.module;
|
||||
if (spec && (spec !== "")) {
|
||||
var lib = RED.require(module.module);
|
||||
var spec = module.module;
|
||||
if (spec && (spec !== "")) {
|
||||
moduleLoadPromises.push(RED.import(module.module).then(lib => {
|
||||
sandbox[vname] = lib;
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO: NLS error message
|
||||
node.error(RED._("function.error.moduleLoadError",{module:module.spec, error:e.toString()}))
|
||||
moduleErrors = true;
|
||||
}).catch(err => {
|
||||
node.error(RED._("function.error.moduleLoadError",{module:module.spec, error:err.toString()}))
|
||||
throw err;
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
if (moduleErrors) {
|
||||
throw new Error(RED._("function.error.externalModuleLoadError"));
|
||||
}
|
||||
throw new Error(RED._("function.error.externalModuleLoadError"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const RESOLVING = 0;
|
||||
const RESOLVED = 1;
|
||||
const ERROR = 2;
|
||||
@@ -337,165 +334,168 @@ module.exports = function(RED) {
|
||||
processMessage(msg, send, done);
|
||||
}
|
||||
});
|
||||
|
||||
var context = vm.createContext(sandbox);
|
||||
try {
|
||||
var iniScript = null;
|
||||
var iniOpt = null;
|
||||
if (node.ini && (node.ini !== "")) {
|
||||
var iniText = `
|
||||
(async function(__send__) {
|
||||
var node = {
|
||||
id:__node__.id,
|
||||
name:__node__.name,
|
||||
outputCount:__node__.outputCount,
|
||||
log:__node__.log,
|
||||
error:__node__.error,
|
||||
warn:__node__.warn,
|
||||
debug:__node__.debug,
|
||||
trace:__node__.trace,
|
||||
status:__node__.status,
|
||||
send: function(msgs, cloneMsg) {
|
||||
__node__.send(__send__, RED.util.generateId(), msgs, cloneMsg);
|
||||
}
|
||||
};
|
||||
`+ node.ini +`
|
||||
})(__initSend__);`;
|
||||
iniOpt = createVMOpt(node, " setup");
|
||||
iniScript = new vm.Script(iniText, iniOpt);
|
||||
}
|
||||
node.script = vm.createScript(functionText, createVMOpt(node, ""));
|
||||
if (node.fin && (node.fin !== "")) {
|
||||
var finText = `(function () {
|
||||
var node = {
|
||||
id:__node__.id,
|
||||
name:__node__.name,
|
||||
outputCount:__node__.outputCount,
|
||||
log:__node__.log,
|
||||
error:__node__.error,
|
||||
warn:__node__.warn,
|
||||
debug:__node__.debug,
|
||||
trace:__node__.trace,
|
||||
status:__node__.status,
|
||||
send: function(msgs, cloneMsg) {
|
||||
__node__.error("Cannot send from close function");
|
||||
}
|
||||
};
|
||||
`+node.fin +`
|
||||
})();`;
|
||||
finOpt = createVMOpt(node, " cleanup");
|
||||
finScript = new vm.Script(finText, finOpt);
|
||||
}
|
||||
var promise = Promise.resolve();
|
||||
if (iniScript) {
|
||||
context.__initSend__ = function(msgs) { node.send(msgs); };
|
||||
promise = iniScript.runInContext(context, iniOpt);
|
||||
}
|
||||
|
||||
processMessage = function (msg, send, done) {
|
||||
var start = process.hrtime();
|
||||
context.msg = msg;
|
||||
context.__send__ = send;
|
||||
context.__done__ = done;
|
||||
|
||||
node.script.runInContext(context);
|
||||
context.results.then(function(results) {
|
||||
sendResults(node,send,msg._msgid,results,false);
|
||||
if (handleNodeDoneCall) {
|
||||
done();
|
||||
}
|
||||
|
||||
var duration = process.hrtime(start);
|
||||
var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100;
|
||||
node.metric("duration", msg, converted);
|
||||
if (process.env.NODE_RED_FUNCTION_TIME) {
|
||||
node.status({fill:"yellow",shape:"dot",text:""+converted});
|
||||
}
|
||||
}).catch(err => {
|
||||
if ((typeof err === "object") && err.hasOwnProperty("stack")) {
|
||||
//remove unwanted part
|
||||
var index = err.stack.search(/\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/);
|
||||
|
||||
//store the error in msg to be used in flows
|
||||
msg.error = err;
|
||||
|
||||
var line = 0;
|
||||
var errorMessage;
|
||||
if (stack.length > 0) {
|
||||
while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) {
|
||||
line++;
|
||||
Promise.all(moduleLoadPromises).then(() => {
|
||||
var context = vm.createContext(sandbox);
|
||||
try {
|
||||
var iniScript = null;
|
||||
var iniOpt = null;
|
||||
if (node.ini && (node.ini !== "")) {
|
||||
var iniText = `
|
||||
(async function(__send__) {
|
||||
var node = {
|
||||
id:__node__.id,
|
||||
name:__node__.name,
|
||||
outputCount:__node__.outputCount,
|
||||
log:__node__.log,
|
||||
error:__node__.error,
|
||||
warn:__node__.warn,
|
||||
debug:__node__.debug,
|
||||
trace:__node__.trace,
|
||||
status:__node__.status,
|
||||
send: function(msgs, cloneMsg) {
|
||||
__node__.send(__send__, RED.util.generateId(), msgs, cloneMsg);
|
||||
}
|
||||
};
|
||||
`+ node.ini +`
|
||||
})(__initSend__);`;
|
||||
iniOpt = createVMOpt(node, " setup");
|
||||
iniScript = new vm.Script(iniText, iniOpt);
|
||||
}
|
||||
node.script = vm.createScript(functionText, createVMOpt(node, ""));
|
||||
if (node.fin && (node.fin !== "")) {
|
||||
var finText = `(function () {
|
||||
var node = {
|
||||
id:__node__.id,
|
||||
name:__node__.name,
|
||||
outputCount:__node__.outputCount,
|
||||
log:__node__.log,
|
||||
error:__node__.error,
|
||||
warn:__node__.warn,
|
||||
debug:__node__.debug,
|
||||
trace:__node__.trace,
|
||||
status:__node__.status,
|
||||
send: function(msgs, cloneMsg) {
|
||||
__node__.error("Cannot send from close function");
|
||||
}
|
||||
};
|
||||
`+node.fin +`
|
||||
})();`;
|
||||
finOpt = createVMOpt(node, " cleanup");
|
||||
finScript = new vm.Script(finText, finOpt);
|
||||
}
|
||||
var promise = Promise.resolve();
|
||||
if (iniScript) {
|
||||
context.__initSend__ = function(msgs) { node.send(msgs); };
|
||||
promise = iniScript.runInContext(context, iniOpt);
|
||||
}
|
||||
|
||||
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+")";
|
||||
processMessage = function (msg, send, done) {
|
||||
var start = process.hrtime();
|
||||
context.msg = msg;
|
||||
context.__send__ = send;
|
||||
context.__done__ = done;
|
||||
|
||||
node.script.runInContext(context);
|
||||
context.results.then(function(results) {
|
||||
sendResults(node,send,msg._msgid,results,false);
|
||||
if (handleNodeDoneCall) {
|
||||
done();
|
||||
}
|
||||
|
||||
var duration = process.hrtime(start);
|
||||
var converted = Math.floor((duration[0] * 1e9 + duration[1])/10000)/100;
|
||||
node.metric("duration", msg, converted);
|
||||
if (process.env.NODE_RED_FUNCTION_TIME) {
|
||||
node.status({fill:"yellow",shape:"dot",text:""+converted});
|
||||
}
|
||||
}).catch(err => {
|
||||
if ((typeof err === "object") && err.hasOwnProperty("stack")) {
|
||||
//remove unwanted part
|
||||
var index = err.stack.search(/\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/);
|
||||
|
||||
//store the error in msg to be used in flows
|
||||
msg.error = err;
|
||||
|
||||
var line = 0;
|
||||
var errorMessage;
|
||||
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();
|
||||
}
|
||||
done(errorMessage);
|
||||
}
|
||||
if (!errorMessage) {
|
||||
errorMessage = err.toString();
|
||||
else if (typeof err === "string") {
|
||||
done(err);
|
||||
}
|
||||
else {
|
||||
done(JSON.stringify(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
node.on("close", function() {
|
||||
if (finScript) {
|
||||
try {
|
||||
finScript.runInContext(context, finOpt);
|
||||
}
|
||||
catch (err) {
|
||||
node.error(err);
|
||||
}
|
||||
done(errorMessage);
|
||||
}
|
||||
else if (typeof err === "string") {
|
||||
done(err);
|
||||
while (node.outstandingTimers.length > 0) {
|
||||
clearTimeout(node.outstandingTimers.pop());
|
||||
}
|
||||
else {
|
||||
done(JSON.stringify(err));
|
||||
while (node.outstandingIntervals.length > 0) {
|
||||
clearInterval(node.outstandingIntervals.pop());
|
||||
}
|
||||
if (node.clearStatus) {
|
||||
node.status({});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
node.on("close", function() {
|
||||
if (finScript) {
|
||||
try {
|
||||
finScript.runInContext(context, finOpt);
|
||||
}
|
||||
catch (err) {
|
||||
node.error(err);
|
||||
}
|
||||
}
|
||||
while (node.outstandingTimers.length > 0) {
|
||||
clearTimeout(node.outstandingTimers.pop());
|
||||
}
|
||||
while (node.outstandingIntervals.length > 0) {
|
||||
clearInterval(node.outstandingIntervals.pop());
|
||||
}
|
||||
if (node.clearStatus) {
|
||||
node.status({});
|
||||
}
|
||||
});
|
||||
|
||||
promise.then(function (v) {
|
||||
var msgs = messages;
|
||||
messages = [];
|
||||
while (msgs.length > 0) {
|
||||
msgs.forEach(function (s) {
|
||||
processMessage(s.msg, s.send, s.done);
|
||||
});
|
||||
msgs = messages;
|
||||
promise.then(function (v) {
|
||||
var msgs = messages;
|
||||
messages = [];
|
||||
}
|
||||
state = RESOLVED;
|
||||
}).catch((error) => {
|
||||
messages = [];
|
||||
state = ERROR;
|
||||
node.error(error);
|
||||
});
|
||||
while (msgs.length > 0) {
|
||||
msgs.forEach(function (s) {
|
||||
processMessage(s.msg, s.send, s.done);
|
||||
});
|
||||
msgs = messages;
|
||||
messages = [];
|
||||
}
|
||||
state = RESOLVED;
|
||||
}).catch((error) => {
|
||||
messages = [];
|
||||
state = ERROR;
|
||||
node.error(error);
|
||||
});
|
||||
|
||||
}
|
||||
catch(err) {
|
||||
// eg SyntaxError - which v8 doesn't include line number information
|
||||
// so we can't do better than this
|
||||
updateErrorInfo(err);
|
||||
node.error(err);
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
// eg SyntaxError - which v8 doesn't include line number information
|
||||
// so we can't do better than this
|
||||
updateErrorInfo(err);
|
||||
node.error(err);
|
||||
}
|
||||
}).catch(err => {
|
||||
throw new Error(RED._("function.error.externalModuleLoadError"));
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("function",FunctionNode, {
|
||||
dynamicModuleList: "libs",
|
||||
|
Reference in New Issue
Block a user