Using sockets outside their dedicated 'connection' scope - node.js

I'm making a node.js app with sockets.io.
The logic of my app needs to communicate to client through their respective sockets, but the problem with sockets is they're in their own "domain" of code.
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
// socket object is only available here
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
See?
I tried to export this socket object out
var Sockets = []
io.sockets.on('connection', function (socket) {
Sockets[socket.handshake.user.id] = socket;
});
Now it's available outside
function myLogic(userid) {
Sockets[userid].emit('free!')
}
But I'm facing weird bugs because it's probably not supposed to be used this way... like new connections make new socket objects but previous ones still exist somewhere in memory and they still react when their .on('..' gets fired...
What is the correct way to use sockets outside of their respective io.sockets.on('connection', function(socket){} scope?

Answering your question: if you want to use sockets outside of their respective "io.sockets.on('connection', function(socket){} scope", you have to access them through the io object --> io.sockets.socket(socketId), where socketId is stored somewhere.

Make a setup function for your module and pass it the initialized socket thing. Ie. something like this from main.js:
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var myModule = require('./myModule').setup(io);
Then in your myModule.js save a reference to the io object:
var localIo;
exports.setup = function(io) {
localIo = io;
};
// Then after in your other code....
function myLocalFunction(myData) {
localIo.sockets.volatile.emit('myevent', {data: myData});
};

Related

I have a two node js servers. second server is for the socket connection. How do I establish a connection between these two servers?

I'm setting up another nodejs server for the socketio, which is index.js. so I have two servers one is app.js and other one is index.js. so how do i establish a connection between these two servers?
If I correctly get what you wanted to do. You wanted to separate the file of the recieving of socket. Here's my code below.
on your app.js
var app = Express();
var server = require('http').createServer(app);
var io = SocketIo.listen(server);
server.listen(function(){
require('/path/of/your/index.js')(io);
})
and on your index.js
module.exports = function(io){
io.on('connection', function(socket){
*your codes here*
});
}
Can you please explain your problem in detail.And second thing, I don't understand why you want to establish two servers.Because you can always connect socket.io using your Node server.The code for it is below:
//Server side code
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');
app.listen(80);
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
//Client Side code
var socket = io.connect();
socket.emit('my other event', {
data : 'Hello'
});
This is very basic example for client-server communication using socket.io
I hope you will get your answer.

Socket.io Best coding practice

I'm developing a Node.js application which uses Socket.io to handle the real time communication. My code is full of On and Emit functions. I use room feature as well. my app looks like this:
var server = require('http').Server();
var io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('event1', function(data){"lots of socket and non-socket codes" });
socket.on('event2', function(data){"lots of socket and non-socket codes" });
socket.on('event3', function(data){"lots of socket and non-socket codes" });
socket.on('disconnect', function(){"Some other code"});
});
server.listen(portNum);
it works fine but It is not my ideal solution.
Firstly, in this approach everything is in one big file instead of smaller file with isolated functionality.
secondly, it is quite difficult to debug and maintain this app as it is quite messy when it comes to 1000+ lines of code.
Here is my question:
Is there a preferred/best practice on developing enterprise quality Socke.io applications?
If yes, Is there any large opensource Socket.io application that demonstrait this approch or any article which help me to refactor my code in a better fassion?
I think starting by putting every callback function in a different function that you put out of io.on('connection'), and maybe also put them in a different file (using module.exports), you will start having a clearer application.
Ok so i will write you one possibility that i use, i don't know if it's the best pattern of the universe for socket.io, but that's good i think.
In your main file (the file with io.onconnection), you can have something like this (you dont have to use namespace, it's just an example) :
var SocketEvent = require('./socketEvent');
io.of('/user').on('connection', function (socket) {
SocketEvent.load_common_event(socket);
SocketEvent.load_user_event(socket);
});
io.of('/operator').on('connection', function (socket) {
SocketEvent.load_common_event(socket);
SocketEvent.load_operator_event(socket);
});
And in the socketEvent.js that you load you can have this :
exports.load_common_event = function(socket){
socket.on('disconnect', function(){"Some other code"});
};
exports.load_user_event = function(socket){
socket.on('event1', function(data){"lots of socket and non-socket codes" });
socket.on('event2', function(data){"lots of socket and non-socket codes" });
socket.on('event3', function(data){"lots of socket and non-socket codes" });
};
exports.load_operator_event = function(socket){
socket.on('event4', function(data){"lots of socket and non-socket codes" });
socket.on('event5', function(data){"lots of socket and non-socket codes" });
socket.on('event6', function(data){"lots of socket and non-socket codes" });
};
Let me know if you have any question
Add-on
If you want something like Socket.on('event' , myModule.doSomething);
you can do like this i guess in the module :
client :
var myModule = require('./socketModule');
io.on('connection', function (socket) {
socket.on('event' , myModule.doSomething(/*some parameters (socket)*/));
});
server socketModule.js :
exports.doSomething = function(/*some parameters (socket)*/){
/* Some processing around */
};
For those who are wondering about pass paremeters, .bind could be an option
const events = require('./events.js')
io.of('/chat').on('connection', (socket) => {
socket.on('print', events.print.bind({socket, io}))
})
event.js
const util = require('util')
function print(data) {
console.log(util.inspect(this.socket).substr(0, 100))
console.log(util.inspect(this.io).substr(0, 100))
}
module.exports = {
print
}
More use of pages, less code in each, share them independently when needed:
Note I assume you are working with express. If not, just remove express from my demos.
// app.js
var app = require('express')();
module.exports = app;
// server.js
var app = require('./app');
var server = require('http').createServer(app);
module.exports = server;
//socket-io-redis.js
var server = require('../server');
var io = require('socket.io')(server);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
io.set('origins', '*:*');
module.exports = io;
Now on every page on your API or on your server you can just import the Io instance (reference and efficient) like this:
var Io = require('../path/to/io-config-file');
console.log(Io); // object
Io.to(room).emit(event, payroll);
You can also make a main connection file like this:
Note I'm pasting here the exact code that I actually use, just in order to show you some of my best practices (of course, adapt and adjust this as your needs):
var { Io } = require('#dependencies/_index');
var Defaults = require('#helpers/defaults');
var _index = require('./services/_index');
const {
validate,
get_user,
subscribe
} = _index;
Io.on("connection", socket => {
socket.on("join", async info => {
await validate(info);
await subscribe(await get_user(info), info, socket, 'join');
});
socket.on("leave", async info => {
await validate(info);
await subscribe(await get_user(info), info, socket, 'leave');
});
});
In the example above, I listen for new connections and securely verified subscribe them to the respective rooms. I am using services in order to so - they are independent as I said that's how all your code should be like.

How to use socket.io with the latest mean.io?

I have fetched a copy of the latest Mean.io and noted quite a number of changes compared to the previous version I have been working with before. Now, what I am doing is creating a very basic chat application that uses socket.io with rooms. Following the basic setup in the Socket documentation I have to implement the following:
var app = require('express')()
, server = require('http').createServer(app)
, io = require('socket.io').listen(server);
server.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Where would I define the basic socket room setup?
socket.set("log level", 1);
var people = {};
var rooms = {};
var clients = [];
You can set the socket.io to listen on your server on
/server/config/system/bootstrap.js
Require the socket.io module
var express = require('express'),
appPath = process.cwd(),
io = require('socket.io');
Now set the socket.io to listen on your app
// Express settings
var app = express();
require(appPath + '/server/config/express')(app, passport, db);
io = io(app.listen(3000));
return io;
Then you need to inject the socket.io object into your app on bootstrapDependencies() function.
function bootstrapDependencies() {
...
// Register socket.io dependency
mean.register('io', function() {
return io;
});
}
Mean.uses this project for its dependency injection
https://www.npmjs.org/package/dependable
Finally you need to configure your app to listen on every socket connections
probably you want to do these on your main app's router at
/server/routes/index.js
Sample connection handler
var io = require('meanio').io;
io.on('connection', function (socket) {
// emit data to the clients
socket.emit('news', { hello: 'world' });
// event listeners
socket.on('my other event', function (data) {
// call your controller function here
Controller.action(data);
});
});
And more importantly, don't forget to setup socket.io on the client side.
// on '/server/views/includes/foot.html'
<script src='/socket.io/socket.io.js'></script>
<script>
var socket = io();
</script>
I've just responded to another SO post (Mean.io framwork with socket.io).
Note: I'm using mean.io v0.5.26 and socket.io v1.1.0.
Pasting my answer again, here.
I also faced the same issue and took me about a week to finally get it right. I'll try to explain what I did:
app.js
In this file, I just invoke the code that creates and sets up a socket.io object for me, which is then passed to the routes module.
'use strict';
/*
* Defining the Package
*/
var Module = require('meanio').Module;
var MeanSocket = new Module('chat');
/*
* All MEAN packages require registration
* Dependency injection is used to define required modules
*/
MeanSocket.register(function(app, http) {
var io = require('./server/config/socketio')(http);
//We enable routing. By default the Package Object is passed to the routes
MeanSocket.routes(io);
return MeanSocket;
});
server/config/socketio.js
This file simply configures the socket.io object. Please note that I had to upgrade meanio module to version 0.5.26 for this work, as http object (express server) is not available in older meanio versions. Moreover, in case you want to use ssl, you can inject https instead of http.
'use strict';
var config = require('meanio').loadConfig(),
cookie = require('cookie'),
cookieParser = require('cookie-parser'),
socketio = require('socket.io');
module.exports = function(http) {
var io = socketio.listen(http);
io.use(function(socket, next) {
var data = socket.request;
if (!data.headers.cookie) {
return next(new Error('No cookie transmitted.'));
}
var parsedCookie = cookie.parse(data.headers.cookie);
var sessionID = parsedCookie[config.sessionName];
var parsedSessionID = cookieParser.signedCookie(parsedCookie[config.sessionName], config.sessionSecret);
if (sessionID === parsedSessionID) {
return next(new Error('Cookie is invalid.'));
}
next();
});
return io;
};
routes/chat.js
Finally, use the routes file to define the socket events, etc.
'use strict';
// The Package is passed automatically as first parameter
module.exports = function(MeanSocket, io) {
io.on('connection', function(socket) {
console.log('Client Connected');
socket.on('authenticate', function(data, callback) {
});
});
};
Hope this helps!
The latest update v0.4.0 requires another strategy to get socket.io setup. I'm currently in discussion with one of the project contributors to validate my solution. I'll make sure to update my response once I'm 100% sure.
The meanio package is now where the bootstrap functionality is located, as well, where express setup is being called from.
Looks like the mean.io guys have recently released an official Socket.io implementation that integrates directly with their stack. Check it out on Github.

encapsulate a socket.io instance in nodejs

I am trying encapsule a socket.io instance in a module. I did this but it looks a bit messy because i have to inject some dependencies for authentication of the socket transport from express / passport.
My problem is i want to access the socket instance outside of the module like socket.on("newDevice", function (data) {});
The socket instance which i get by the connection event is inside the function and it even may not exist on creation because no connection is established. This simply looks kind of wrong to me. I dont want to inject more and more depencies just because i need them inside of the function scope.
I thought about doing the sio.on('connection', function(socket) {}); outside of the module. And maybe i could do it twice, first inside of the module and then outside but i would create two listeners i guess.
Is there any good practice or pattern how to do this properly?
var io = require('socket.io');
var socket = function (server, sessionStore, cookieParser, authentication) {
var sio = io.listen(server);
// Configure socket.io
sio.configure(function () {
// Authorize the socket.io request
sio.set('authorization', function (data, accept) {
// Authorization is done here
});
});
sio.on('connection', function(socket) {
var lastActionTime = new Date();
// Get the userId from the session
var session = socket.handshake.session;
var userId = session.passport.user;
var sessionID = socket.handshake.sessionID;
var userdata = null;
// Deserialize user by the userId
authentication.deserializeUser(userId, function(err, user) {
// get the userdata
});
socket.on('disconnect', function() {
});
socket.on('brightnessChange', function(data) {
// TODO Do something here device control
// Broadcast to other devices
this.broadcast.emit('brightnessChange', data);
});
});
return sio;
};
module.exports = socket;
I would suggest, the below, flexibility and scales well. I've tried both ways and resulted in using multiple connection events.
I thought about doing the sio.on('connection', function(socket) {}); outside of the module. And maybe i could do it twice, first inside of the module and then outside but i would create
two listeners i guess.

Working with Routes in express js and socket.io and maybe node in general

I am trying to write a multi channel application in socket.io. The channel you are in should be defined by the url you are on. If I do the joining part in the app.js with permanent values everything works. As soon as I change it so that the route for route.page does the joining I get the error, that sockets is not available in the context. What would be the correct way so that I can dynamically join the channel?
/app.js
var io = socketio.listen(app);
require('./io')(io);
io.sockets.on('connection', function (socket) {
socket.on('debug', function (message) {
socket.get('channel', function (err, name) {
socket.in(name).broadcast.emit('debug', message);
});
});
});
/io.js
var socketio = function (io) {
if (!io) return socketio._io;
socketio._io = io;
}
module.exports = socketio;
/routes/index.js
var io = require('../io')();
exports.page = function(req, res){
var channel = req.params.id;
res.render('page', { title: 'PAGE', channel: channel });
io.sockets.on('connection', function (socket) {
socket.join(channel);
socket.set('channel', channel );
});
};
The easiest way I've found to do multiple channels is off of different URLs.
For example I have the client do the following:
io.connect('/game/1')
io.connect('/system')
and on the server I have
io.of('/game/1').on('connect' function(socket) {...})
io.of('/system').on('connect' function(socket) {...})
It looks like I'm connecting twice here, but socket.io is smart enough to use a single websocket for this connection (at least it says so in the how-to-use).

Resources