User receive more than 1 notification from nodejs - javascript

This is my first time with nodejs and I have some issues with it. The main problem is that the user receive more than 1 signal from the server. The count is based on the refresh of the page.
Below is my code:
var http = require('http');
var server = http.createServer().listen(1332);
var io = require('socket.io').listen(server);
var redis = require('redis');
var sub = redis.createClient();
//Subscribe to the Redis chat channel
sub.subscribe('notification_count');
console.log("Server is running...\nClick on Ctrl+C to exit");
io.sockets.on('connection', function (socket) {
var user_id = socket["handshake"]["query"]["user_id"];
console.log("user_id", user_id);
socket.room = user_id;
socket.join(user_id);
socket.on('disconnect', function(){
socket.leave(socket.room);
});
//Grab message from Redis and send to client
sub.on('message', function(channel, message){
io.sockets.in(message).emit('message', message );
});
});
And here is the client side js code:
var socket = io.connect('localhost:1332', { query: "user_id={{ request.user.id }}" });
socket.on('connect', function(){
console.log("connected");
});
socket.on('message', function(message) {
//something
});
Basically on connection from the server I send to the server the user_id. After that I create a new room which name is the same as the user_id. Of course on disconnect the room should be delete. I have noticed that sub.on() is fired more than once, but I cannot figure out why. I will appreciate any help. Thank you in advance !

The problem is that you are using a handler inside the connection event, everytime a client connects it will execute everything inside the connection event including your sub.on
Place sub.on out of the connection event and it should stop the double messages

Related

Page doesn't automatically update when socket.io receive

I want to page update when new socket.io data appear.
I have a server -> client comunication:
Server code (the n var is the message)
io2.on('connection', function(socket2) {
socket2.on('live', function(data2) {
console.log('status from live client:', data2);
socket2.emit('live', n);
});
});
Live page code:
var socket = io.connect('http://localhost:3002');
socket.emit('live', 'live client is connected');
socket.on('live', function(data) {
//alert(data)
document.getElementById("demo").innerHTML = data;
});
The socket works fine because when I send the data and I refresh the page it show what I want. The problem is that I want to see the updated message without manual refresh.
Thanks!
The scope for n is undefined in the first function, so the receiving function doesn't have anything to show.
You'll need to define n in the original emitting function.
You need to emit the event from server side to the client side and then catch data there
var server = app.listen(3000);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
socket.on('event', function(data) {
var n = data.message;
io.sockets.emit('event', message);
});
And then on frontend in live page you write this
var n = <%-JSON.stringify(v1)%>;
var socket = io.connect('http://localhost:3000');
socket.on('event', (data)=>{
console.log(data)
});

Redis + Socket.io - How to client can join two room the same time?

In my project, I've a user, that user can in two channels , but i want this user can receive notifications for two channels different.
I can ask a question?
How to Client can join multiple room and receive 2 notifications the same time for different two rooms.
I have code here :
client.js
var socket = io.connect('localhost:3000');
socket.on('connect', function(){
socket.emit("subscribe",'test');
});
socket.on('message', function(message) {
console.log('Receive >>', message);
});
server.js
var client = redis.createClient();
io.sockets.on('connection', function (socket) {
var broadcast = function(channel, message){
socket.broadcast.to(channel).emit('message', message);
}
socket.on("subscribe",function(channel){
client.subscribe(channel);
socket.join(channel);
});
socket.on('disconnect', function() {
client.unsubscribe(channel);
client.removeListener(broadcast)
})
client.on("message", broadcast);
});
I wanna : socket.on("subscribe",function(channel){
client.subscribe(channel, channel1, channel2);
socket.join(channel, channel1, channel2);
});
But socket.io not support that.
Please give me an idea or a suggestion. Thanks so much!

Node.js Socket.io error: disconnect event is triggered after connect

On server the disconnect event is triggered after connect when the network had
dropped and the client reconnects.
Client code:
var url ='192.168.1.101', port = '80',
socket = io.connect('http://' + url + ':' + port, {
'reconnect': true,
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 1000
});
//reconnect event
socket.on('reconnect', function (nr) {
console.log('reconnected, nr: ', nr);
});
//connect event
socket.on('connect', function () {
console.log('connected');
});
//disconnect event
socket.on('disconnect', function () {
console.log('disconnected');
});
Server code:
'use strict';
var fs = require('fs'),
express = require('express'),
app = express(),
io = require('socket.io'),
server = require('http').createServer(app),
compress = require('compression'),
socket;
app.use(compress({level: 9}));
server.listen(port, url);
socket = io.listen(server, {'pingTimeout': 1000, 'pingInterval': 3000});
socket.on('connection', function (client) {
console.log('client connected');
client.on('disconnect', function () {
console.log('client disconnected');
});
});
- Result on server if client reconnects:
> client connected
> client disconnected
Can someone explain to me why this is happening?
The client and server exchange heart beat messages while the connection is active. When the server stops receiving these messages it will declare the client disconnected. The client can also disconnect explicitly.
What you are experiencing though is probably the first case. The client has a retry logic so whenever the connection is dropped it'll try to reconnect. I'm not sure why this is happen, you may want to look at the network tab in your browser's console to see what's happening at the request/response level.
REF:
https://github.com/socketio/socket.io/issues/1910
https://github.com/miguelgrinberg/Flask-SocketIO/issues/116
Are you sure that the client disconnected and client connected texts are from the same socket/connection? Maybe first one is from previous connection and it is just delivered to you a bit later than info about new connection?
Try to generate and add some ID numbers to connections/sockets and output them to console along with info messages.

How to push notification to specific user Node + AngularJS + Laravel

I need help how to push notification to specific user. I can now push notifcation but all user will get that notification. I can filter it on clinet side but I think it is unsecure...
First I send data with laravel 5:
$redis = Redis::connection();
$redis->publish('update.answer', json_encode($events));
here is my node.js i emite data:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.subscribe('update.group', function(err, count) {
});
redis.subscribe('update.question', function(err, count) {
});
redis.subscribe('update.answer', function(err, count) {
});
redis.subscribe('update.comment', function(err, count) {
});
redis.on('message', function(channel, message) {
message = JSON.parse(message);
console.log(message);
io.emit(channel, message);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
and with angularjs I take data and push to the client.
socket.on('update.answer',function(data){
if($scope.remove){
$scope.remove = false;
}
$scope.feed = $("#feed").val();
if(parseInt($scope.feed) === parseInt(data.userID)){
$scope.answers.push(data);
$scope.$digest();
}
});
WIth this part:
$scope.feed = $("#feed").val();
if(parseInt($scope.feed) === parseInt(data.user_id) && data.admin_id !== null){
}
I check if client should get notification but it is unsecure...
Any way to improve this?
To push message to specific user , you must store his/her reference somewhere.
for ex
io.on('connection', function(socket) {
socket.on('add-user', function(data){
clients[data.username] = socket;
});
});
now to push message to specific user just use his username to retrive his socket
clients[data.username].emit(channel, message);
Update : Explanation
This Assume that each user who uses you web app is having some sort of authentication.
As soon as user login into your application , let him join on the nodejs backend socket.
on client side
socket.emit('add-user',userObj);
});
userObj is object that contains user details,you can send the username alone too
socket.emit('add-user',username);
in your nodejs first decalre one array that contains the socket of all the users who joins the website
var clients = [];
now in your nodejs application write this additional code
io.on('connection', function(socket) {
socket.on('add-user', function(data){
clients[data.username] = socket;
});
});
up to this moment the user who login into your website will call add-user event from client side which will in turn call add-user on nodejs and there socket will be added into the clients array
now to send message to any particular user you must know there username,so if you know the username of the user then you can simply emit message to them using
clients[data.username].emit(channel, message);

How to send data to specific client in a specific room with socket io

My question is what's the proper way of sending data to a specific client in a specific room. I'm using socket io and the code written below:
I use the command:
socket.to(socket.id).emit('change', {data})
but the client never gets this command. Anyone know why?
Below is a snippet of my code:
server code:
io.on('connection', function (socket) {
socket.on('channelJoin', function(channel){
socket.join(channel);
if(deltasByChannel[channel])
{
console.log("sending initial data to: "+socket.id);
socket.to(socket.id).emmit('change', deltasByChannel[channel]);
}
socket.on("change", function(delta){
console.log("channel: " + channel+" was edited!");
console.log(deltasByChannel[channel]);
deltasByChannel[channel] ? deltasByChannel[channel] = deltasByChannel[channel].concat(delta) : deltasByChannel[channel] = delta;
socket.broadcast.to(channel).emit('change', delta);
});
});
});
http.listen(3000, function () {
console.log('listening on *:3000');
});
client code:
var channel = window.location.pathname;
var socket = io.connect();
//Ace handlers
var sendUpdateData = function(e){
socket.emit("change", [e.data]);
};
socket.on('connect', function(){
socket.on("change", function(data){
console.log("change event received!");
editor.getSession().removeListener('change', sendUpdateData);
editor.getSession().getDocument().applyDeltas(data);
editor.getSession().on('change', sendUpdateData);
});
editor.getSession().on('change', sendUpdateData);
socket.emit('channelJoin', channel);
});
just to avoid confusion the editor object is listening for a change event as well. It's from an entirely different library (ace.js) that has nothing to do with my socket io issue.
below is another snippet of the server code for more clarity:
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, function () {
console.log('listening on *:3000');
});
I think there's some confusion about sending data over sockets using socket.io. You can elect to emit events or data using rooms or private namesspaces, you can broadcast to all connected sockets, or you can emit data to a specific ID.
In your case you should just be selecting a socket.id, to emit an event to a particular connection. You can do this by:
io.sockets.connected[ socket.id ].emit('privateMsg', 'hello this is a private msg');
You can also use the to() method in conjunction with broadcast as well:
socket.broadcast.to( socket.id ).emit('privateMsg', 'hello this is a private msg');
This will reach the user which matches the socket.id you pass in as the argument.
To contact users within a "room" or private namespace, you can also use the to() method:
io.to('some room').emit('some event');
In this case some room would be the channel var you've defined, and it should match a predefined variable that has already been instantiated.
For more information about rooms/namespaces/and reaching specific socket connections: http://socket.io/docs/rooms-and-namespaces/#

Categories