Cyclical reference in chat program - javascript

I wrote a chat program in Node.js. The server manages a list of rooms in a class called RoomManager with an object this.rooms. Whenever a command is sent to the server from a client, it goes into a router. Most of the commands deal with rooms (sending messages to rooms, joining rooms, creating rooms..). The command message must always have a room ID in it. The server must always try and find the room first:
roomManagerGetRoom(roomName){
return this.rooms[roomName] || null;
}
Since the rooms object will eventually get large, I figured the clients should keep their own references to what rooms they are in. That way, the server could first try and find the room from the client's own list which would be much smaller, 1-4 rooms on average.
However, this creates a cyclical loop
RoomManager requies Room requires ClientManager requires Client requires RoomManager requies Room requires ClientManager requires Client ...
So 1.5 questions:
How much speed would I be gaining by first looking through Client's own list?
If it's significant, how do I avoid the cyclical issue?

Related

socket.io emit to everyone except for some certain clients

In my Node.js server, I have an array of client IDs, and I have a socket that I want to send to all connected clients except for the clients I have in that array, so I want to emit to all clients excluding some clients that i have defined by id, is that possible?
Answering my own question after some research.
One thing you could do is to add the clients you want to exclude inside of a Scoket.io room and then emit to everyone except for that room, like shown below:
io.except("room1").emit(/* ... */); // to all clients except the ones in "room1"
Note that this feature was implemented in version socket.io#4.0.0.
here is documentation for it

socket.io without using default namespace/room feature

I found it's easier to just setup own custom path for multiple endpoints like this
server side:
io.on('connection', function(client) {
var username = client.handshake.headers.users[0].username;
client.on(username+'_con1', function(data) {
io.emit(username+'_con1',data);
});
client.on(username+'_con2', function(data) {
io.emit(username+'_con2',data);
});
}
Is above approach correct? at least I'm able to make it work.
Depending on what you mean by correct. This will create multiple events for the client.
Its hard to say if this is the best/correct way without any context. But you should look into namespaces and rooms and decide for yourself! http://socket.io/docs/rooms-and-namespaces/
Creating unique message names for each client makes it seem like you plan on sending a message to all clients and only some clients will be listening for the message directed at them. This is not a very efficient way to do things.
Rooms in socket.io are designed such that you can have a common message name (no need for a unique message name for each client) and then send that message only to the clients that it is intended for. That's a lot more efficient scheme.
Now, of course, you could create the unique message name for each client and then only send it to the desired client, but why bother with the extra complication of the unique message name. You don't need it if you're only sending the message to the intended client.
So, you could certainly make your scheme work, but it does not seem like it's the simplest way to do things and, depending upon other details of your implementation, it may not be the most efficient way to do things either.
A namespace is more like connecting to a particular channel. The client decides what channel they want to connect to. The server then decides which namespace to send a given message to.
A room is a something a server subscribes a client to in order to make it easy to send a specific set of clients the same messages or in some cases to share incoming messages from one client with all the other clients in a room (like in chat).

socket.io leave room after emitting to it

I would like to know when emit process to a room is done in order to leave room right after.
Is it OK to leave the room right after emit?
I tried using a callback in emit to room but got a server error so I guess it's not possible.
Since I imagine that it's an async process, leaving the room right after emit might not be safe (in a large scale).
Thoughts?
//join all friends to a room
Socket.join(SOME_ROOM);
//send data to this room
io.to(SOME_ROOM).emit('SOME_EVENT', SOME_DATA); //cb function fails if I add one
//leave room
Socket.leave(SOME_ROOM); //is it safe?
It is safe to leave the room immediately after calling .emit(). The room is only used to figure out which sockets you intend to send to and that is done synchronously in the io.to() call so that is all figured out by the time the .emit() call returns.
Even if the actual sending of the data to those sockets id done asynchronously (which it is), it no longer matters whether the socket is still in the room or not. The room was only used to initially select which sockets to send to and is not used in the actual sending process itself.
Keep in mind that while a room sounds like an all-powerful concept, all it really is under the covers is a list of sockets.
So, you should be able to do this just fine:
//join all friends to a room
Socket.join(SOME_ROOM);
//send data to this room
io.to(SOME_ROOM).emit('SOME_EVENT', SOME_DATA);
//leave room
Socket.leave(SOME_ROOM);

Ajax polling chat gets duplicates at message receiver front-end on speedy chat

I have developed a javascript chat (php on the backend) using:
1) long-polling to get new messages for the receiver
2) sessionStorage to store the counter of messages
3) setInterval to read new messages and if sessionStorageCounter < setIntervalCounter then the last message is shown to receiver.
4) javascript to create,update and write the chat dialogues
The module is working fine, but when users have a speedy chat the receiver' front end gets two or three same messages, (neither the counter fails, nor the query provides double inserts).
The code seems to be correct (that's why I don't provide the code), so the interval delay might be the reason (on reducing interval delay, nothing changes).
Do you think that the above schema is a bad practice and which schema do you think would eliminate the errors?
My approach, if solving it myself (as opposed to using an existing library that already handles this) would be:
Have the server assign a unique ID (GUID) to each message as it arrives.
On the clients, store the ID of the most recently received message.
When polling for new messages, do so with the ID of the last message successfully received. Server then responds by finding that message in its own queue and replaying all of the subsequent messages.
To guard against 'dropped' messages, each message can also carry the ID of the immediately-previous message (allowing the client to do consistency-checking)
If repolling does cause duplicates to be delivered from server to client, the presence of unique IDs on each message makes eliminating them trivial. Think of the server-side message queue as an event stream, with each client tracking their last-read position. The client makes no guesses about the appropriate order of messages, how many there are, etc - because its state consists entirely of 'what have I seen', there are few opportunities to get out of sync.
Since it's real time chat, the setInterval interval is probably small enough to ask the server for new messages two or three times simultaneously. Make sure that the server handler is synchronized and it is ignoring duplicated queries from the same user.

Run different instances in nowjs

I create a server using nowjs. How can I serve clients grouped under an URL.
It's a wague way of putting the question. I ll give an example.
I run my server(with nowjs) in mysite.com which contains many chat rooms.
Users can join one of the chat rooms and start chatting. Real time sync happens - all handled by nowjs.
Now coming to my problem, I'm not able to differentiate between the chat rooms. Whatever chatroom user joins, since I'm using the everyone object, every user gets a message (independent of which chat room he is in).
use a group object.
I solved this issue by using
everyone.now.distributeMessage = function(message,groupname){
group = nowjs.getGroup(groupname);
group.now.receiveMessage(this.now.name, message, groupname);
}
everyone has access to that function, and by passing the groupname, only those who are members of that group get the message.

Categories

Resources