Socket.io pair rooms - javascript

Im using the opentok and socket.io packages to try and create 2 "groups". I have been able to pair up non grouped users with a 1to1 relationship just fine. What Im trying to do is have 2 groups of users. Lets say one group is a help desk and the other group is a customer. I want all the customers to be grouped together but not connect to one another. I would also like for the same behavior with the help desk group. I then want any 1to1 pair to group together ie. helpdeskTOcustomer. I would provide some code, but from a logical standpoint im not even sure how to begin coding this and the only thing I would be able to provide is just the slightly modified code from here.. http://www.tokbox.com/developersblog/code-snippets/opentok-sessions-using-node-js/

It's not really clear from your question exactly what you're trying to do (e.g. what do you mean by "pair" or "group together"), but you may find some use of Socket.IO's rooms.
Sometimes you want to put a bunch of sockets in one room, and send a message to them [all at once]. You can leverage rooms by calling join on a socket, and then [send data or emit events] with the flags to and in:
io.sockets.on('connection', function (socket) {
socket.join('a room');
socket.broadcast.to('a room').send('im here');
io.sockets.in('some other room').emit('hi');
});
[Edit]
Okay, after seeing your comment and looking over the OpenTok docs a bit (I wasn't familiar with it, it seems pretty neat), it looks like you just want a queue for each type of user, right? Here's a bit of code (more like pseudocode, as I'm not intimately familiar with your app or the OpenTok API):
var customers_waiting = [];
var employees_waiting = [];
io.sockets.on("connection", function(socket) {
// Determining whether a connecting socket is a customer
// or an employee will be a function of your specific application.
// Determining this in this callback may not work depending on your needs!
if(/* client is a customer*/) {
customers_waiting.push(socket); // put the customer in the queue
else if(/* client is an employee */) {
employees_waiting.push(socket); // put the employee in the queue
}
try_to_make_pair();
});
function try_to_make_pair() {
if(customers_waiting.length > 0 && employees_waiting.length > 0) {
// If we have people in both queues, remove the customer and employee
// from the front of the queues and put them in a session together.
customer = customers_waiting.shift();
employee = employees_waiting.shift();
opentok.createSession('localhost', {}, function(session) {
enterSession(session, customer);
enterSession(session, employee);
}
}
}

Related

Trouble understanding sockets.io room

I am trying to configure a 1v1 game with multiple rooms on my server with sockets.io. When the user create a room, a random alphanumeric identifier of 5 letters is generated and the user joins the room.
function handleNewGame() {
let roomName = makeid(5);
client.join(roomName);
}
Then another user is supposed to join with the room name. The room name is taken from a tag inside the html main page and then is sent by a function.
This is the function that handles game joining on server side
function handleJoinGame(roomName) {
const room = io.sockets.adapter.rooms[roomName];
}
All of this is wrapped inside an
io.on('connection', client => {
}
The problem is that at this point, before the other user even tries to join, the room is undefined.
console.log(room);
This gives me undefined.
If I try to actually print out all the rooms, it actually exist, but the method can't find it. What did I do wrong?
Forget the library for a moment. Conceptually, a room is just a group of users. an array of socket connections to whom you broadcast using a for loop. It should come with a room manager since you want to have many rooms otherwise you had single room anyway.
Let's assume an object of arrays.
var roomManager = {
"room12345" : [socket1, socket2, socket5],
"room76432" : [socket3, socket4],
}
and when socket1 wants to broadcast, you know its room room12345 so you broadcast to all others in that room.
So really you can implement this logic yourself quite easily.
Actually, the io.sockets.adapter.rooms returns a Map. Said so, I had to get the room with a key, using
const room = io.sockets.adapter.rooms.get(roomName);
I've solved the issue.

Ideal way to handle multiple socket rooms?

So I am creating a chat application and I want to handle multiple chat rooms. Now I watched some tutorials and came up with a way.
const io = require("socket.io")(http);
io.on("connection", (socket) => {
socket.on("joinRoom", (roomid) => {
//Joining the room
socket.join(roomid)
//Broadcasting all previous messages
io.to(roomid).emit("messages",allPreviousMessages)
})
socket.on("chatMessage", (data) => {
//Saving msg to dB then broadcasting
io.to(roomid).emit("message",receivedMessage)
})
socket.on("disconnect",(data) => {
//updating user's lastSeen info in dB
})
})
So on my frontend when user clicks on a chatroom we call the "joinRoom" event and connect to the room and on clicking another chatroom make the same process of joining room.
Is this an ideal way for handling multiple chatrooms? If not so please let me know a better solution.
I think the best way to implement private rooms or channels or chats is this way. I have implemented an example for these three sections. Link
User token and api must be authenticated before connecting to socket.io. If this part is ok it will connect to socket.io otherwise it can't cause you to see the event that is there. Something happens by calling each of them. For example, by calling this onNotificationForVoiceCall event, the received data is first checked, then it is checked whether this user is present in the list of online users or not, and the state of the next step is checked. Whether or not this room has already been created in the database, the response of all these operations is returned to the user by socket.emit,
And I fixed some bug in project.

Socket IO and Dynamic Rooms

If anyone is experienced with Websockets / Socket IO hopefully you can point me in the right direction.
I made a Discord Clone and I'm trying to optimize it to scale better. Right now when a user sends a message I query the DB for all users part of that server, and emit a message to their specific socket. This is obviously not going to scale well as every message requires a expensive query and lookup in the client list
// Emit messages to only users part of specific server
// Will only return list of users part of server and active in last 10 minutes
sqlQuery = `SELECT userservers.user_id FROM userservers
JOIN users ON users.user_id = userservers.user_id AND users.user_last_active > (NOW() - INTERVAL 10 minute)
WHERE server_id = ${sql.escape(serverId)}`;
const users = await sql.query(sqlQuery);
action = { type: "message", payload: msg };
// Iterate over users, and find them in clients list
// Emit over socket only to that user
users.forEach((user) => {
clients.forEach((client) => {
if (client.userId === user.user_id) {
io.to(client.id).emit(user.user_id, action);
}
})
});
However using Rooms for each Sever would eliminate my need to query the DB. I understand I can do this when the socket server first starts
// Get server list from Mysql DB
servers.forEach((server) => {
socket.join(server.name);
}
However my issue becomes, when a user create a new server once the application is already running It will not update the list.
I am probably missing some concept on creating dynamic rooms.
EDIT : I am thinking the solution could be that every time a "server" is created, I send a message to the socket server so it can join that "room"
Right now when a user sends a message I query the DB for all users part of that server
I think you can submit broad cast message to all online users, so instead of forEach client => io.to(clientId) you can submit broad cast message to all connected users io.emit('some event', { for: 'everyone' });
also I'm wondering why you are creating many servers? you can divide your server into namespaces by using const namespace = io.of('/thisIsASeparateNamespace'); and also you can submit broadcast messages to all users inside this name space by namespace.emit('some event', { for: 'everyone in name space' });
So your chat structure can be like this
Server
Namespaces // for separate chat app / or like slack work spaces
Rooms // for group chatting
ClientID // for one to one

Socket.io - tell client if he creates or joins a room

I currently use the following code to allow users to create/join a specific room in socket.io:
socket.on('create', function (roomId) {
...
socket.join(roomId);
...
});
since the join function is used for both creating AND joining the same room, I would like tell the client if he was the one that created the room or just joined an existing one.
WHAT I TRIED TO DO
I tried to store the Id (and other informations not related to the problem), then check whenever that id already exists and emit a different message depending on the results. something like:
// "repo" is a variable declared globally
socket.on('create', function (roomId) {
...
socket.join(roomId);
if (repo.hasRoom(roomId)) {
app.io.sockets.in(roomId).emit('someone Joined');
} else {
app.io.sockets.in(roomId).emit('someone Created this room');
repo.saveRoom(roomId);
}
...
});
the above code doesn't work, as the client is unable to receive the message emitted (I guess because is on the "create" event). to be clear, I CAN determine on the server if a room is created, but the CLIENT doesn't know.
Is there an effective way to notify the client if he was responsible for creating or just joining a room?

Restrict number of users in a session in vline

Can I restrict the number of users in a session? Is there any option in vline.session? Please guide if this can be done by writing custom javascript.
EDIT:
Referring to https://vline.com/developer/docs/vline.js/vline.MediaSession#examples, a two party call controller is explained. I want to ask is there any way to restrict number of users in a session? There is no such option present in session's docs. Is it supported as a part of the API?
If this can be done using custom javascript, how?
As a part of my effort, I have tried to implement vline-django examples, but could not find a section in documentation that addresses this issue.
EDIT 2: The code that is working for me.
var vlineClient = (function(){
var client, session,
authToken = {{ user|vline_auth_token|safe }},
serviceId = {% vline_service_id %},
profile = {{ user|vline_user_profile|safe }};
// Create vLine client
window.vlineClient = client = vline.Client.create({"serviceId": serviceId, "ui": true});
// Add login event handler
client.on('login', onLogin);
// Do login
client.login(serviceId, profile, authToken);
function onLogin(event) {
session = event.target;
// Find and init call buttons
var callButtons = document.getElementsByClassName('callbutton');
for (var i=0; i < callButtons.length; ++i) {
initCallButton(callButtons[i]);
}
}
// add event handlers for call button
function initCallButton(button) {
var userId = button.getAttribute('data-userid');
// fetch person object associated with username
session.getPerson(userId).done(function(person) {
// update button state with presence
function onPresenceChange() {
button.setAttribute('data-presence', person.getPresenceState());
}
// set current presence
onPresenceChange();
// handle presence changes
person.on('change:presenceState', onPresenceChange);
// start a call when button is clicked
button.addEventListener('click', function() {
person.startMedia();
});
});
}
return client;
})();
How do I move ahead?
Reference: https://vline.com/developer/docs/vline.js/
if i understand correctly the OP is trying to make a multi-user chat room - this is also what i wanted to do with vline and because i wanted a/v chat as well the number of participants should obviously be capped - it appears that the term 'session' is causing the confusion here so i will refrain from using it
i worked around this by creating a fixed number of users in a db and handling authentication
myself before actually associating a visitor with one of the prepared users - so some javascript logs in each visitor as one of those existing 'anonymous' users and sets only a logged_in? flag in the db so that the next visitor will log in as the next vacant user slot and when all slots are occupied the visitor gets a "chat room full - try again later" response
probably not the most elegant solution - for example the visitor chosen usernames are stored client-side and must be re-assigned to one of the user-definable vline session vars so it can be passed along with each message and the logged_in? db flag needs to be reset when the user exits
note that this was almost a year ago so im a bit foggy on exactly what i did but my app (rails) in up on github if youre interested to fork it - also i should add that although this sort of thing wasnt strictly supported by the vline API at the time there were at least some hints that some analogous feature was being prepared for so there may be some API support for this now - i did notice since then that they have released a "chat room demo" app on github and i would expect that their implementation is more concise than mine so you may want to look at that first - my app tho does have a mostly complete UI with gravatars and collaboration is welcomed

Categories