Is it possible to use NR-Runtime without http server?

sorry,a newbie here with a newbie question
i noticed the latest version NR has split editor and runtime,that's awsone!
and i am planing to make a game server logic design by editor with nodes drag-n-drop, then export the logic flows configs via runtime.flows.getFlows(), then i am thinking embed the runtime into my game server, that maybe not use any http server, but the runtime.init ( settings, server, adminApi ) look need a server as the second parameter. is that possible to just ignore that parameter?
thanks

Well you can certainly embed the whole of Node-RED into your own ExpressJS server - but I don't know about just the runtime I'm afraid. Check the docs on running Node-RED as an embedded platform to get you started.

thanks for your reply
my point is
is it possible to treat Node-RED as a STANDALONE LOGIC PROCESS COMPONENT, i feed(input) the data through calling specific custom methods,like call mehods on a normal component(instance),then Node-RED process the data inside, so that there no need to use any http server, cause for that "Node-RED component", there is no need to expose out for API or web browser visiting. there is no editor ui, no auth action, server is unnecessary, is that alright?

after a few hours researching, i figured out that run Node-RED runtime only is very easy
write down a simple test with a repeat 'hello world' msg a code like this

var flows=[{"id":"dc77e143.33e97","type":"tab","label":"flow2","disabled":false,"info":""},{"id":"7bd58677.985428","type":"debug","z":"dc77e143.33e97","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","x":476,"y":289,"wires":[]},{"id":"32ec7bb.86cd484","type":"inject","z":"dc77e143.33e97","name":"","topic":"","payload":"hello world","payloadType":"str","repeat":"1","crontab":"","once":true,"onceDelay":0.1,"x":237,"y":254,"wires":[["7bd58677.985428"]]}];
var r=require('node-red');
r.init(null,{httpAdminRoot:false})
r.start().then(()=>{
        r.runtime.flows.setFlows({flows:{flows}});
    })

meanwhile found and fixed a bug

next step is found a communication way, so far i know i can use TCP,UDP,WEBSOCKET... network nodes and set Node-RED as server, let outside logic to be a client and do some remote call like RPC. maybe there is a directly way to just send message to an entry node

2 Likes

Nice, well done for working it out. Bookmarking this for future reference.

As you probably realised, I've never gone beyond embedding the full NR into my own Node.js app.

In regard to your second question though, it kind of depends what kind of data you are trying to pass through. You may also be able to use UNIX pipes. I would think, however, that other than pipes, the lowest overhead would be UDP. But if you want to separate out the comms to multiple machines then MQTT or websockets might be better. Also depends of course as to whether you need continuous comms or periodic, the expected throughput and the data size/complexity you expect.

So many choices!

well, after few hours more researching
i found a way to directly send msg to the specify node.
every component needs a main entry, for data input.
suppose thers is an inject node we set the name is 'entry', and accept json data

// use flows api to get flows and then found the node object config which name is 'entry'
    var {flows: nodeObjects} = await r.runtime.flows.getFlows();
    var foundNodeObject = nodeObjects.find((f) => (f.name == 'entry'))
    
//well,you can use another way to find the entry node object config,via eachNode method,
//however, the offical code in eachNode does not have a break,(yes,that's just EACH means)
//maybe add a new function called 'findNode' just like Array.find do would be nice

    // var foundNodeObject;
    // await r.runtime._.nodes.eachNode((n) => {
    //     if (n.name == 'entry') {
    //         foundNodeObject = n;
    //         return true; //(useless in eachNode method,but ok with findNode(if it exisit) )
    //     }
    // })

//one big confusion for newbie like me is, you got know some methods return the node config object,like the methods above, 
//some methods is return the node object (instance), like the getNode method below.
    var foundNode = await r.runtime._.nodes.getNode(foundNodeObject.id);
//if you want change the payload,if the entry inject node js a send msg repeatly,changing payload works
    //foundNode.payload = JSON.stringify({msg: "world hello"})
//or if you just want send a message once,as a normal component and drive by outside data feed,use this method is meanful
     foundNode.send(JSON.stringify({msg: "world hello"}));

full code is like this

var flows = [{"id": "dc77e143.33e97", "type": "tab", "label": "流程2", "disabled": false, "info": ""},
{"id": "7bd58677.985428", "type": "debug", "z": "dc77e143.33e97", "name": "", "active": true, "tosidebar": true, "console": true, "tostatus": false, "complete": "true", "x": 476, "y": 289, "wires": []},
{"id": "32ec7bb.86cd484", "type": "inject", "z": "dc77e143.33e97", "name": "entry", "topic": "", "payload": "{\"msg\":\"hello world\"}", "payloadType": "json", "repeat": "1", "crontab": "", "once": true, "onceDelay": 0.1, "x": 217, "y": 254, "wires": [["7bd58677.985428"]]}]

var r = require('node-red');
r.init(null, {httpAdminRoot: false})
r.start().then(() => {
    r.runtime.flows.setFlows({flows: {flows}}).then(
        async () => {
            var {flows: nodeObjects} = await r.runtime.flows.getFlows();
            var foundNodeObject = nodeObjects.find((f) => (f.name == 'entry'))
            var foundNode = await r.runtime._.nodes.getNode(foundNodeObject.id);
            foundNode.payload = JSON.stringify({msg: "world hello"})
            // foundNode.send(JSON.stringify({msg: "world hello"}));
        })
})

BUT WAIT!! it's just a one way communcation, how about return the data that processed inside the Node-RED to outside app? emmmm....i need more hours researching again...

Well, few hours later in last day i found let message out is simple via a PROXY GLOBAL PROPERTY
first in NODE-RED,i set some code in a function node like this

if(global.get("outterFunc"))
    global.get("outterFunc")(msg)


then in out side app,i just set the outterFunc to be some outside function like

var {flows: nodeObjects} = await r.runtime.flows.getFlows();
var foundNodeObject = nodeObjects.find((f) => (f.name == 'entry'))
var foundNode = await r.runtime._.nodes.getNode(foundNodeObject.id);
//node.context().global is the same as inside global,so,the context can be share some variables like a function named "outterFunc"
foundNode.context().global.set("outterFunc", function (msg) {console.log("outter function says:" + JSON.stringify(msg))})
//emit some data to entry inject node,so that outterFunc would be call in next node
foundNode.send({msg: "world hello"});

then it looks i open a new gate to a new world, so later hours, i try to work out a simple blackjack game server side logic

FINAL CONCLUSION
with my shallow experiences, i have to say,Node-RED is nice for visual of process flow, but it's hard to debug and manage the project,especially for some large projects.it is a wonderful tool for work flow explaination, simple tasks, even program education.
if i insist to use it for a complex project,i will consider to place data and all the related management functions outside of Node-RED,but using it as a simple flow controller in development,(as a flow controller,it is nice to explain to everyone in my team,how our app would work) in that case, at least i can set a breakpoint and debug easily in my IDE. then if Node-RED is too expensive to performence(so far i saw flows have been saved in hard-disc as json file even i just run the runtime programmly, Express instance has been created, even i didn't use any http server things), i will consider about use or not use it then.
hope v1.0 have some supprises

thanks for NODE-RED team guys, for this great product. i read the history, it is a honor that we both have the same idea in same period,i try to achieve a kind-of things in adobe flash once.

1 Like