Send db-query-result to client - node.js

Trying to send results from a node-mysql database query to the client.
Code:
io.on('connection', function(socket){
socket.on('admin', function() {
[...]
locations = getUserInfo(function(e,c){...});
[...]
});
});
function getUserInfo(callback) {
var json = '';
connection.query('SELECT * from locations WHERE loc_id = 1', function(err, results, fields) {
if(err)
return callback(err, null);
console.log('The query-result is: ', results[0]);
json = JSON.stringify(results);
console.log('JSON-result: ', json);
callback(null, json);
});
};
getUserInfo(function(e,c){
console.log(c);
});
This is working as expected.
But I don't want to write it to the console but send it to the client (with socket.io). How can I do this? All my attempts ended in getting undefined as result.

You might be sending the locations object back, which is always undefined. Try:
io.on('connection', function(socket){
socket.on('admin', function() {
getUserInfo(function(e,c){
if(!e){
socket.emit('locations', c);
}
});
});
});

Related

Modularizing an Express/Socket.io application

I want to be able to load these 4 functions: returnAvailable, processMessage, removeUser and joinRoom from an external file, but i get reference errors where it says that socket and nicknames are undefined. How do I modularize my app with respect to dependencies I use?
Here's my code:
server.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
// mongoDB init
var mongoose = require('mongoose');
mongoose.connect("mongodb://localhost:27017/chat");
var Message = require('./server/datasets/message');
//include these 4 functions
var util = require('./server/util/util');
//object which contains all users and chatrooms
var nicknames = {
'Music': [],
'Videogames': [],
'Sports': [],
'TV': [],
'Politics': []
};
// middleware
// serves static files
app.use('/client', express.static(__dirname + '/client'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
// routes
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html')
});
app.get('/api/rooms/get', function(req, res){
res.json(nicknames);
});
server.listen(2000);
// socket functionality
io.sockets.on('connection', function(socket){
socket.on('new user', util.returnAvailable);
// do when 'send message' data is received from client
socket.on('send message', function(data){
util.processMessage(data);
});
// do when 'disconnect' data is received from the client
socket.on('disconnect', function(data){
util.removeUser();
});
socket.on('leave room', function(){
util.removeUser();
});
});
util.js
module.exports.returnAvailable = function (data, callback){
console.log(data);
if(nicknames[data.room].indexOf(data.username) != -1){
callback({ bool: false });
}else {
socket.nickname = data.username;
joinRoom(socket, data.room);
nicknames[data.room].push(socket.nickname);
console.log(nicknames[data.room]);
io.sockets.to(data.room).emit('usernames', nicknames[data.room]);
callback({ bool: true, nickname: socket.nickname});
}
}
module.exports.removeUser = function(){
//console.log(socket.nickname + " disconnected. Bool value: " + socket.nickname==true);
if(socket.nickname==false) return;
// socket.room has to be defined, otherwise crashes if user reloads while not in a roomn
if(socket.room)
{
nicknames[socket.room].splice(nicknames[socket.room].indexOf(socket.nickname), 1);
socket.leave(socket.room);
}
io.sockets.to(socket.room).emit('usernames', nicknames[socket.room]);
}
module.exports.joinRoom = function (data){
socket.join(data);
socket.room = data;
console.log(socket.room);
var query = Message.find({room: socket.room});
query.sort({created:-1}).limit(5).exec(function(err, results){
if(err) { console.log(err); }
else if(results){
io.sockets.to(socket.room).emit('old messages', results);
}
});
}
module.exports.processMessage = function(data){
io.sockets.to(socket.room).emit('new message', {msg : data, nick : socket.nickname});
var message = new Message({
created: new Date,
user: socket.nickname,
message: data,
room: socket.room
});
message.save(function(err){
if(err){
console.log(err);
}else{
console.log('Successfully saved.');
}
});
}
I'm using Express 4.13.4
The socket variable is only available within io.sockets.on('connection', callback function so you can't use it in other files this easily. But you can pass the socket variable to the function where you are trying to use it like this
util.removeUser(socket);
and change the definition of removeUser to accept the socket as an argument
module.exports.removeUser = function(socket){
// your code here
}
The same goes for nicknames variable, use it like this
socket.on('new user', function(data) {
util.returnAvailable(io, socket, nicknames, data);
});
and change the function to accept those arguments
module.exports.returnAvailable = function (io, socket, nicknames, data){
// your code here
}

socket.io functions not working in callbacks

The issue I am having is that I want the current session to join a room if they pass a database check. If they do pass the check, meaning the query returns a result, it should add the user to a room. However, when I call socket.join("room"), it does not work if its in the database callback function. Here is a SIMPLIFIED version of my code:
var pg = require('pg');
var conString = 'connection_to_postgres_server'
var server = require('http').createServer();
var io = require('socket.io')(server);
var port = 8080;
function defaultOnSuccess(query, result){
console.log("Result of query `", query, "` -> ", result);
}
function defaultOnError(query, err){
console.log("Error of query `", query, "` -> ", err);
}
function runQuery(query, queryParams, onSuccess, onError){
onSuccess = (typeof onSuccess !== 'undefined' ? onSuccess : defaultOnSuccess);
onError = (typeof onError !== 'undefined' ? onError : defaultOnError);
pg.connect(conString, function(err, client, done){
if(err){
onError(query, err);
done();
return;
}
client.query(query, queryParams, function(err, result){
if(err){
onError(query, err);
done();
return;
}
else {
onSuccess(query, result);
done();
return;
}
});
});
}
function listenOn(channel, onNotification, onError){
onError = (typeof onError !== 'undefined' ? onError : defaultOnError);
pg.connect(conString, function(err, client, done){
if(err){
onError(channel, err);
done();
return;
}
client.on('notification', function(msg) {
onNotification(channel, msg);
});
var query = client.query("LISTEN \"" + channel + "\";");
done();
});
}
io.on('connection', function(socket){
runQuery("THIS QUERY SHOULD RETURN EXACTLY ONE RESULT IF THE USER IS VALIDATED", [],
function(query, result){
if(result.rowCount == 1){
console.log("Pre rooms: ", socket.rooms);
socket.join("hello");
console.log("Current rooms: ", socket.rooms);
}
}
);
});
io.on('connection', function(socket){
socket.on('disconnect', function(){
});
});
server.listen(port, function(){
console.log('listening on *:' + port);
listenOn("project_tc_changed",
function(channel, message){
console.log(message);
io.emit("data", message);
}
);
});
When I connect with a client, the output of the "Pre rooms:" and "Current rooms:" log is exactly the same. In addition, the io.emit() in server.listen does not work, even though I know the code is getting called, because the message gets logged.
I know for a fact that the socket.join() call and the io.emit() call are getting reached, they are just not having any effects, and not returning any errors.
The socket.join is working as expected, but due to the asynchronous nature of javascript your console logs are not showing what you expected. In javascript every line of code is ran asynchronously, including your socket.join and console.log. This is why we have to make use of callbacks to see what the environment looks like after a function has completed. socket.join allows for this callback. So to see the room join in action, we simply have to change our 3 lines of code to the following:
console.log("Pre rooms: ", socket.rooms);
socket.join("hello", function(){
console.log("Current rooms: ", socket.rooms);
);
As for your emit; If you believe your emit is being reached and the message variable contains data, your io.emit should work. So without seeing what the client side code looks like it is hard to help solve for this.

Send update notification to particular users using socket.io

Following is the code on front end, where storeSelUserId contains user_id to send the message-
FYI - Node Version 1.1.0
// Socket Notification
var socket = io('http://localhost:6868');
socket.on('connection', function (data) {
socket.emit('send notification', { sent_to: storeSelUserId });
});
Following is the server code in routes file -
var clients = {};
io.on('connection', function (socket) {
socket.emit('connection', "Connection Created.");
socket.on('send notification', function (sent_to) {
console.log(sent_to);
});
});
In console sent_to is showing the array of user_id.
Now being a starter in socket.io I stuck with the solution that how do I send the message to these particular userids.
I search and found that I need to push each user with its sockets so I reformed it to -
var users = [];
io.on('connection', function (socket) {
users.push({socket_id: socket.id});
socket.emit('connection', "Connection Created.");
socket.on('send notification', function (sent_to) {
console.log(sent_to);
});
});
But I am in dilemma that else do I need to do to store which user_id refers to which socket_id and then update the div of users with that particular ids?
EDIT -
Add Controller - (Front End)
Front end Interface where memo is created and send to particular users
var socket = io('http://localhost:6868');
socket.on('connection', function (data) {
socket.emit('send memo notification', {creator_id: creator_id, sent_to: [Array of user_ids to whom memo to send]});
});
Dashboard controller - (Front End)
Front end Interface where notification count to show "notificationCount"
if (SessionService.currentUser._id) {
var socket = io('http://localhost:6868');
socket.on('connection', function (data) {
socket.emit('get notifications', {user_id: SessionService.currentUser._id});
});
socket.on('notification data', function(data){
console.log("-- Not Data Test -");
$scope.notificationCount = data.length;
});
}
Code at server end -
io.on('connection', function (socket) {
socket.emit('connection', "Connection Created.");
socket.on('send memo notification', function(data) {
notifications.createNotification(data);
});
socket.on('get notifications', function(data){
notifications.getNotifications(data, function(response){
socket.emit('notification data', response.data);
});
});
});
Backend controller code -
exports.getNotifications = function(data, callback) {
var userId = data.user_id;
Notification.find({receiver_id: userId}, function(err, response){
if (err)
callback({"message": "error", "data": err, "status_code": "500"});
else
callback({"message": "success", "data": response, "status_code": "200"});
});
};
exports.createNotification = function(data) {
var notificationData = data;
var x = 0;
for(var i=0; i< notificationData.length; i++) {
// Code
Notification(notificationData[i]).save(function(err,response){
if (err)
return false;
});
if (x === notificationData.length - 1) {
return true;
}
x++;
}
};
If you want to use your own user ids then there is no way around mapping the socket id to the user id. I assume a client knows its user id from somewhere, so it could send its user id to the server after connection.
Client
socket.on('connection', function (data) {
socket.emit('setUserId', myUserId);
});
The server saves the socket for each user id.
socket.on('setUserId', function (userId) {
users[userId]=socket;
});
If you have such a mapping in the server you can send a message just to this client using the user id.
socket.on('send notification', function (userId) {
users[userId].emit('notification', "important notification message");
});
Edit: Saving the corresponding socket directly is even better.
According to what i understand, you need private notification send to only some users. For that, save your users name to whom you want to send and their corresponding socket in different hashes.
username [socket.name] = username to be added;
usersocket [ socket.name ] =socket;
Then to emit the messages to that user only, use
usersocket[ socket.name ].emit('event for send message', ' what you want to send ');

Socket.io send data only a client who make request

I'm sending data to all clients but I need to send the data only one client (who make request) too.
app.post(.....){
myModel.save(function (err) {
if (err) return handleError(err);
///send to all
io.sockets.emit("ev", { ...... });
//// send to one client
......
});
}
There is a function called io.sockets.emit but there is no io.socket.emit.
I assume that in the post method you have identified the user or session.
So you can create a room per user to later emit on it.
client.js
var room = "#usernameRoom";
socket.on('connect', function() {
socket.emit('privateroom', room);
});
socket.on('privatemessage', function(data) {
console.log('Incoming private message:', data);
});
server.js
io.sockets.on('connection', function(socket) {
var socket_room;
socket.on('privateroom', function(room) {
socket_room = room;
socket.join(room);
});
socket.on('disconnect', function() {
if (socket_room) {
socket.leave(socket_room);
}
});
});
app.post(.....){
myModel.save(function (err) {
if (err) return handleError(err);
///send to all
io.sockets.emit("ev", { ...... });
//// send to one client
// now, it's easy to send a message to just the clients in a given private room
privateRoom = "#usernameRoom";
io.sockets.in(privateRoom ).emit('privatemessage', 'Never reveal your identity!');
});
}
hope that helps

get the last updated mongo id from nodejs

am working on push notifications using mongodb and nodejs.
I can see the newly added notifications (which are addede in Mongodb) in my browser
But, if I updated the record, the value is not updating in the browser
// if no error get reference to colelction named: 'notifications'
db.collection('notifications', function(err, collection){
if(err) {
throw err;
}
// if no error apply a find() and get reference to doc
collection.find().sort({
$natural: -1
}).limit(1).nextObject(function(err, doc) {
// Rewind the cursor, resetting it to point to the start of the query
if(err) {
throw err;
}
// using tailable cursor get reference to our very first doc
var query = {
_id: {
$gt: doc._id
}
};
var options = {
tailable: true,
awaitdata: true,
numberOfRetries: -1
};
var cursor = collection.find(query, options).sort({
$natural: 1
});
// This function will take cursor to next doc from current as soon as 'notifications' database is updated
function next() {
cursor.nextObject(function(err, message) {
if (err) throw err;
console.log(message.message);
mdsok.volatile.emit('notification', message);
next();
});
}
// what you need to do is: call it first time
next();
});
This is what i am doing in my code.
what should I do to update the value in the browser when I update the same in db.
Please help me . Thanks in advance!
My problem was solved upto some extent.
var http = require('http'),
fs = require('fs'),
// NEVER use a Sync function except at start-up!
index = fs.readFileSync('index.html');
// Send index.html to all requests
var app = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.end(index);
});
// Socket.io server listens to our app
var io = require('socket.io').listen(app);
var MongoClient = require('mongodb').MongoClient;
function getdata(){
MongoClient.connect("mongodb://127.0.0.1:27017/test", function(err, db) {
var collection = db.collection('my_collection');
var stream = collection.find({
//'_id': new ObjectID('53eb6f2e75fd7ad00d000029')
//_id: ObjectID.createFromHexString("53eb6f2e75fd7ad00d000029")
}).stream();
stream.on("data", function(item) {
io.sockets.emit('db_status', {
status: item.status
});
prev = item.status;
console.log(prev);
});
stream.on("end", function() {
console.log("Done loading data");
});
});
}
// Send current time every 5 secs
setInterval(getdata, 5000);
// Emit welcome message on connection
io.sockets.on('connection', function(socket) {
socket.emit('welcome', {
message: 'Welcome!'
});
socket.on('i am client',function(data){
console.log(data);
});
});
app.listen(3000);
for every 5 secs, i am hitting the db and getting the value and displaying it in the browser.
To get the newly inserted object, we are using .nextObject() in node.js
Is there any way to get the updated object of the db as above in node.js.

Resources