How do I maintain multi tenant data base connections nodejs - javascript

Let's say I have a service app.js. Whenever a new client connects to the service , we will check if a mongodb connection is already establish for this client or not.
If it is not available then we will fetch the server ip, dbname ,collection name from a configuration file, connect to the db,and reply to the user.
Note: we can add a new client and corresponding info to Client Info at any time. (dynamically)
Client Info ClientId: ServerIp : Database Name :Collection Name I have tried to store mongo object in array so I can reuse them object based on database name from user's session data. But I keep running into circular json error. How do I store multi tenant database connections?
async.eachSeries(conf.clientDbs.clientsList, function(clientDetails,callback){
console.log(clientDetails);
mongodb.MongoClient.connect(conf.clientDbs.connection+clientDetails.dbName, function (err, database) {
if (err) {
console.log(err);
process.exit(1);
}
// Save database object from the callback for reuse.
var tempdbobj = {};
tempdbobj["obj"] = database
allDbs[clientDetails.team_id] = tempdbobj;
console.log("Database connection ready for "+clientDetails.team_id);
allDbs[clientDetails.team_id].obj.collection('collection_name').find({"ref_id":"111"}, function(dberr, testDoc){
if (dberr) {
console.log(dberr);
callback();
}
else {
console.log(testDoc);
callback();
}
});
});
});

Related

Emit event for particular user if login functionality in application in Socket.io with Node.js

I have used methods socket.on and io.emit, And i got response to all users. But, i want to get response for particular user.
But my application contains login functionality and i followed this post on stackoverflow, and they are saying we need unique userId and socketId in an object for a particular user to emit an event for a particular user.
But i am getting the userId after login, But we want it when user connect to app.
So can anyone please help me with the same?
In your node.js, create a global array 'aryUser', each element contains the socketid and loginid.
node.js onConnect (new connection), add a new element to the array with the socketid and set loginid = empty.
after the user login, emit an event from client to the server, e.g:
socket.emit('userloginok', loginid)
in node.js, define a function:
socket.on('userloginok', loginid)
and in this function, search the aryUser with the socketid and replace the empty loginid inside the array element with the parm loginid.
in node.js, define the function:
socket.on('disconnect')
and in this function, search the aryUser, use aryUser.splice(i,1) to remove the user just disconnected.
that means, aryUser contains all users connected, some of them logined, some of them not logined. And you can use the socketid of the array to send message to particular user, and/or all users.
Example Source Code:
server.js
http://www.zephan.top/server.js
server.html
http://www.zephan.top/server.html.txt
rename server.html.txt to server.html, put server.html and server.js in the same directory, and run:
node server.js
Yes, you definitely need socketId in order to send and receive messages between two specific users.
UserId is required just to keep track of socketId associated with the particular user or you can manage it with some other way as well that's up to you.
As per your question, you have userId of the user and you need socketId of that user! So, in this case, you can pass userId when that particular connects to a socket server from the client side as shown in below snippet,
const socket = io(this.SOCKET_SERVER_BASE_URL, { query: `userId=${userId}` });
And you can read this user on nodejs server like this,
const userId= socket.request._query['userId'],
const socketId= socket.id
Now store this socketId in somewhere, for example, Redis or some sort of caching mechanism again up to you, just make sure fetching and retrieval should be fast.
Now while sending a message just pull the socketId from your cache and emit the message on that socketId by using below code,
io.to(socket.id).emit(`message-response`, {
message: 'hello'
});
I have written a complete blog post on this topic on both Angular and AngularJs, you can refer those as well.
Edit 1:
Part 1 =>
When your user completes the login request, then make the connection to the socket server.
Assuming you are using React Or Angular After a successful login you will redirect your user to home component(page). On the Home component(page) make the socket server connect by passing the userId just like this,
const socket = io(SOCKET_SERVER_BASE_URL, { query: `userId=${userId}` });
P.S. you can get userID from URL or maybe using a cookie that is up to you.
Once you receive this socket connection request on the server, then you can read the userID query and you can get socketId associated with it and store it in cache like this,
io.use( async (socket, next) => {
try {
await addSocketIdInCache({
userId: socket.request._query['userId'],
socketId: socket.id
});
next();
} catch (error) {
// Error
console.error(error);
}
});
Part 2 =>
Now, let's say you have a list of the users on the client side, and you want to send a message to particular users.
socket.emit(`message`, {
message: 'hello',
userId: userId
});
On the server side, fetch the socketId from the cache using UserId. Once you get the socketId from cache send a specific message like this,
io.to(socketId).emit(`message-response`, {
message: 'hello'
});
Hope this helps.

pass the credentials of user to all views node.js

I'm trying to build an android application using node.js web services,the first interface allow the user to connect to a host using ip address,login and password, so he can get all the databases,i want to save the object credentials to use in all other routes,i tried express-session but it didnt worked.
Any solution?
app.post('/connect',function(req,res){
sess=req.session;
sess.user=req.body.user;
sess.password=req.body.password;
sess.server=req.body.server;
sess.database=req.body.database;
console.log(sess)
user = req.body.user;
password = req.body.password;
server = req.body.server;
database = req.body.database;
var config = {
user: user,
password: password,
server: server,
database: database
};
// connect to your database
sql.connect(config, function (err) {
if (err) {res.json({success: false, message: "error connexion to SQL Server"});
sql.close()}
else{
res.json({success: true, message: "connexion established to SQL Server"});
sql.close();
}
});
});
In your case the request make by http lib of android (or another) which is not a browse then express-session will not work. Your server must be like a API server, client(android) request login server response a token (api key or the same), in next request client push data embeded token and server side can credentials the request. I suggest read about JWT (Json Web Token) to do this.
This is easy if you are using express module in node application.
You basically create routes using express and can pass the required data to the appropriate routes and views as follows
router.get('/', function(req, res, next) {
res.render('category',
{
videodata: vd
});
});
Here while rendering the response, the data that is to be passed is also included. It's name is videodata and value is vd

How to connect MySQL with nodejs controllers?

I have a server on sails nodejs and I am trying to connect my controllers with my MySQL db through a wrapper file that would create the connection pool. My purpose is that I use that pool everytime a function in any controller needs to interact with DB, and in such a way that connection is created at the time interaction starts and connection is closed at the time interaction is over. For this, I have created a wrapper file db.js
db.js
var mysql = require('mysql');
var connection = mysql.createConnection({
host:"localhost",
port: '3306',
user:"ye_old_username",
password:"ye_old_password",
database: "ye_old_schema"
});
module.exports = connection;
Now, I am creating a connection pool called ConnectionPool.js
ConnectionPool.js
var mysql = require('mysql'),
config = require("./db");
/*
* #sqlConnection
* Creates the connection, makes the query and close it to avoid concurrency conflicts.
*/
var sqlConnection = function sqlConnection(sql, values, next) {
// It means that the values hasnt been passed
if (arguments.length === 2) {
next = values;
values = null;
}
var connection = mysql.createConnection(config);
connection.connect(function(err) {
if (err !== null) {
console.log("[MYSQL] Error connecting to mysql:" + err+'\n');
}
});
connection.query(sql, values, function(err) {
connection.end();
if (err) {
throw err;
}
next.apply(this, arguments);
});
}
module.exports = sqlConnection;
I have followed the method answered on this question to create the connection pool: How to provide a mysql database connection in single file in nodejs
And finally, I am trying to run a function from a controller using the wrapper and the connection pool. The code inside the Controller is
var connPool = require('./ConnectionPool');
module.exports = {
testConn: function(req, res){
connPool('SELECT * from user where ?', {id: '1'}, function(err, rows) {
if(err){
sails.log.debug(err);
}else{
console.log(rows);
}
});
}
};
All the three files, the wrapper, the connection pool, and the controller are in the same Controllers folder.
Now, when I send a request to the URL through my client, that would invoke the testConn function inside the controller, I get the following response on server log:
[MYSQL] Error connecting to mysql:Error: ER_ACCESS_DENIED_ERROR: Access denied for user ''#'localhost' (using password: NO)
This error is coming from the line connection.connect(function(err) { in connection pool file.
When I try to log on my MySQL db through the same credentials on command line, I am through it. Therefore I believe that db.js file has some format related issue because of which a proper connection is not getting initiated. There can be other reason as well, but the reason I suspect seems to be very strong.
I need some guidance on solving this issue. Any help will be appreciated.

Socket.io - Cant stop passing all data to all clients

I am having a issue where I am pulling data from a DB via node mysql & Express and passing it via socket.io.... but there's an issue am running into.
All users are updating with the same data rather than unique data per user.
For example:
If user A has just logged in he can see all his account details. But when user B logs in right after he can then see all his details....but it then updates user A details to show user B details as well.
I am trying to ensure user A can can only see his own and same for user B.
I have tried numerous things to stop this happening via JQuery but cant seem to find a resolution.
Below I have trimmed down a the code to a basic example:
HTML
<span id="id-val">User A</span>
<span id="user-val"></span>
Server side
server = http.createServer(app),
io = require('socket.io').listen(server);
function SQLuserData(userval) {
connection.getConnection(function (err, connection) {
connection.query('SELECT val FROM test WHERE name= ?;',
[userval],
function (err, rows) {
var accountval = rows[0]['val'];
if (accountval) {
console.log("Val : " + accountval);
UserVal(accountval);
} else {
console.log("Error | Val: " + err);
}
});
connection.release();
});
}
//Socket.io connection socket
io.sockets.on('connection', function (socket) {
socket.on('sqluser', function (userval) {
SQLuserData(userval);
});
});
//Pass val client side.
function UserVal(accountval) {
io.sockets.emit("valsocket", accountval);
}
Client side
var socket = io.connect();
//Used to grab information for that user from serverside.
$(document).ready(function () {
var userval = $('#id-val').text();
socket.emit('sqluser', userval);
});
//Grabs user value being passed from serverside and updates HTML.
socket.on("valsocket", function (accountval) {
$("#user_val").val(accountval);
});
Does anyone have any advice or potential solutions?
you need to grab and store the socket.id for each connected user
var users = {};
//Socket.io connection socket
io.sockets.on('connection', function (socket) {
socket.on('sqluser', function (userval) {
// 'userval' must be unique for each user
users[userval] = socket.id;
SQLuserData(userval);
});
});
and then use the same id to emit data ti single socket
//Pass val client side.
function UserVal(accountval, userval) {
io.sockets.socket(users[userval]).emit("valsocket", accountval);
}
for socket.io version 1.0 and above
io.to(users[userval]).emit("valsocket", accountval);
I think you want to avoid emitting the account data to all connected users, which is what Socket.IO's emit method does. It might be better have the client send a GET request to the server and respond with the account details to the individual client.
Here are some resources if you choose to use an HTTP request over Socket.IO:
jQuery GET
Express Respond
So basically the problem with your code is that you are not distinguishing between users . Since you are sending data through socket you need to be careful to whom you are sending data.
You can use socketio-auth to create a type of authentication . And then send the data as socket.emit(event, data); Where socket is an individual object per user . You can also use a cookie based session to help you with this .

Passing a Mongo connection to JQuery code via socket.io?

I am trying to create a global MongoDB connection in my node.js web app like this:
var MongoClient = require('mongodb').MongoClient;
var mconn = null;
MongoClient.connect('mongodb://myHost:27017/users', function(err, udb) { //open connection to MongoDB db
if (!err){
mconn = udb;
}
else
console.error("Could not connect to sql: ", err);
});
Then, I want to pass this connection via a `socket.emit' event like this:
io.sockets.on('connection', function(socket) {
socket.on('updates', function(PEMSID){
gps_helper.get_gps(PEMSID, conn, function(data){ //make initial query to GPS table for marker coordinates
socket.emit('message', {message: data, mongoConnection: mconn});
});
intervalID = setInterval(function(){
gps_helper.get_gps(PEMSID, conn, function(data){ //query GPS table for marker coordinates on an interval
socket.emit('message', {message: data, mongoConnection: mconn});
});
}, 30000);
});
This doesn't appear to be working, the 'mongoConnection' value is empty on the other side. Is it possible to send it this way?
That's not possible: you can't generally serialize, and therefore transmit, opaque data types like network connections or file handles.
Consider the security risks if it were possible: malicious clients would have complete access to your database.
You're going to have to make some sort of interface where your client code is sending certain messages to the server, the server performs the appropriate database actions and sends back the results (again, make sure you don't make this interface too general so that malicious client code gets to execute random queries against your database).

Categories

Resources