Dynamic node invocation

Is it possible to create a custom node, that based on some input to invoke dynamically other nodes in Nodered?

Question first:

Why? the point of node-red is a graphical flow based environment. Doing this would make things "under the hood" occur and make tracing issues verry difficult.

There is already the link-call node that can call to other link-in nodes dynamically (by name) so I am not certain what you are asking is a good idea when you can mostly achieve something similar give the existing mechanisms.

1 Like

the WHY part is a longer story :slight_smile:

I am more interested in how to achieve it technically. the WHY is explained bellow.

we are trying to use nodered for some general task automation thingy
The custom node would let the user specify a list of commands (as input to a custom nodered node) and based on them it would invoke some nodered nodes because this is how we have some of the functionality implemented. I just work on a POC for our PO, trying out if this is feasible in this way or not (even if it is not the brightest idea but we already have a lot of functionality encapsulated in custom nodered nodes :roll_eyes: )

A lot depends on whether you are developing the nodes to be executed yourself or whether you are wanting to use existing node-red nodes.

Because Node-RED is one big Node.js app, it is certainly possible to achieve if you have control of the nodes you wish to call. Not so easy (maybe not possible?) if you need to be able to trigger any node.

Not sure how this differs from dynamic link-call?

inject (user sets up an array of "things to call")
:arrow_down:
split node
:arrow_down:
set link target
:arrow_down:
call a flow dynamically

[{"id":"d3104102381c0861","type":"inject","z":"70a9fc5b046fbfdd","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"target\":\"flow 99\"},{\"target\":\"flow 1\",\"payload\":[1,2,3]},{\"target\":\"another flow\",\"payload\":\"some value\"},{\"target\":\"flow 1\",\"payload\":[50,75]}]","payloadType":"json","x":1070,"y":100,"wires":[["10866f9c9ad4000b"]]},{"id":"10866f9c9ad4000b","type":"split","z":"70a9fc5b046fbfdd","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":1200,"y":100,"wires":[["48a6d81b34bed794"]]},{"id":"48a6d81b34bed794","type":"change","z":"70a9fc5b046fbfdd","name":"","rules":[{"t":"set","p":"target","pt":"msg","to":"payload.target","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"payload.payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1360,"y":100,"wires":[["442ff2d15e14e773","fe13049086d810c9"]]},{"id":"442ff2d15e14e773","type":"link call","z":"70a9fc5b046fbfdd","name":"","links":[],"linkType":"dynamic","timeout":"3","x":1550,"y":100,"wires":[["7302f327e9657079"]]},{"id":"7302f327e9657079","type":"debug","z":"70a9fc5b046fbfdd","name":"result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1690,"y":100,"wires":[]},{"id":"e0a562c6ec0e0ce8","type":"link in","z":"70a9fc5b046fbfdd","name":"flow 1","links":[],"x":1160,"y":200,"wires":[["662c1b9502c1beb4"]],"l":true},{"id":"c124487507701469","type":"link out","z":"70a9fc5b046fbfdd","name":"link out 1","mode":"return","links":[],"x":1585,"y":200,"wires":[]},{"id":"662c1b9502c1beb4","type":"function","z":"70a9fc5b046fbfdd","name":"multiply array elements by 10","func":"node.warn(`Someone called \"${msg.target}\" dynamically & passed in a payload of ${JSON.stringify(msg.payload)}!`)\nmsg.payload = msg.payload.map( e => e * 10 )\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1370,"y":200,"wires":[["c124487507701469"]]},{"id":"31dca68009752801","type":"link in","z":"70a9fc5b046fbfdd","name":"another flow","links":[],"x":1140,"y":260,"wires":[["995ffced473a78d9"]],"l":true},{"id":"85333b1a6c551af2","type":"link out","z":"70a9fc5b046fbfdd","name":"link out 2","mode":"return","links":[],"x":1585,"y":260,"wires":[]},{"id":"995ffced473a78d9","type":"function","z":"70a9fc5b046fbfdd","name":"concat payload with \" WOOHOO\"","func":"node.warn(`Someone called \"${msg.target}\" dynamically & passed in a payload of ${msg.payload}!`)\nmsg.payload += \" WOOHOO\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1390,"y":260,"wires":[["85333b1a6c551af2"]]},{"id":"84c541e9a780a740","type":"function","z":"70a9fc5b046fbfdd","name":"get the time NOW","func":"node.warn(`Someone called \"${msg.target}\" dynamically!`)\nmsg.payload = new Date()\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1340,"y":320,"wires":[["2edf0dc154752d23"]]},{"id":"b4c222a5ab769c5b","type":"link in","z":"70a9fc5b046fbfdd","name":"flow 99","links":[],"x":1160,"y":320,"wires":[["84c541e9a780a740"]],"l":true},{"id":"2edf0dc154752d23","type":"link out","z":"70a9fc5b046fbfdd","name":"link out 3","mode":"return","links":[],"x":1585,"y":320,"wires":[]},{"id":"fe13049086d810c9","type":"debug","z":"70a9fc5b046fbfdd","name":"Dynamic call","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"{\t    \"calling\": target,\t    \"with-payload\": payload\t}","targetType":"jsonata","statusVal":"","statusType":"auto","x":1490,"y":140,"wires":[]}]
3 Likes

I agree that routing link-calls to existing nodes is the best & safest way.
There is a possibility for a custom node to transform itself dynamically, by loading and then executing JS code in runtime. But this is a huge security breach.

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.