Socket.IO define namespace in runtime - node.js

In socket.IO there are 2 ways to send message to users separately: rooms and namespaces. In my project I need both of them - namespaces to divide users of different applications and rooms for each namespace for private messages and other specific stuff.
It's quite easy to create rooms directly in runtime. But is it possible to do the same trick with namespaces? I'd like to do something like this:
io.of(*someFunctionToCreateNameSpaceInRuntime*)
.on('connection', function (socket) {
socket.emit(***);
});
There is very similar question, but id doesn't work now. Is it possible to send namespace name with params and store it somewhere before connection event fires?
Thanks for any advise.

Related

How to build Slack clone using socket.io

We are building a slack clone, where could be many organizations, which each organization have multiple rooms or channels like slack.
I have 2-3 mongo models to save messages:
model conversations{
id: Int
participants:[userIds]
date:Date
lastMessage:Message
}
model message {
id:Int
body:String
conversationId: Conversation
date:Date
}
model User {
id:Int
name:Sting
organisationId:Organisation
}
model Organisation {
id:Int
name:String
}
Each organization can have many rooms/ channel and the user can be in that room/channel.
I'm thinking to use new socket.io namespace for each organization. Each namespace im using socket.io rooms as channels, where users can subscribe to rooms and communicate
I'm not sure how the client will create namespace for each organization, how in each namespace can create rooms as there is no room concept in socket.io client side.
I just want someone who can help me understand how can i implement namespaces and rooms in socket from client and also on server side.
I know how to listen to events and and send to events in general, but not sure how to go about this.
I remember I made an online game with socket.io.
The flow was simple, some user was able to create their own room and some of them was able to join their rooms.
I think you should use this method. By creating a channel by an Organization or a user, you should start listening to the room.
the namespace should be the name of the room.

socket.io: Is is possible to intercept a join namespace request?

My Node.js knowledge is fairly basic. I'm using socket.io to create a server and socket.io-client-swift in an iOS app.
I would like the server to create a dynamic namespace depending on the users selection on the client app. The idea being that all users with a specific selection join the same namespace on the server. This allows messages to be broadcast to all of those users within the namespace.
The problem is that the socket.io documentation and code appears to assume that you will be hardcoding the namespace name in the node.js code and that the namespace will be defined before the client iOS code attempts to join it.
Here's what i would like to occur:
Client requests to join a namespace called 'abc'.
Server receives request.
Something on the server checks the request, figures out there is no current namespace for 'abc' and dynamically allocates one.
Server finishes processing the join request, connecting the socket to the newly created namespace.
It's step #3 that I'm having problems with. I've tried using io.use(function(socket, next){...} to intercept the incoming request, but it appears that occurs after the server has determined whether there is a matching namespace for the request.
Does anyone have any idea how to intercept an incoming namespace request?
I think I figured it out. I added some code to my server.js like this:
// Lets Swizzle in some wrapper code.
//var originalConnection = Client.prototype.connect;
Client.prototype.originalConnect = Client.prototype.connect;
Client.prototype.connect = function(name){
var nsp = io.nsps[name];
if (!nsp) {
io.of(name);
}
this.originalConnect(name);
};
Effectively I swizzled in a wrapper function that does the dynamic namespace creation.

Trying to broadcast socket.io message to all connected sockets in e.g. room

Challenge:
I would like to use SailsJS, and be able to join a room, by means of socket.io, and receive unsolicited messages from this room, not just when one enters or leaves the room but also receive objects.
So several clients connect to the server.
Afterwards broadcast (initiated from the server) messages/objects to every room and thus everey connected socket in this room.
I maybe could just send every connected socket a message, but dearly would like a example on how to do this with SailsJS 0.10, and a elegant method in the SailsJS 0.10 way.
I am looking at : https://github.com/balderdashy/sailsChat, but I think this is to close to the models themselves, with like e.g: autosubscribe: ['destroy', 'update']
In my opinion this should be more loosely coupled, and not so tied to the model itself.
Thanks in advance!
I.
The purpose of the SailsChat example is to demonstrate how Sails JS resourceful pubsub can take a lot of hassle out of socket messaging when you are mainly concerned with sending messages about models. The fact that you can make a full-featured chat app in Sails with very little back-end code is what makes it impressive. For situations where resourceful pubsub is not appropriate--or if you just plain don't want to use it--Sails exposes lower-level methods on the sails.sockets namespace. The docs are pretty clear on how they work.
To join a socket to an arbitrary room, do sails.sockets.join(<socket>, <roomName>), where <socket> is either a raw socket (probably from req.socket or a socket ID).
To broadcast a message to all sockets in a room, do sails.sockets.broadcast(<roomName>, <data>).
These and more methods are described in detail in the Sails JS documentation.
I'm just starting with SailsJS, and already a big fan.
I need to find out if this is also scalable with e.g. Heroku or other flavors of SAAS providers, but seems not that hard.
So just a follow up on what I did with SailsJS 0.10:
Server-side:
Made a controller with the following:
join: function (req, res) {
if (req.isSocket === true) {
sails.sockets.join(req.socket, 'mysecretroom');
return res.send(200, 'joined');
}
return res.send(200);
},
sendToRoom: function( req, res ) {
if (req.isSocket === true ) {
sails.sockets.broadcast('mysecretroom', 'messageevent', {message:'Listen very carefully, I'll shall say this only once..!'});
}
return res.send(200);
}
Client-side:
io.socket.on('messageevent', function (data) {
console.log(data);
})
+1 kudos #sgress454!
Thanks!

One socket joins several namespaces

I have an application that uses several namespaces to differentiate between different kind of clients, so since the beginning I separate them in this manner (I'm using cluster and spawn 4 processes)
//server code
io.of("/TYPE_ONE").on("connection", function(socket){
console.log("Client connected to TYPE_ONE with id:\t"+socket.id+"\t"+process.env.NODE_WORKER_ID);
});
io.of("/TYPE_TWO").on("connection", function(socket){
console.log("Client connected to TYPE_TWO with id:\t"+socket.id+"\t"+process.env.NODE_WORKER_ID);
});
//client code
//for type one
socket = io.connect("http://mydomain.com/TYPE_ONE", socketOptions);
//different files always, only one type sent to each client
//for type two
socket = io.connect("http://mydomain.com/TYPE_TWO", socketOptions);
All of a sudden, after looking at the console, when a single client connects and I get the following output:
Client connected to TYPE_ONE with id: 1234 3
.
.
.
Client connected to TYPE_TWO with it: 1234 3
(same id and workerId as previous connection)
I'm certain that there is only one connection being made to the server, t
I'm wondering what could be causing this? Because Ive looked through my code, and simplified the methods to the stubs I just showed, and can't seem to find the issue.
Thanks for your help.
There are no errors in your code: you have only one connection, therefore socket connects to namespaces with one socket.id. I don't know how to make many connections, maybe you should try two ports of connection, or connect/listen server multiple times.
To solve your problem i would use one connection, but think about how to sturcure your site. For example, use rooms and store in session NEW user id's to figure out in what room or namespace to put user.
"Multiple namespaces and multiple rooms can share the same (WebSocket) connection"
socket.io rooms or namespacing?
If you want to differentiate clients, you can put theme in another rooms in one namespace and having their socket.id check in what room they are (or join rooms with socket.id name (.joind(socket.id)).
https://github.com/LearnBoost/socket.io/wiki/Rooms
It turns out, at some point in my code, I had a io.of("/TYPE_ONE").socket(socket.id).emit(message); and that socket belonged to the namespace TYPE_TWO, so it seems whenever you send a message to a socket from a namespace to which he isn't connected, this will automatically connect it to that said namespace. Weird though.

Socket.IO messaging to multiple rooms

I'm using Socket.IO in my Node Express app, and using the methods described in this excellent post to relate my socket connections and sessions. In a comment the author describes a way to send messages to a particular user (session) like this:
sio.on('connection', function (socket) {
// do all the session stuff
socket.join(socket.handshake.sessionID);
// socket.io will leave the room upon disconnect
});
app.get('/', function (req, res) {
sio.sockets.in(req.sessionID).send('Man, good to see you back!');
});
Seems like a good idea. However, in my app I will often by sending messages to multiple users at once. I'm wondering about the best way to do this in Socket.IO - essentially I need to send messages to multiple rooms with the best performance possible. Any suggestions?
Two options: use socket.io channels or socket.io namespaces. Both are documented on the socket.io website, but in short:
Using channels:
// all on the server
// on connect or message received
socket.join("channel-name");
socket.broadcast.to("channel-name").emit("message to all other users in channel");
// OR independently
io.sockets.in("channel-name").emit("message to all users in channel");
Using namespaces:
// on the client connect to namespace
io.connect("/chat/channel-name")
// on the server receive connections to namespace as normal
// broadcast to namespace
io.of("/chat/channel-name").emit("message to all users in namespace")
Because socket.io is smart enough to not actually open a second socket for additional namespaces, both methods should be comparable in efficiency.

Resources