How to embed multiple instances of node-red in node app - node.js

Node-red documentation here gives info on how to embed a single node-red app inside a nodejs app - http://nodered.org/docs/embedding
We wanted our site's users to have their own node-red's on different ports for some custom programming. Is it possible to embed multiple node-red apps in a nodejs applicaiton?
I tried repeating same steps for embedding by changing settings of each call with different port but only one time it is created. First time, a node-red instance is created based on settings. Next time we call, we get port in use. I assume this has something to do with node require doing caching and all... Any workaround for this issue?

If you're interested I created a fork of the node-red project allowing this feature.
this is how you would initiate it:
var http = require('http');
var express = require("express");
var RED = require("node-red")();
var RED2 = require("node-red")();
// Create an Express app
var app = express();
// Add a simple route for static content served from 'public'
app.use("/",express.static("public"));
// Create a server
var server = http.createServer(app);
// Create the settings object - see default settings.js file for other options
var settings = {
httpAdminRoot:"/red1",
httpNodeRoot: "/api",
userDir:"./hhh",
functionGlobalContext: { } // enables global context
};
// Initialise the runtime with a server and settings
RED.init(server,settings);
console.log(RED2.settings === RED.settings, 888, RED2.settings.userSettings);
// Serve the editor UI from /red
app.use(settings.httpAdminRoot,RED.httpAdmin);
// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot,RED.httpNode);
server.listen(8005);
// Start the runtime
RED.start();
var app2 = express();
app2.use("/",express.static("public"));
var server2 = http.createServer(app2);
var settings2 = {
httpAdminRoot:"/red2",
httpNodeRoot: "/api",
userDir:"./hhhh",
functionGlobalContext: { }
};
RED2.init(server2,settings2);
app2.use(settings2.httpAdminRoot,RED2.httpAdmin);
app2.use(settings2.httpNodeRoot,RED2.httpNode);
RED2.start();
server2.listen(8006);
console.log(RED.settings.httpAdminRoot);
console.log(RED2.settings.httpAdminRoot);
console.log(RED2.settings === RED.settings);
also, works on the same port. but make sure to use different paths is so.
https://github.com/aryeharmon/node-red

No, currently Node-RED has no multi-user capabilities and no way to instantiate multiple instances in one process.
You'll have to run separate instances of the application for each user. Have a look at something like FRED for an example of this. This runs individual instances and proxies them to make the integration look like it's all on the same port/domain

Related

Best Practice to create REST APIs using node.js

I am from .Net and C# background and I am new to Node.js. I am working on a project, which is mix of MongoDB and Node.JS.
In MongoDB, data from various tools is stored in different different collections. I have to create multiple REST APIs using Node.JS for CRUD operation on that data, these APIs will be called from React.JS application.
I want to keep APIs into separate files for seperate tool and then calling including all files into app.js file.
Please help me with best approach.
For POC purpose, I created a node.js application, where I created app.js file and written all my code for GET|POST|DELETE APIs. This is working fine.
var _expressPackage = require("express");
var _bodyParserPackage = require("body-parser");
var _sqlPackage = require("mssql");
var app = _expressPackage();
var cors = require("cors");
var auth = require('basic-auth');
var fs = require('fs');
const nodeMailer = require('nodemailer');
//Lets set up our local server now.
var server = app.listen(process.env.PORT || 4000, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
app.get("/StudentList", function(_req ,_res){
console.log("Inside StudentList");
var Sqlquery = "select * from tbl_Host where HostId='1'";
GetQueryToExecuteInDatabase(_req,_res, Sqlquery,function(err,data){
console.log(data);
});
});
Don't know exactly what your app intends to do, but usually if you are not serving webpages and your API is not too complex, there is no need to use express. You can build a simple server natively in NodeJS to serve data.
Additionally, if your app has many routes (or is likely to in the future), it is a good idea to put helper functions like GetQueryToExecuteInDatabase() in a separate file outside of app.js such as utils.js.
Based on what I have understood about what you want to do, your file structure should look something like this:
data (db related files)
services (contains one file per api service)
app.js
utils.js
Hope this helps.

Add domains to NodeJS Express http server on the fly

I'm hosting multiple domains each running the same node app using Express vhost. I start them all using http.createServer
var app = express();
require('./app.js')(function(theApp) {
app.use(express.vhost(domainName1, theApp));
app.use(express.vhost(domainName2, theApp));
app.use(express.vhost(domainName3, theApp));
var d = domain.create();
d.run(function(){
http.createServer(app).listen(80);
});
});
Is it possible to do the same thing but be able to add new domains to the server on the fly without having to restart the node application? IE pseudo-code:
Do the above
Wait for a Domains database record to be added
Add a new vhost
Restart necessary things
I want to make sure that users of the existing domains get as little down-time as possible (or even none) whilst the new domain is added.
The default Express behavior is to not discriminate based on the Host header. The vhost middleware adds this behavior. You probably could add more middleware whenever you discover a new domain you want to support… or you could just not discriminate on the Host header in the first place:
var app = express();
require('./app.js')(function(theApp) {
app.use(theApp);
var d = domain.create();
d.run(function(){
http.createServer(app).listen(80);
});
});

heroku: route subdirectory to a second node.js app?

I have a heroku node.js app running under the domain foo.com. I want to proxy all urls beginning with foo.com/bar/ to a second node.js process - but I want the process to be controlled within the same heroku app. Is this possible?
If not, is it possible to proxy a subdirectory to a second heroku app? I haven't been able to find much control over how to do routing outside of the web app's entry point. That is, I can easily control routing within node.js using Express for example, but that doesn't let me proxy to a different app.
My last resort is simply using a subdomain instead of a subdirectory, but I'd like to see if a subdirectory is possible first. Thanks!
Edit: I had to solve my problem using http-proxy. I have two express servers listening on different ports and then a third externally facing server that routes to either of the two depending on the url. Not ideal of course, but I couldn't get anything else to work. The wrap-app2 approach described below had some url issues that I couldn't figure out.
Just create a new express server and put a middleware in the main one to redirect to the secondary when comes a request to your desired path:
var app2 = express();
app2.use(function(req, res){
res.send('Hey, I\'m another express server');
});
app.use('/foo', app2);
I haven't tried it yet in Heroku, but it the same process and doesn't create any new TCP binding or process, so It will work. For reference, a modified plain express template.
And if you really want other express process handling the connection, you need to use cluster. Check the worker.send utility.
app.use('/foo', function(req,res){
//You can send req too if you want.
worker.send('foo', res);
});
This is possible. The most elegant way I could think is by using clustering. 1 Heroku Dyno contains four cores. Therefore, you can run four worker threads to a node process.
Here is an introduction to clustering.
What you're looking at is initializing two express apps (assuming you're using express) and serving those two in two worker threads.
if (cluster.isMaster) {
// let's make four child processes
for (var i = 0; i < 4; i++) {
if (i%2 == 0) {
cluster.fork(envForApp1);
} else {
cluster.fork(envForApp2);
}
}
} else {
// refer to NODE_ENV and see whether this should be your app1 or app2
// which should be started. This is passed from the fork() before.
app.listen(8080);
}

Can I define Express routes in a child process?

So I run a bunch of a little chatbots written in node, nothing too exciting. However, I recently decided to give them their own little web page to display information in a graphical manner. To do this, I figured I'd just run express.
However, I'm running my bots with a wrapper file that starts each chatbot as a child process. Which makes using express a little tricky. Currently I'm starting the express server in the wrapper.js file like so:
var express = require("express");
var web = express();
web.listen(3001);
And then in the child processes, I'm doing this:
var express = require("express");
var web = express();
web.get("/urlforbot",function (req,res) {
res.send("Working!");
});
However, when I navigate to :3001/urlforbot, I get Cannot GET /urlforbot.
Any idea what I'm doing wrong and how to fix this?
Edit: This is my complete wrapper file: http://snippi.com/s/3vn56m2
Edit 2: This is what I'm doing now. I'm hosting each bot on it's own port, and storing that information in the configs. This is the code I'm using, and it appears to be working:
web.get("/"+cfg.route, function (req,res) { // forward the data
res.redirect('http://url.com:'+cfg.port+"/"+cfg.route);
});
Since your bots run as separate processes (any particular reason?), you have to treat each one as having to implement their own HTTP server with Express:
var express = require("express");
var web = express();
web.get("/urlforbot",function (req,res) {
res.send("Working!");
});
web.listen(UNIQUE_PORT_NUMBER);
Each bot process needs to listen on a unique port number, it can't be shared.
Next, you need to map requests coming in on port 3001 in the 'master' process to the correct child process' Express server.
node-http-proxy has a useful option called a ProxyTable with which to create such a mapping, but it requires the master process to know what the endpoint (/urlforbot in your terms) for each bot is. It also requires that the master knows on which port the bots are listening.
EDIT: alternatively, you can use child_process.fork to fork a new process for each of your bots, and communicate between them and the master process (port numbers and such, or even all the data required to generate the /urlforbot pages) using the comm channel that Node provides, but that still sounds like an overly complex setup.
Wouldn't it be possible to create a Bot class instead? You'd instantiate the class for each bot you want to run, and that instance loads its specific configuration and adds its routes to the Express server. All from the same process.

Sharing Node App and Connect's port

Is there any way to get Connect to run on the same port as your node app so you can serve up assets using relative or absolute paths?
Right now I have them running on separate ports, which is a pain:
var app = require('http').createServer(handler).listen(81),
connect = require('connect');
connect.createServer(
connect.static(__dirname + '/assets')
).listen(82);
Let connect create the server for you:
var connect=require('connect'),
app=connect.createServer(handler,
connect.static(__dirname+"/assets"))
.listen(81);
Only other difference is that handler now takes a third parameter, next, which is a function that handler should call if it doesn't want to handle the request itself but rather wants to pass it on to the static handler (or anything else implemented via connect).

Resources