Send messages from server to client socket.io - javascript

I am trying to send a message from NodeJS server to client using socket.io
However, I found the same practice all over the internet, which is wrapping the emit with io.on('connection', handler) and then making the server listen on a special "channel" event like so:
var io = require('socket.io')();
var socketioJwt = require('socketio-jwt');
var jwtSecret = require('./settings').jwtSecret;
var User = require('./models/users').User;
io.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
var sockets = [];
io.on('connection', function(socket) {
sockets.push(socket);
});
sendLiveUpdates = function(gameSession) {
console.log(sockets);
}
exports.sendLiveUpdates = sendLiveUpdates;
exports.io = io;
My problem is: I want to emit messages outside this on connection wrapper, example from my routes or other scripts. Is it possible?
Thanks.

Yes. You just need to keep a reference to the socket.
// Just an array for sockets... use whatever method you want to reference them
var sockets = [];
io.on('connection', function(socket) {
socket.on('event', function() {
io.emit('another_event', message);
});
// Add the new socket to the array, for messing with later
sockets.push(socket);
});
Then somewhere else in your code...
sockets[0].emit('someEvent');
What I usually do is assign new clients a UUID and add them to an object keyed by this UUID. This comes in handy for logging and what not as well, so I keep a consistent ID everywhere.

Related

Express-generator, Socket.io Event issuing multiple times

I have create a node app using express generator. I have integrated socket.io in the application. Since express generator has their own way of creating express server i have followed this procedure to successfully integrate the Socket connection with listening server and made the io available throughout the application via res.io instance.
FILE: bin/www
#!/usr/bin/env node
var app = require('../app').app;
var debug = require('debug')('www:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = require('../app').server;
/app.js
//Express handler
var app = express();
// Socket configuration
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.use(function(req, res, next){
res.io = io;
next();
});
...
module.exports = {app: app, server: server};
But the problem is when i m emitting an event as shown below. My client is reading the data multiple times.
routes/index.js
var clients = 0;
var nsp = res.io.of('/default-namespace');
nsp.on('connection', function (socket) {
clients++;
console.log(clients + ' clients connected!');
socket.on('disconnect', (reason) => {
clients--;
console.log(clients + ' clients connected!');
});
nsp.emit("socketToMe", "New User connected. Current clients:"+ clients);
});
My listener has the following code:
home.pug
var socket = io('/default-namespace');
socket.on('socketToMe', function (data) {
$('#data-div').append($('<li>').text(data));
});
Whenever i refresh the browser in another instance like incoginito my main browser is showing multiple events for the data. Like this
New User connected. Current clients:1
New User connected. Current clients:2
New User connected. Current clients:1
New User connected. Current clients:2
New User connected. Current clients:1
New User connected. Current clients:1
Not sure what is wrong. Can anyone help me on this?
Nodejs is event driven.The res object is not a global variable.
Express middleware runs for every request.
var clients = 0;
var nsp = res.io.of('/default-namespace');
nsp.on('connection', function (socket) {
clients++;
console.log(clients + ' clients connected!');
socket.on('disconnect', (reason) => {
clients--;
console.log(clients + ' clients connected!');
});
nsp.emit("socketToMe", "New User connected. Current
clients:"+clients);
});
Let me explain what happens above.A user requests and req handler is fired and you access the res object and you listen for events.
So for each request, you are listening for socket 'connection' event.That means you are setting multiple event listeners with the same name.Every time you make a request you set a new listener.
You are supposed to set only a single 'connection' listener.
This explains emitting the same event multiple times.
app.use(function(req, res, next){
res.io = io;
next();
});
Instead of using the above middleware function,listen directly on io instance

Express - socket.io - session. Refer to user id as socket id

I am using express-socket.io-session. I think I was able to setup the basic config by seeing the tutorials:
//BASIC CONFIG?
var clients = [];
var session = require("express-session")({
secret: 'some key',
resave: true,
saveUninitialized: true
});
var sharedsession = require("express-socket.io-session");
app.use(session);
io.use(function(socket, next){
next();
});
io.use(sharedsession(session, {
autoSave:true
}));
io.on('connection', function(socket) {
console.log("CLIENT CONNECTED");
var session = socket.handshake.session;
clients.push(socket);
socket.on('disconnect', function() {
console.log("CLIENT DISCONNECTED");
});
});
What I want to be able to do now is to refer to a specific client socket not by the socket but by the session id that should be assigned to that socket. When a user logins this happens:
req.session.user_id = user_id;
//(user_id is equal to DB {0,1,2,3...} ids
I was able to send sockets to specific clients when I did this:
clients[0].emit("to_do",info); // I don't know who is client index 0 compared to the login reference...
I would like to be able to do this or similar:
user_id = 3; // which would have a socket assigned
clients(user_id).emit("to_do",info);
That would mean each client would have a socket assigned to its previously assigned id. How could I do this so I could specify the socket by that id? I am not experienced at all with all of this so sorry for any big mistakes. Thanks
Your problem can be solved by each socket joining a group named after it's id:
socket.join(socket.id);
io.sockets.in(socket.id).emit('to_do', info);
//or
io.sockets.in(clients[0].id).emit('to_do', info);
Well I solved this out by iterating through the clients list and seeing which one had the socket I wanted
I ran into a similar issue, when using express-socket.io-session the user ID in socket.handshake.session.passport changes when a new user login, I used the below to solve it.
var userID;
if (!userID){
userID = socket.handshake.session.userID = socket.handshake.session.passport['user'];
}

Unable to persist a sockets array upon user connection

I have these two files:
io.js:
var io = require('socket.io')();
var socketioJwt = require('socketio-jwt');
var jwtSecret = require('./settings').jwtSecret;
io.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
io.on('connection', function(socket) {
IO.pushSocket(socket);
});
var IO = module.exports = {
io: io,
sockets: [],
pushSocket: function(socket) {
if (typeof IO.sockets === 'undefined') {
IO.sockets = [];
}
IO.sockets.push(socket);
console.log(IO.sockets);
}
}
main.js:
var sockets = require('./io').sockets;
console.log(sockets); \\ output is []
As you may notice, upon user connection I am trying to push to the sockets array in the IO module. But when I log the array in main.js it always returns as empty array. Any idea ?
Thank you.
You're fetching require('./io').sockets before the code (in pushSocket()) actually creates the array.
You cannot read an array before it exists.
You probably want to create the array immediately, so it will exist before you try to read it.
I'd suggest a bit of a different solution. You don't need to keep track of your own array of connected sockets at all because socket.io already does that for you. It provides both an array of sockets and a map of sockets (indexed by socket id):
// io.js
var io = require('socket.io')();
var socketioJwt = require('socketio-jwt');
var jwtSecret = require('./settings').jwtSecret;
io.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
io.on('connection', function(socket) {
// whatever you want to do here
});
module.exports = io;
Then, to use that module, you can do this:
// main.js:
var io = require('./io');
// then sometime later AFTER some sockets have connected
console.log(io.sockets.sockets); // array of connected sockets
Here are some of the data structures you can use from the io object:
io.sockets.sockets // array of connected sockets
io.sockets.connected // map of connected sockets, with socket.id as key
io.nsps // map of namespaces in use
io.nsps['/'].sockets // array of connected sockets in the "/" namespace (which is the default)
io.nsps['/'].connected // map of connected sockets in the "/" namespace
If you want to then track connect and disconnect events from outside the io module, you can just directly subscribe to the connection and disconnect events without having to invent your own scheme for it:
// main.js:
var io = require('./io');
io.on('connection', function(socket) {
// new socket just connected
console.log(io.sockets.sockets); // array of connected sockets
socket.on('disconnect', function() {
// socket just disconnected
});
});

How can I have faye-websockets code running in the browser?

I'm new with node.js/express and all and I want to be able to notify any clients in browser about a new message received from some algorithm in the back-end. The publisher algorithm connect to the websocket and writes the message.
As far as I've looked there were examples which recommended websockets but I haven't been able to run that code in browser only in console.
Example client code:
var WebSocket = require('faye-websocket');
var ws = new WebSocket.Client('ws://localhost:1234');
var http = require('http');
var port = process.env.PORT || 1235;
var server = http.createServer()
.listen(port);
// receive a message from the server
ws.on('message', function(event) {
alert(JSON.parse(event.data));
});
Thank you
Found the answer after some trial/error iterations.
The algorithm now does a POST to an URL which in turn triggers a write to sockets for all connected clients via socket.io.
Client code:
var socket = io('http://localhost:7777');
socket.on('message', function (msg) {
document.body.insertAdjacentHTML( 'beforeend', '<div id="myID">'+msg+'</div>' );
});
And on the server, when client connects I retain it's socket into an array so I can write to each one:
Server code:
io.on('connection', function(socket){
console.log('a user connected: '+socket.id);
var id = clientCount++;
clientSockets[id] = socket;
socket.on('disconnect', function(){
console.log('user disconnected');
delete clientSockets[id];
socket = null
});
});
app.post('/alerts', function(req, res) {
req.accepts(['json', 'application']);
console.log("Algo did a POST on /alerts!");
// send the message to all clients
//console.log(req.body);
for(var i in clientSockets) {
clientSockets[i].send(JSON.stringify(req.body));
}
res.send(200);
});
In conclusion, I'm not using faye-websockets but instead socket.io

Event emitter inside of event emitter using socket.io node.js

i have a situation where i have web-socket server and OSC message client. I need to send data to all socket users when i recieve a message from OSC server. So far i just placed the OSC event inside of socket.io connection function, thus it created a memory leak. Because it create a new event emitter for the global variable "oscServer". How do i avoid that?
var io = require('socket.io')(server);
var oscServer = new osc.Server(oscPorts.server, oscIp.server);
io.on('connection', function (socket) {
oscServer.on(oscAdress.server, function (msg, rinfo) {
socket.broadcast.emit('moved', msg);
});
});
I would try saving a reference to socket, the only caveat - you'll need to ensure that var socket isn't undefined, so I would use a promise to make sure that socket is defined before broadcasting your event.
var io = require('socket.io')(server);
var oscServer = new osc.Server(oscPorts.server, oscIp.server);
var socket;
io.on('connection', function (s) {
socket = s;
});
oscServer.on(oscAdress.server, function (msg, rinfo) {
socket.broadcast.emit('moved', msg);
});

Categories

Resources