Implement notification system using node.js,express,socket - node.js

I am trying to add a notification system. If a user logs in and performs an action a notification should be sent to another user if he is logged in. I have made my application in node.js using express. I know that I have to use socket but how the event needs to be handled? If someone could let me know any reference or sample which I can follow for this task?

I just did something similar and handled it like this:
io.js - central node.js file where I handle new connnections and store io
var io = require('socket.io')();
io.on('connection', function(socket){
console.log("Socket established with id: " + socket.id);
socket.on('disconnect', function () {
console.log("Socket disconnected: " + socket.id);
});
});
module.exports = io;
someroute.js - somewhere in the node.js server application I want to emit messages
var appRoot = require('app-root-path');
var io = require(appRoot + '/server/io');
/*your code, somwhere you will call the
* function below whenever you want to emit
* the 'user_did_action' event:
*/
if(user.didNewStuff()){
emitUserAction(user);
}
var emitUserAction = function(user){
io.sockets.emit('user_did_action', user);
};
client_javascript.js - some client js (in my case angular, but it doesent matter), import the socket.io lib, then access somewhere in the client like this:
/*connect to the server*/
var socket = io.connect();
/*do something wen the event 'user_did_action'
* is received, just invoke the callback
*
*in the function param data, you will have the same
*data you emitted earlier in the server,
*in this example the user object!*/
socket.on('user_did_action', myFunctionToHandleTheEvent(data));

Related

Websockets & NodeJS - Changing Browser Tabs & Sessions

I've started writing a node.js websocket solution using socket.io.
The browsers connects to the node server successfully and I get see the socket.id and all config associated with console.log(socket). I also pass a userid back with the initial connection and can see this on the server side to.
Question: I'm not sure the best way to associate a user with a connection. I can see the socket.id changes every page change and when a tab is opened up. How can I track a user and send 'a message' to all required sockets. (Could be one page or could be 3 tabs etc).
I tried to have a look at 'express-socket.io-session' but I'm unsure how to code for it and this situation.
Question: I have 'io' and 'app' variables below. Is it possible to use the 2 together? app.use(io);
Essentially I want to be able to track users (I guess by session - but unsure of how to handle different socket id's for tabs etc) and know how to reply to user or one or more sockets.
thankyou
The best way to handle the situation is rely on SocketIO's rooms. Name the room after the user's unique ID. This will support multiple connections out of the box. Then, whenever you need to communicate with a particular user, simply call the message function and pass in their id, the event, and any relevant data. You don't need to worry about explicitly leaving a room, SocketIO does that for you whenever their session times out or they close their browser tab. (We do explicitly leave a room whenever they log out though obviously)
On the server:
var express = require('express');
var socketio = require('socket.io');
var app = express();
var server = http.createServer(app);
var io = socketio(server);
io.on('connect', function (socket) {
socket.on('userConnected', socket.join); // Client sends userId
socket.on('userDisconnected', socket.leave); // Cliend sends userId
});
// Export this function to be used throughout the server
function message (userId, event, data) {
io.sockets.to(userId).emit(event, data);
}
On the client:
var socket = io('http://localhost:9000'); // Server endpoint
socket.on('connect', connectUser);
socket.on('message', function (data) {
console.log(data);
});
// Call whenever a user logs in or is already authenticated
function connectUser () {
var userId = ... // Retrieve userId somehow
if (!userId) return;
socket.emit('userConnected', userId);
}
// Call whenever a user disconnects
function disconnectUser () {
var userId = ... // Retrieve userId somehow
if (!userId) return;
socket.emit('userDisconnected', userId);
}

Reconnect socket in disconnect event

I am trying to reconnecct the socket after the disconnect event is fired with same socket.id here is my socket config
var http = require('http').Server(app);
var io = require('socket.io')(http);
var connect_clients = [] //here would be the list of socket.id of connected users
http.listen(3000, function () {
console.log('listening on *:3000');
});
So on disconnect event i want to reconnect the disconnected user with same socket.id if possible
socket.on('disconnect',function(){
var disconnect_id = socket.id; //i want reconnect the users here
});
By default, Socket.IO does not have a server-side logic for reconnecting. Which means each time a client wants to connect, a new socket object is created, thus it has a new id. It's up to you to implement reconnection.
In order to do so, you will need a way to store something for this user. If you have any kind of authentication (passport for example) - using socket.request you will have the initial HTTP request fired before the upgrade happened. So from there, you can have all kind of cookies and data already stored.
If you don't want to store anything in cookies, the easiest thing to do is send back to client specific information about himself, on connect. Then, when user tries to reconnect, send this information again. Something like:
var client2socket = {};
io.on('connect', function(socket) {
var uid = Math.random(); // some really unique id :)
client2socket[uid] = socket;
socket.on('authenticate', function(userID) {
delete client2socket[uid]; // remove the "new" socket
client2socket[userID] = socket; // replace "old" socket
});
});
Keep in mind this is just a sample and you need to implement something a little bit better :) Maybe send the information as a request param, or store it another way - whatever works for you.

How to write custom emitEvent for proessing in socket.io?

I am writing a multi-player game using processing.js, node.js and socket.io.
Question #1:
In the client, I use p5.js to create a class Ball.
I want the server to send parameter to create an array using that class (balls.push(new Ball(x, y));), so every client can have a bunch of balls moving on the canvas.
I know I should use socket.io to emit the parameter to the client but i have no clue.
Normally the array is created inside the setup function inside p5...so how could socket do that?
Question #2:
How could the client send the mouseX and mouseY to the server? And then how could the server send back others' mouseX and mouseY to every client?
I try to make p5.js into normal js like this:
(function () {
"use strict";
function sketchProc(processing) {
var p=processing,
var ...,
var ...;
function ball(){...}
p.setup=function(){}
p.draw=function(){}
}
var canvas = document.getElementById("canvas1"),
p = new Processing(canvas, sketchProc);
}());
But i don't know if this helps...
The balls should be passed to the client only in the connection event. That's where node's beauty lies, code sharing.
To create a socket server, you can use either node's native Net module or Socket.io
On the server:
var server = net.createServer();
server.listen(PORT, HOST);
server.on('connection', function(socket) {
socket.write({ type: "BallsArray", data: BallsArray });
});
On the client, you use WebSockets with Socket.io:
var client = io.connect('http://localhost:3000');
var BallsArray = null;
client.on('message', function(msg) {
if(msg.type == "BallsArray")
BallsArray = msg.data;
});

How can I send packets between the browser and server with socket.io, but only when there is more than one client?

In my normal setup, the client will emit data to my server regardless of whether or not there is another client to receive it. How can I make it so that it only sends packets when the user-count is > 1? I'm using node with socket.io.
To do this you would want to listen to the connection event on your server (as well as disconnect) and maintain a list of clients which are connected in a 'global' variable. When more than 1 client is connected send out a message to all connected clients to know they can start sending messages, like so:
var app = require('express').createServer(),
io = require('socket.io').listen(app);
app.listen(80);
//setup express
var clients = [];
io.sockets.on('connection', function (socket) {
clients.push(socket);
if (clients.length > 1) {
io.socket.emit('start talking');
}
socket.on('disconnect', function () {
var index = clients.indexOf(socket);
clients = clients.slice(0, index).concat(clients.slice(index + 1));
if (clients.length <= 1) {
io.sockets.emit('quiet time');
};
});
});
Note: I'm making an assumption here that the socket is passed to the disconnect event, I'm pretty sure it is but haven't had a chance to test.
The disconnect event wont receive the socket passed into it but because the event handler is registered within the closure scope of the initial connection you will have access to it.

Socket.io 0.7 can not call broadcast.send?

in socket.io 0.6, i have following example code:
var io = require('/usr/lib/node_modules/socket.io');
var server = http.createServer(function(req,res){
var path = url.parse(req.url).pathname;
switch( path ){
....
//core codes
socket.broadcast(data);
}
}).listen(8080);
// ... ...
var socket = io.listen(server);
and everything going ok.
But now i have renew the socket.io to 0.7 and have changed the socket.broadcast to socket.sockets.broadcast.send(data) ;
Got an exception : can not call send of 'undefined'?
Who can tell me how can i send data to everybody without listening on a certain event?
Maybe here is a way:
clients = new Array();
socket.on('connection',function(socket){ clients.push(socket);}
// ...
for(s in clients) s.send(data);
// ...
does it really needed to do like this way?
Thanks!
In socket.io 0.7 you do:
io.sockets.send() // broadcasts to all connected users
io.sockets.json.send() // broadcasts JSON to all connected users
io.sockets.emit('eventname') // broadcasts and emit
or to namespaces
io.of('/namespace').send('msg'); // broadcast to all connect users in /namespace
you can just do
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.broadcast.emit('user connected');
});
Use
sioServer.sockets.on('connection', function (client) {
client.broadcast.send('Hello, Everybody else!');
});
to broadcast to every other connected client (that is except the broadcasting client himself) and use
sioServer.sockets.on('connection', function (client) {
sioServer.sockets.send('Hello, Everybody!');
});
to broadcast to everybody (including client himself).

Resources